mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-16 10:42:25 +01:00
v3.7.0
This commit is contained in:
parent
f24569a1b4
commit
31588bb4f5
@ -33,7 +33,7 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
project(Catch2
|
project(Catch2
|
||||||
VERSION 3.6.0 # CML version placeholder, don't delete
|
VERSION 3.7.0 # CML version placeholder, don't delete
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
# HOMEPAGE_URL is not supported until CMake version 3.12, which
|
# HOMEPAGE_URL is not supported until CMake version 3.12, which
|
||||||
# we do not target yet.
|
# we do not target yet.
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
# Release notes
|
# Release notes
|
||||||
**Contents**<br>
|
**Contents**<br>
|
||||||
|
[3.7.0](#370)<br>
|
||||||
[3.6.0](#360)<br>
|
[3.6.0](#360)<br>
|
||||||
[3.5.4](#354)<br>
|
[3.5.4](#354)<br>
|
||||||
[3.5.3](#353)<br>
|
[3.5.3](#353)<br>
|
||||||
@ -63,6 +64,26 @@
|
|||||||
[Even Older versions](#even-older-versions)<br>
|
[Even Older versions](#even-older-versions)<br>
|
||||||
|
|
||||||
|
|
||||||
|
## 3.7.0
|
||||||
|
|
||||||
|
### improvements
|
||||||
|
* Slightly improved compile times of benchmarks
|
||||||
|
* Made the resolution estimation in benchmarks slightly more precise
|
||||||
|
* Added new test case macro, `TEST_CASE_PERSISTENT_FIXTURE` (#2885, #1602)
|
||||||
|
* Unlike `TEST_CASE_METHOD`, the same underlying instance is used for all partial runs of that test case
|
||||||
|
* **MASSIVELY** improved performance of the JUnit reporter when handling successful assertions (#2897)
|
||||||
|
* For 1 test case and 10M assertions, the new reporter runs 3x faster and uses up only 8 MB of memory, while the old one needs 7 GB of memory.
|
||||||
|
* Reworked how output redirects works.
|
||||||
|
* Combining a reporter writing to stdout with capturing reporter no longer leads to the capturing reporter seeing all of the other reporter's output.
|
||||||
|
* The file based redirect no longer opens up a new temporary file for each partial test case run, so it will not run out of temporary files when running many tests in single process.
|
||||||
|
|
||||||
|
### Miscellaneous
|
||||||
|
* Better documentation for matchers on thrown exceptions (`REQUIRE_THROWS_MATCHES`)
|
||||||
|
* Improved `catch_discover_tests`'s handling of environment paths (#2878)
|
||||||
|
* It won't reorder paths in `DL_PATHS` or `DYLD_FRAMEWORK_PATHS` args
|
||||||
|
* It won't overwrite the environment paths for test discovery
|
||||||
|
|
||||||
|
|
||||||
## 3.6.0
|
## 3.6.0
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
@ -88,7 +88,7 @@ class.
|
|||||||
|
|
||||||
### 3. `TEST_CASE_PERSISTENT_FIXTURE`
|
### 3. `TEST_CASE_PERSISTENT_FIXTURE`
|
||||||
|
|
||||||
> [Introduced](https://github.com/catchorg/Catch2/pull/2885) in Catch2 X.Y.Z
|
> [Introduced](https://github.com/catchorg/Catch2/pull/2885) in Catch2 3.7.0
|
||||||
|
|
||||||
`TEST_CASE_PERSISTENT_FIXTURE` behaves in the same way as
|
`TEST_CASE_PERSISTENT_FIXTURE` behaves in the same way as
|
||||||
[TEST_CASE_METHOD](#1-test_case_method) except that there will only be
|
[TEST_CASE_METHOD](#1-test_case_method) except that there will only be
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
// Catch v3.6.0
|
// Catch v3.7.0
|
||||||
// Generated: 2024-05-05 20:53:27.562886
|
// Generated: 2024-08-14 12:04:53.604337
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
// This file is an amalgamation of multiple different files.
|
// This file is an amalgamation of multiple different files.
|
||||||
// You probably shouldn't edit it directly.
|
// You probably shouldn't edit it directly.
|
||||||
@ -128,7 +128,13 @@ namespace Catch {
|
|||||||
namespace Catch {
|
namespace Catch {
|
||||||
namespace Benchmark {
|
namespace Benchmark {
|
||||||
namespace Detail {
|
namespace Detail {
|
||||||
|
struct do_nothing {
|
||||||
|
void operator()() const {}
|
||||||
|
};
|
||||||
|
|
||||||
BenchmarkFunction::callable::~callable() = default;
|
BenchmarkFunction::callable::~callable() = default;
|
||||||
|
BenchmarkFunction::BenchmarkFunction():
|
||||||
|
f( new model<do_nothing>{ {} } ){}
|
||||||
} // namespace Detail
|
} // namespace Detail
|
||||||
} // namespace Benchmark
|
} // namespace Benchmark
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
@ -1040,6 +1046,7 @@ namespace Catch {
|
|||||||
m_messages.back().message += " := ";
|
m_messages.back().message += " := ";
|
||||||
start = pos;
|
start = pos;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
default:; // noop
|
default:; // noop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2273,7 +2280,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Version const& libraryVersion() {
|
Version const& libraryVersion() {
|
||||||
static Version version( 3, 6, 0, "", 0 );
|
static Version version( 3, 7, 0, "", 0 );
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4808,138 +4815,328 @@ namespace Catch {
|
|||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <iosfwd>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
#if defined( CATCH_CONFIG_NEW_CAPTURE )
|
||||||
#if defined(_MSC_VER)
|
# if defined( _MSC_VER )
|
||||||
#include <io.h> //_dup and _dup2
|
# include <io.h> //_dup and _dup2
|
||||||
#define dup _dup
|
# define dup _dup
|
||||||
#define dup2 _dup2
|
# define dup2 _dup2
|
||||||
#define fileno _fileno
|
# define fileno _fileno
|
||||||
#else
|
# else
|
||||||
#include <unistd.h> // dup and dup2
|
# include <unistd.h> // dup and dup2
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )
|
namespace {
|
||||||
: m_originalStream( originalStream ),
|
//! A no-op implementation, used if no reporter wants output
|
||||||
|
//! redirection.
|
||||||
|
class NoopRedirect : public OutputRedirect {
|
||||||
|
void activateImpl() override {}
|
||||||
|
void deactivateImpl() override {}
|
||||||
|
std::string getStdout() override { return {}; }
|
||||||
|
std::string getStderr() override { return {}; }
|
||||||
|
void clearBuffers() override {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirects specific stream's rdbuf with another's.
|
||||||
|
*
|
||||||
|
* Redirection can be stopped and started on-demand, assumes
|
||||||
|
* that the underlying stream's rdbuf aren't changed by other
|
||||||
|
* users.
|
||||||
|
*/
|
||||||
|
class RedirectedStreamNew {
|
||||||
|
std::ostream& m_originalStream;
|
||||||
|
std::ostream& m_redirectionStream;
|
||||||
|
std::streambuf* m_prevBuf;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RedirectedStreamNew( std::ostream& originalStream,
|
||||||
|
std::ostream& redirectionStream ):
|
||||||
|
m_originalStream( originalStream ),
|
||||||
m_redirectionStream( redirectionStream ),
|
m_redirectionStream( redirectionStream ),
|
||||||
m_prevBuf( m_originalStream.rdbuf() )
|
m_prevBuf( m_originalStream.rdbuf() ) {}
|
||||||
{
|
|
||||||
|
void startRedirect() {
|
||||||
m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
|
m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
|
||||||
}
|
}
|
||||||
|
void stopRedirect() { m_originalStream.rdbuf( m_prevBuf ); }
|
||||||
|
};
|
||||||
|
|
||||||
RedirectedStream::~RedirectedStream() {
|
/**
|
||||||
m_originalStream.rdbuf( m_prevBuf );
|
* Redirects the `std::cout`, `std::cerr`, `std::clog` streams,
|
||||||
|
* but does not touch the actual `stdout`/`stderr` file descriptors.
|
||||||
|
*/
|
||||||
|
class StreamRedirect : public OutputRedirect {
|
||||||
|
ReusableStringStream m_redirectedOut, m_redirectedErr;
|
||||||
|
RedirectedStreamNew m_cout, m_cerr, m_clog;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StreamRedirect():
|
||||||
|
m_cout( Catch::cout(), m_redirectedOut.get() ),
|
||||||
|
m_cerr( Catch::cerr(), m_redirectedErr.get() ),
|
||||||
|
m_clog( Catch::clog(), m_redirectedErr.get() ) {}
|
||||||
|
|
||||||
|
void activateImpl() override {
|
||||||
|
m_cout.startRedirect();
|
||||||
|
m_cerr.startRedirect();
|
||||||
|
m_clog.startRedirect();
|
||||||
}
|
}
|
||||||
|
void deactivateImpl() override {
|
||||||
RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {}
|
m_cout.stopRedirect();
|
||||||
auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); }
|
m_cerr.stopRedirect();
|
||||||
|
m_clog.stopRedirect();
|
||||||
RedirectedStdErr::RedirectedStdErr()
|
|
||||||
: m_cerr( Catch::cerr(), m_rss.get() ),
|
|
||||||
m_clog( Catch::clog(), m_rss.get() )
|
|
||||||
{}
|
|
||||||
auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }
|
|
||||||
|
|
||||||
RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr)
|
|
||||||
: m_redirectedCout(redirectedCout),
|
|
||||||
m_redirectedCerr(redirectedCerr)
|
|
||||||
{}
|
|
||||||
|
|
||||||
RedirectedStreams::~RedirectedStreams() {
|
|
||||||
m_redirectedCout += m_redirectedStdOut.str();
|
|
||||||
m_redirectedCerr += m_redirectedStdErr.str();
|
|
||||||
}
|
}
|
||||||
|
std::string getStdout() override { return m_redirectedOut.str(); }
|
||||||
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
std::string getStderr() override { return m_redirectedErr.str(); }
|
||||||
|
void clearBuffers() override {
|
||||||
#if defined(_MSC_VER)
|
m_redirectedOut.str( "" );
|
||||||
TempFile::TempFile() {
|
m_redirectedErr.str( "" );
|
||||||
if (tmpnam_s(m_buffer)) {
|
|
||||||
CATCH_RUNTIME_ERROR("Could not get a temp filename");
|
|
||||||
}
|
}
|
||||||
if (fopen_s(&m_file, m_buffer, "w+")) {
|
};
|
||||||
|
|
||||||
|
#if defined( CATCH_CONFIG_NEW_CAPTURE )
|
||||||
|
|
||||||
|
// Windows's implementation of std::tmpfile is terrible (it tries
|
||||||
|
// to create a file inside system folder, thus requiring elevated
|
||||||
|
// privileges for the binary), so we have to use tmpnam(_s) and
|
||||||
|
// create the file ourselves there.
|
||||||
|
class TempFile {
|
||||||
|
public:
|
||||||
|
TempFile( TempFile const& ) = delete;
|
||||||
|
TempFile& operator=( TempFile const& ) = delete;
|
||||||
|
TempFile( TempFile&& ) = delete;
|
||||||
|
TempFile& operator=( TempFile&& ) = delete;
|
||||||
|
|
||||||
|
# if defined( _MSC_VER )
|
||||||
|
TempFile() {
|
||||||
|
if ( tmpnam_s( m_buffer ) ) {
|
||||||
|
CATCH_RUNTIME_ERROR( "Could not get a temp filename" );
|
||||||
|
}
|
||||||
|
if ( fopen_s( &m_file, m_buffer, "wb+" ) ) {
|
||||||
char buffer[100];
|
char buffer[100];
|
||||||
if (strerror_s(buffer, errno)) {
|
if ( strerror_s( buffer, errno ) ) {
|
||||||
CATCH_RUNTIME_ERROR("Could not translate errno to a string");
|
CATCH_RUNTIME_ERROR(
|
||||||
|
"Could not translate errno to a string" );
|
||||||
}
|
}
|
||||||
CATCH_RUNTIME_ERROR("Could not open the temp file: '" << m_buffer << "' because: " << buffer);
|
CATCH_RUNTIME_ERROR( "Could not open the temp file: '"
|
||||||
|
<< m_buffer
|
||||||
|
<< "' because: " << buffer );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
# else
|
||||||
TempFile::TempFile() {
|
TempFile() {
|
||||||
m_file = std::tmpfile();
|
m_file = std::tmpfile();
|
||||||
if (!m_file) {
|
if ( !m_file ) {
|
||||||
CATCH_RUNTIME_ERROR("Could not create a temp file.");
|
CATCH_RUNTIME_ERROR( "Could not create a temp file." );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
#endif
|
~TempFile() {
|
||||||
|
|
||||||
TempFile::~TempFile() {
|
|
||||||
// TBD: What to do about errors here?
|
// TBD: What to do about errors here?
|
||||||
std::fclose(m_file);
|
std::fclose( m_file );
|
||||||
// We manually create the file on Windows only, on Linux
|
// We manually create the file on Windows only, on Linux
|
||||||
// it will be autodeleted
|
// it will be autodeleted
|
||||||
#if defined(_MSC_VER)
|
# if defined( _MSC_VER )
|
||||||
std::remove(m_buffer);
|
std::remove( m_buffer );
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::FILE* getFile() { return m_file; }
|
||||||
FILE* TempFile::getFile() {
|
std::string getContents() {
|
||||||
return m_file;
|
ReusableStringStream sstr;
|
||||||
}
|
constexpr long buffer_size = 100;
|
||||||
|
char buffer[buffer_size + 1] = {};
|
||||||
std::string TempFile::getContents() {
|
long current_pos = ftell( m_file );
|
||||||
std::stringstream sstr;
|
CATCH_ENFORCE( current_pos >= 0,
|
||||||
char buffer[100] = {};
|
"ftell failed, errno: " << errno );
|
||||||
std::rewind(m_file);
|
std::rewind( m_file );
|
||||||
while (std::fgets(buffer, sizeof(buffer), m_file)) {
|
while ( current_pos > 0 ) {
|
||||||
|
auto read_characters =
|
||||||
|
std::fread( buffer,
|
||||||
|
1,
|
||||||
|
std::min( buffer_size, current_pos ),
|
||||||
|
m_file );
|
||||||
|
buffer[read_characters] = '\0';
|
||||||
sstr << buffer;
|
sstr << buffer;
|
||||||
|
current_pos -= static_cast<long>( read_characters );
|
||||||
}
|
}
|
||||||
return sstr.str();
|
return sstr.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) :
|
void clear() { std::rewind( m_file ); }
|
||||||
m_originalStdout(dup(1)),
|
|
||||||
m_originalStderr(dup(2)),
|
|
||||||
m_stdoutDest(stdout_dest),
|
|
||||||
m_stderrDest(stderr_dest) {
|
|
||||||
dup2(fileno(m_stdoutFile.getFile()), 1);
|
|
||||||
dup2(fileno(m_stderrFile.getFile()), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputRedirect::~OutputRedirect() {
|
private:
|
||||||
|
std::FILE* m_file = nullptr;
|
||||||
|
char m_buffer[L_tmpnam] = { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirects the actual `stdout`/`stderr` file descriptors.
|
||||||
|
*
|
||||||
|
* Works by replacing the file descriptors numbered 1 and 2
|
||||||
|
* with an open temporary file.
|
||||||
|
*/
|
||||||
|
class FileRedirect : public OutputRedirect {
|
||||||
|
TempFile m_outFile, m_errFile;
|
||||||
|
int m_originalOut = -1;
|
||||||
|
int m_originalErr = -1;
|
||||||
|
|
||||||
|
// Flushes cout/cerr/clog streams and stdout/stderr FDs
|
||||||
|
void flushEverything() {
|
||||||
Catch::cout() << std::flush;
|
Catch::cout() << std::flush;
|
||||||
fflush(stdout);
|
fflush( stdout );
|
||||||
// Since we support overriding these streams, we flush cerr
|
// Since we support overriding these streams, we flush cerr
|
||||||
// even though std::cerr is unbuffered
|
// even though std::cerr is unbuffered
|
||||||
Catch::cerr() << std::flush;
|
Catch::cerr() << std::flush;
|
||||||
Catch::clog() << std::flush;
|
Catch::clog() << std::flush;
|
||||||
fflush(stderr);
|
fflush( stderr );
|
||||||
|
|
||||||
dup2(m_originalStdout, 1);
|
|
||||||
dup2(m_originalStderr, 2);
|
|
||||||
|
|
||||||
m_stdoutDest += m_stdoutFile.getContents();
|
|
||||||
m_stderrDest += m_stderrFile.getContents();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
FileRedirect():
|
||||||
|
m_originalOut( dup( fileno( stdout ) ) ),
|
||||||
|
m_originalErr( dup( fileno( stderr ) ) ) {
|
||||||
|
CATCH_ENFORCE( m_originalOut >= 0, "Could not dup stdout" );
|
||||||
|
CATCH_ENFORCE( m_originalErr >= 0, "Could not dup stderr" );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getStdout() override { return m_outFile.getContents(); }
|
||||||
|
std::string getStderr() override { return m_errFile.getContents(); }
|
||||||
|
void clearBuffers() override {
|
||||||
|
m_outFile.clear();
|
||||||
|
m_errFile.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void activateImpl() override {
|
||||||
|
// We flush before starting redirect, to ensure that we do
|
||||||
|
// not capture the end of message sent before activation.
|
||||||
|
flushEverything();
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
ret = dup2( fileno( m_outFile.getFile() ), fileno( stdout ) );
|
||||||
|
CATCH_ENFORCE( ret >= 0,
|
||||||
|
"dup2 to stdout has failed, errno: " << errno );
|
||||||
|
ret = dup2( fileno( m_errFile.getFile() ), fileno( stderr ) );
|
||||||
|
CATCH_ENFORCE( ret >= 0,
|
||||||
|
"dup2 to stderr has failed, errno: " << errno );
|
||||||
|
}
|
||||||
|
void deactivateImpl() override {
|
||||||
|
// We flush before ending redirect, to ensure that we
|
||||||
|
// capture all messages sent while the redirect was active.
|
||||||
|
flushEverything();
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
ret = dup2( m_originalOut, fileno( stdout ) );
|
||||||
|
CATCH_ENFORCE(
|
||||||
|
ret >= 0,
|
||||||
|
"dup2 of original stdout has failed, errno: " << errno );
|
||||||
|
ret = dup2( m_originalErr, fileno( stderr ) );
|
||||||
|
CATCH_ENFORCE(
|
||||||
|
ret >= 0,
|
||||||
|
"dup2 of original stderr has failed, errno: " << errno );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif // CATCH_CONFIG_NEW_CAPTURE
|
#endif // CATCH_CONFIG_NEW_CAPTURE
|
||||||
|
|
||||||
|
} // end namespace
|
||||||
|
|
||||||
|
bool isRedirectAvailable( OutputRedirect::Kind kind ) {
|
||||||
|
switch ( kind ) {
|
||||||
|
// These two are always available
|
||||||
|
case OutputRedirect::None:
|
||||||
|
case OutputRedirect::Streams:
|
||||||
|
return true;
|
||||||
|
#if defined( CATCH_CONFIG_NEW_CAPTURE )
|
||||||
|
case OutputRedirect::FileDescriptors:
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Detail::unique_ptr<OutputRedirect> makeOutputRedirect( bool actual ) {
|
||||||
|
if ( actual ) {
|
||||||
|
// TODO: Clean this up later
|
||||||
|
#if defined( CATCH_CONFIG_NEW_CAPTURE )
|
||||||
|
return Detail::make_unique<FileRedirect>();
|
||||||
|
#else
|
||||||
|
return Detail::make_unique<StreamRedirect>();
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
return Detail::make_unique<NoopRedirect>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RedirectGuard scopedActivate( OutputRedirect& redirectImpl ) {
|
||||||
|
return RedirectGuard( true, redirectImpl );
|
||||||
|
}
|
||||||
|
|
||||||
|
RedirectGuard scopedDeactivate( OutputRedirect& redirectImpl ) {
|
||||||
|
return RedirectGuard( false, redirectImpl );
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputRedirect::~OutputRedirect() = default;
|
||||||
|
|
||||||
|
RedirectGuard::RedirectGuard( bool activate, OutputRedirect& redirectImpl ):
|
||||||
|
m_redirect( &redirectImpl ),
|
||||||
|
m_activate( activate ),
|
||||||
|
m_previouslyActive( redirectImpl.isActive() ) {
|
||||||
|
|
||||||
|
// Skip cases where there is no actual state change.
|
||||||
|
if ( m_activate == m_previouslyActive ) { return; }
|
||||||
|
|
||||||
|
if ( m_activate ) {
|
||||||
|
m_redirect->activate();
|
||||||
|
} else {
|
||||||
|
m_redirect->deactivate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RedirectGuard::~RedirectGuard() noexcept( false ) {
|
||||||
|
if ( m_moved ) { return; }
|
||||||
|
// Skip cases where there is no actual state change.
|
||||||
|
if ( m_activate == m_previouslyActive ) { return; }
|
||||||
|
|
||||||
|
if ( m_activate ) {
|
||||||
|
m_redirect->deactivate();
|
||||||
|
} else {
|
||||||
|
m_redirect->activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RedirectGuard::RedirectGuard( RedirectGuard&& rhs ) noexcept:
|
||||||
|
m_redirect( rhs.m_redirect ),
|
||||||
|
m_activate( rhs.m_activate ),
|
||||||
|
m_previouslyActive( rhs.m_previouslyActive ),
|
||||||
|
m_moved( false ) {
|
||||||
|
rhs.m_moved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RedirectGuard& RedirectGuard::operator=( RedirectGuard&& rhs ) noexcept {
|
||||||
|
m_redirect = rhs.m_redirect;
|
||||||
|
m_activate = rhs.m_activate;
|
||||||
|
m_previouslyActive = rhs.m_previouslyActive;
|
||||||
|
m_moved = false;
|
||||||
|
rhs.m_moved = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
|
||||||
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
#if defined( CATCH_CONFIG_NEW_CAPTURE )
|
||||||
#if defined(_MSC_VER)
|
# if defined( _MSC_VER )
|
||||||
#undef dup
|
# undef dup
|
||||||
#undef dup2
|
# undef dup2
|
||||||
#undef fileno
|
# undef fileno
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -5573,6 +5770,7 @@ namespace Catch {
|
|||||||
m_config(_config),
|
m_config(_config),
|
||||||
m_reporter(CATCH_MOVE(reporter)),
|
m_reporter(CATCH_MOVE(reporter)),
|
||||||
m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },
|
m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },
|
||||||
|
m_outputRedirect( makeOutputRedirect( m_reporter->getPreferences().shouldRedirectStdOut ) ),
|
||||||
m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )
|
m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )
|
||||||
{
|
{
|
||||||
getCurrentMutableContext().setResultCapture( this );
|
getCurrentMutableContext().setResultCapture( this );
|
||||||
@ -5588,6 +5786,7 @@ namespace Catch {
|
|||||||
|
|
||||||
auto const& testInfo = testCase.getTestCaseInfo();
|
auto const& testInfo = testCase.getTestCaseInfo();
|
||||||
m_reporter->testCaseStarting(testInfo);
|
m_reporter->testCaseStarting(testInfo);
|
||||||
|
testCase.prepareTestCase();
|
||||||
m_activeTestCase = &testCase;
|
m_activeTestCase = &testCase;
|
||||||
|
|
||||||
|
|
||||||
@ -5638,15 +5837,17 @@ namespace Catch {
|
|||||||
m_reporter->testCasePartialStarting(testInfo, testRuns);
|
m_reporter->testCasePartialStarting(testInfo, testRuns);
|
||||||
|
|
||||||
const auto beforeRunTotals = m_totals;
|
const auto beforeRunTotals = m_totals;
|
||||||
std::string oneRunCout, oneRunCerr;
|
runCurrentTest();
|
||||||
runCurrentTest(oneRunCout, oneRunCerr);
|
std::string oneRunCout = m_outputRedirect->getStdout();
|
||||||
|
std::string oneRunCerr = m_outputRedirect->getStderr();
|
||||||
|
m_outputRedirect->clearBuffers();
|
||||||
redirectedCout += oneRunCout;
|
redirectedCout += oneRunCout;
|
||||||
redirectedCerr += oneRunCerr;
|
redirectedCerr += oneRunCerr;
|
||||||
|
|
||||||
const auto singleRunTotals = m_totals.delta(beforeRunTotals);
|
const auto singleRunTotals = m_totals.delta(beforeRunTotals);
|
||||||
auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting());
|
auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting());
|
||||||
|
|
||||||
m_reporter->testCasePartialEnded(statsForOneRun, testRuns);
|
m_reporter->testCasePartialEnded(statsForOneRun, testRuns);
|
||||||
|
|
||||||
++testRuns;
|
++testRuns;
|
||||||
} while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
|
} while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
|
||||||
|
|
||||||
@ -5657,6 +5858,7 @@ namespace Catch {
|
|||||||
deltaTotals.testCases.failed++;
|
deltaTotals.testCases.failed++;
|
||||||
}
|
}
|
||||||
m_totals.testCases += deltaTotals.testCases;
|
m_totals.testCases += deltaTotals.testCases;
|
||||||
|
testCase.tearDownTestCase();
|
||||||
m_reporter->testCaseEnded(TestCaseStats(testInfo,
|
m_reporter->testCaseEnded(TestCaseStats(testInfo,
|
||||||
deltaTotals,
|
deltaTotals,
|
||||||
CATCH_MOVE(redirectedCout),
|
CATCH_MOVE(redirectedCout),
|
||||||
@ -5690,7 +5892,10 @@ namespace Catch {
|
|||||||
m_lastAssertionPassed = true;
|
m_lastAssertionPassed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals));
|
{
|
||||||
|
auto _ = scopedDeactivate( *m_outputRedirect );
|
||||||
|
m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) );
|
||||||
|
}
|
||||||
|
|
||||||
if ( result.getResultType() != ResultWas::Warning ) {
|
if ( result.getResultType() != ResultWas::Warning ) {
|
||||||
m_messageScopes.clear();
|
m_messageScopes.clear();
|
||||||
@ -5707,6 +5912,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RunContext::notifyAssertionStarted( AssertionInfo const& info ) {
|
void RunContext::notifyAssertionStarted( AssertionInfo const& info ) {
|
||||||
|
auto _ = scopedDeactivate( *m_outputRedirect );
|
||||||
m_reporter->assertionStarting( info );
|
m_reporter->assertionStarting( info );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5725,7 +5931,10 @@ namespace Catch {
|
|||||||
SectionInfo sectionInfo( sectionLineInfo, static_cast<std::string>(sectionName) );
|
SectionInfo sectionInfo( sectionLineInfo, static_cast<std::string>(sectionName) );
|
||||||
m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
|
m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
|
||||||
|
|
||||||
m_reporter->sectionStarting(sectionInfo);
|
{
|
||||||
|
auto _ = scopedDeactivate( *m_outputRedirect );
|
||||||
|
m_reporter->sectionStarting( sectionInfo );
|
||||||
|
}
|
||||||
|
|
||||||
assertions = m_totals.assertions;
|
assertions = m_totals.assertions;
|
||||||
|
|
||||||
@ -5785,7 +5994,15 @@ namespace Catch {
|
|||||||
m_activeSections.pop_back();
|
m_activeSections.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_reporter->sectionEnded(SectionStats(CATCH_MOVE(endInfo.sectionInfo), assertions, endInfo.durationInSeconds, missingAssertions));
|
{
|
||||||
|
auto _ = scopedDeactivate( *m_outputRedirect );
|
||||||
|
m_reporter->sectionEnded(
|
||||||
|
SectionStats( CATCH_MOVE( endInfo.sectionInfo ),
|
||||||
|
assertions,
|
||||||
|
endInfo.durationInSeconds,
|
||||||
|
missingAssertions ) );
|
||||||
|
}
|
||||||
|
|
||||||
m_messages.clear();
|
m_messages.clear();
|
||||||
m_messageScopes.clear();
|
m_messageScopes.clear();
|
||||||
}
|
}
|
||||||
@ -5802,15 +6019,19 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RunContext::benchmarkPreparing( StringRef name ) {
|
void RunContext::benchmarkPreparing( StringRef name ) {
|
||||||
m_reporter->benchmarkPreparing(name);
|
auto _ = scopedDeactivate( *m_outputRedirect );
|
||||||
|
m_reporter->benchmarkPreparing( name );
|
||||||
}
|
}
|
||||||
void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
|
void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
|
||||||
|
auto _ = scopedDeactivate( *m_outputRedirect );
|
||||||
m_reporter->benchmarkStarting( info );
|
m_reporter->benchmarkStarting( info );
|
||||||
}
|
}
|
||||||
void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {
|
void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {
|
||||||
|
auto _ = scopedDeactivate( *m_outputRedirect );
|
||||||
m_reporter->benchmarkEnded( stats );
|
m_reporter->benchmarkEnded( stats );
|
||||||
}
|
}
|
||||||
void RunContext::benchmarkFailed( StringRef error ) {
|
void RunContext::benchmarkFailed( StringRef error ) {
|
||||||
|
auto _ = scopedDeactivate( *m_outputRedirect );
|
||||||
m_reporter->benchmarkFailed( error );
|
m_reporter->benchmarkFailed( error );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5841,8 +6062,13 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RunContext::handleFatalErrorCondition( StringRef message ) {
|
void RunContext::handleFatalErrorCondition( StringRef message ) {
|
||||||
|
// TODO: scoped deactivate here? Just give up and do best effort?
|
||||||
|
// the deactivation can break things further, OTOH so can the
|
||||||
|
// capture
|
||||||
|
auto _ = scopedDeactivate( *m_outputRedirect );
|
||||||
|
|
||||||
// First notify reporter that bad things happened
|
// First notify reporter that bad things happened
|
||||||
m_reporter->fatalErrorEncountered(message);
|
m_reporter->fatalErrorEncountered( message );
|
||||||
|
|
||||||
// Don't rebuild the result -- the stringification itself can cause more fatal errors
|
// Don't rebuild the result -- the stringification itself can cause more fatal errors
|
||||||
// Instead, fake a result data.
|
// Instead, fake a result data.
|
||||||
@ -5869,7 +6095,7 @@ namespace Catch {
|
|||||||
Counts assertions;
|
Counts assertions;
|
||||||
assertions.failed = 1;
|
assertions.failed = 1;
|
||||||
SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, 0, false);
|
SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, 0, false);
|
||||||
m_reporter->sectionEnded(testCaseSectionStats);
|
m_reporter->sectionEnded( testCaseSectionStats );
|
||||||
|
|
||||||
auto const& testInfo = m_activeTestCase->getTestCaseInfo();
|
auto const& testInfo = m_activeTestCase->getTestCaseInfo();
|
||||||
|
|
||||||
@ -5900,7 +6126,7 @@ namespace Catch {
|
|||||||
return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter());
|
return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {
|
void RunContext::runCurrentTest() {
|
||||||
auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
|
auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
|
||||||
SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
|
SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
|
||||||
m_reporter->sectionStarting(testCaseSection);
|
m_reporter->sectionStarting(testCaseSection);
|
||||||
@ -5911,18 +6137,8 @@ namespace Catch {
|
|||||||
|
|
||||||
Timer timer;
|
Timer timer;
|
||||||
CATCH_TRY {
|
CATCH_TRY {
|
||||||
if (m_reporter->getPreferences().shouldRedirectStdOut) {
|
{
|
||||||
#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
|
auto _ = scopedActivate( *m_outputRedirect );
|
||||||
RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr);
|
|
||||||
|
|
||||||
timer.start();
|
|
||||||
invokeActiveTestCase();
|
|
||||||
#else
|
|
||||||
OutputRedirect r(redirectedCout, redirectedCerr);
|
|
||||||
timer.start();
|
|
||||||
invokeActiveTestCase();
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
timer.start();
|
timer.start();
|
||||||
invokeActiveTestCase();
|
invokeActiveTestCase();
|
||||||
}
|
}
|
||||||
@ -5967,11 +6183,12 @@ namespace Catch {
|
|||||||
void RunContext::handleUnfinishedSections() {
|
void RunContext::handleUnfinishedSections() {
|
||||||
// If sections ended prematurely due to an exception we stored their
|
// If sections ended prematurely due to an exception we stored their
|
||||||
// infos here so we can tear them down outside the unwind process.
|
// infos here so we can tear them down outside the unwind process.
|
||||||
for (auto it = m_unfinishedSections.rbegin(),
|
for ( auto it = m_unfinishedSections.rbegin(),
|
||||||
itEnd = m_unfinishedSections.rend();
|
itEnd = m_unfinishedSections.rend();
|
||||||
it != itEnd;
|
it != itEnd;
|
||||||
++it)
|
++it ) {
|
||||||
sectionEnded(CATCH_MOVE(*it));
|
sectionEnded( CATCH_MOVE( *it ) );
|
||||||
|
}
|
||||||
m_unfinishedSections.clear();
|
m_unfinishedSections.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6898,6 +7115,8 @@ namespace Catch {
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
void ITestInvoker::prepareTestCase() {}
|
||||||
|
void ITestInvoker::tearDownTestCase() {}
|
||||||
ITestInvoker::~ITestInvoker() = default;
|
ITestInvoker::~ITestInvoker() = default;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -10333,7 +10552,7 @@ namespace Catch {
|
|||||||
xml( m_stream )
|
xml( m_stream )
|
||||||
{
|
{
|
||||||
m_preferences.shouldRedirectStdOut = true;
|
m_preferences.shouldRedirectStdOut = true;
|
||||||
m_preferences.shouldReportAllAssertions = true;
|
m_preferences.shouldReportAllAssertions = false;
|
||||||
m_shouldStoreSuccesfulAssertions = false;
|
m_shouldStoreSuccesfulAssertions = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10443,7 +10662,7 @@ namespace Catch {
|
|||||||
if( !rootName.empty() )
|
if( !rootName.empty() )
|
||||||
name = rootName + '/' + name;
|
name = rootName + '/' + name;
|
||||||
|
|
||||||
if( sectionNode.hasAnyAssertions()
|
if ( sectionNode.stats.assertions.total() > 0
|
||||||
|| !sectionNode.stdOut.empty()
|
|| !sectionNode.stdOut.empty()
|
||||||
|| !sectionNode.stdErr.empty() ) {
|
|| !sectionNode.stdErr.empty() ) {
|
||||||
XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
|
XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
// Catch v3.6.0
|
// Catch v3.7.0
|
||||||
// Generated: 2024-05-05 20:53:27.071502
|
// Generated: 2024-08-14 12:04:53.220567
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
// This file is an amalgamation of multiple different files.
|
// This file is an amalgamation of multiple different files.
|
||||||
// You probably shouldn't edit it directly.
|
// You probably shouldn't edit it directly.
|
||||||
@ -1584,22 +1584,17 @@ namespace Catch {
|
|||||||
private:
|
private:
|
||||||
struct callable {
|
struct callable {
|
||||||
virtual void call(Chronometer meter) const = 0;
|
virtual void call(Chronometer meter) const = 0;
|
||||||
virtual Catch::Detail::unique_ptr<callable> clone() const = 0;
|
|
||||||
virtual ~callable(); // = default;
|
virtual ~callable(); // = default;
|
||||||
|
|
||||||
callable() = default;
|
callable() = default;
|
||||||
callable(callable const&) = default;
|
callable(callable&&) = default;
|
||||||
callable& operator=(callable const&) = default;
|
callable& operator=(callable&&) = default;
|
||||||
};
|
};
|
||||||
template <typename Fun>
|
template <typename Fun>
|
||||||
struct model : public callable {
|
struct model : public callable {
|
||||||
model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {}
|
model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {}
|
||||||
model(Fun const& fun_) : fun(fun_) {}
|
model(Fun const& fun_) : fun(fun_) {}
|
||||||
|
|
||||||
Catch::Detail::unique_ptr<callable> clone() const override {
|
|
||||||
return Catch::Detail::make_unique<model<Fun>>( *this );
|
|
||||||
}
|
|
||||||
|
|
||||||
void call(Chronometer meter) const override {
|
void call(Chronometer meter) const override {
|
||||||
call(meter, is_callable<Fun(Chronometer)>());
|
call(meter, is_callable<Fun(Chronometer)>());
|
||||||
}
|
}
|
||||||
@ -1613,14 +1608,8 @@ namespace Catch {
|
|||||||
Fun fun;
|
Fun fun;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct do_nothing { void operator()() const {} };
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
BenchmarkFunction(model<T>* c) : f(c) {}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BenchmarkFunction()
|
BenchmarkFunction();
|
||||||
: f(new model<do_nothing>{ {} }) {}
|
|
||||||
|
|
||||||
template <typename Fun,
|
template <typename Fun,
|
||||||
std::enable_if_t<!is_related<Fun, BenchmarkFunction>::value, int> = 0>
|
std::enable_if_t<!is_related<Fun, BenchmarkFunction>::value, int> = 0>
|
||||||
@ -1630,20 +1619,12 @@ namespace Catch {
|
|||||||
BenchmarkFunction( BenchmarkFunction&& that ) noexcept:
|
BenchmarkFunction( BenchmarkFunction&& that ) noexcept:
|
||||||
f( CATCH_MOVE( that.f ) ) {}
|
f( CATCH_MOVE( that.f ) ) {}
|
||||||
|
|
||||||
BenchmarkFunction(BenchmarkFunction const& that)
|
|
||||||
: f(that.f->clone()) {}
|
|
||||||
|
|
||||||
BenchmarkFunction&
|
BenchmarkFunction&
|
||||||
operator=( BenchmarkFunction&& that ) noexcept {
|
operator=( BenchmarkFunction&& that ) noexcept {
|
||||||
f = CATCH_MOVE( that.f );
|
f = CATCH_MOVE( that.f );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
BenchmarkFunction& operator=(BenchmarkFunction const& that) {
|
|
||||||
f = that.f->clone();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator()(Chronometer meter) const { f->call(meter); }
|
void operator()(Chronometer meter) const { f->call(meter); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -1780,7 +1761,7 @@ namespace Catch {
|
|||||||
template <typename Clock, typename Fun, typename... Args>
|
template <typename Clock, typename Fun, typename... Args>
|
||||||
TimingOf<Fun, Args...> measure(Fun&& fun, Args&&... args) {
|
TimingOf<Fun, Args...> measure(Fun&& fun, Args&&... args) {
|
||||||
auto start = Clock::now();
|
auto start = Clock::now();
|
||||||
auto&& r = Detail::complete_invoke(fun, CATCH_FORWARD(args)...);
|
auto&& r = Detail::complete_invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...);
|
||||||
auto end = Clock::now();
|
auto end = Clock::now();
|
||||||
auto delta = end - start;
|
auto delta = end - start;
|
||||||
return { delta, CATCH_FORWARD(r), 1 };
|
return { delta, CATCH_FORWARD(r), 1 };
|
||||||
@ -1946,15 +1927,17 @@ namespace Catch {
|
|||||||
namespace Detail {
|
namespace Detail {
|
||||||
template <typename Clock>
|
template <typename Clock>
|
||||||
std::vector<double> resolution(int k) {
|
std::vector<double> resolution(int k) {
|
||||||
std::vector<TimePoint<Clock>> times;
|
const size_t points = static_cast<size_t>( k + 1 );
|
||||||
times.reserve(static_cast<size_t>(k + 1));
|
// To avoid overhead from the branch inside vector::push_back,
|
||||||
for ( int i = 0; i < k + 1; ++i ) {
|
// we allocate them all and then overwrite.
|
||||||
times.push_back( Clock::now() );
|
std::vector<TimePoint<Clock>> times(points);
|
||||||
|
for ( auto& time : times ) {
|
||||||
|
time = Clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<double> deltas;
|
std::vector<double> deltas;
|
||||||
deltas.reserve(static_cast<size_t>(k));
|
deltas.reserve(static_cast<size_t>(k));
|
||||||
for ( size_t idx = 1; idx < times.size(); ++idx ) {
|
for ( size_t idx = 1; idx < points; ++idx ) {
|
||||||
deltas.push_back( static_cast<double>(
|
deltas.push_back( static_cast<double>(
|
||||||
( times[idx] - times[idx - 1] ).count() ) );
|
( times[idx] - times[idx - 1] ).count() ) );
|
||||||
}
|
}
|
||||||
@ -2103,12 +2086,12 @@ namespace Catch {
|
|||||||
: fun(CATCH_MOVE(func)), name(CATCH_MOVE(benchmarkName)) {}
|
: fun(CATCH_MOVE(func)), name(CATCH_MOVE(benchmarkName)) {}
|
||||||
|
|
||||||
template <typename Clock>
|
template <typename Clock>
|
||||||
ExecutionPlan prepare(const IConfig &cfg, Environment env) const {
|
ExecutionPlan prepare(const IConfig &cfg, Environment env) {
|
||||||
auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
|
auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
|
||||||
auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
|
auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
|
||||||
auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<IDuration>(run_time), 1, fun);
|
auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<IDuration>(run_time), 1, fun);
|
||||||
int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
|
int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
|
||||||
return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FDuration>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
|
return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), CATCH_MOVE(fun), std::chrono::duration_cast<FDuration>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Clock = default_clock>
|
template <typename Clock = default_clock>
|
||||||
@ -3347,6 +3330,18 @@ namespace Catch {
|
|||||||
#endif // CATCH_ASSERTION_RESULT_HPP_INCLUDED
|
#endif // CATCH_ASSERTION_RESULT_HPP_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef CATCH_CASE_SENSITIVE_HPP_INCLUDED
|
||||||
|
#define CATCH_CASE_SENSITIVE_HPP_INCLUDED
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
enum class CaseSensitive { Yes, No };
|
||||||
|
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_CASE_SENSITIVE_HPP_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#ifndef CATCH_CONFIG_HPP_INCLUDED
|
#ifndef CATCH_CONFIG_HPP_INCLUDED
|
||||||
#define CATCH_CONFIG_HPP_INCLUDED
|
#define CATCH_CONFIG_HPP_INCLUDED
|
||||||
|
|
||||||
@ -3366,18 +3361,6 @@ namespace Catch {
|
|||||||
#define CATCH_WILDCARD_PATTERN_HPP_INCLUDED
|
#define CATCH_WILDCARD_PATTERN_HPP_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef CATCH_CASE_SENSITIVE_HPP_INCLUDED
|
|
||||||
#define CATCH_CASE_SENSITIVE_HPP_INCLUDED
|
|
||||||
|
|
||||||
namespace Catch {
|
|
||||||
|
|
||||||
enum class CaseSensitive { Yes, No };
|
|
||||||
|
|
||||||
} // namespace Catch
|
|
||||||
|
|
||||||
#endif // CATCH_CASE_SENSITIVE_HPP_INCLUDED
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace Catch
|
namespace Catch
|
||||||
@ -5953,6 +5936,8 @@ namespace Catch {
|
|||||||
|
|
||||||
class ITestInvoker {
|
class ITestInvoker {
|
||||||
public:
|
public:
|
||||||
|
virtual void prepareTestCase();
|
||||||
|
virtual void tearDownTestCase();
|
||||||
virtual void invoke() const = 0;
|
virtual void invoke() const = 0;
|
||||||
virtual ~ITestInvoker(); // = default
|
virtual ~ITestInvoker(); // = default
|
||||||
};
|
};
|
||||||
@ -6005,6 +5990,33 @@ Detail::unique_ptr<ITestInvoker> makeTestInvoker( void (C::*testAsMethod)() ) {
|
|||||||
return Detail::make_unique<TestInvokerAsMethod<C>>( testAsMethod );
|
return Detail::make_unique<TestInvokerAsMethod<C>>( testAsMethod );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename C>
|
||||||
|
class TestInvokerFixture : public ITestInvoker {
|
||||||
|
void ( C::*m_testAsMethod )() const;
|
||||||
|
Detail::unique_ptr<C> m_fixture = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TestInvokerFixture( void ( C::*testAsMethod )() const) noexcept : m_testAsMethod( testAsMethod ) {}
|
||||||
|
|
||||||
|
void prepareTestCase() override {
|
||||||
|
m_fixture = Detail::make_unique<C>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDownTestCase() override {
|
||||||
|
m_fixture.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void invoke() const override {
|
||||||
|
auto* f = m_fixture.get();
|
||||||
|
( f->*m_testAsMethod )();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename C>
|
||||||
|
Detail::unique_ptr<ITestInvoker> makeTestInvokerFixture( void ( C::*testAsMethod )() const ) {
|
||||||
|
return Detail::make_unique<TestInvokerFixture<C>>( testAsMethod );
|
||||||
|
}
|
||||||
|
|
||||||
struct NameAndTags {
|
struct NameAndTags {
|
||||||
constexpr NameAndTags( StringRef name_ = StringRef(),
|
constexpr NameAndTags( StringRef name_ = StringRef(),
|
||||||
StringRef tags_ = StringRef() ) noexcept:
|
StringRef tags_ = StringRef() ) noexcept:
|
||||||
@ -6101,6 +6113,26 @@ static int catchInternalSectionHint = 0;
|
|||||||
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
|
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
|
||||||
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ )
|
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ )
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
#define INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE2( TestName, ClassName, ... ) \
|
||||||
|
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
|
||||||
|
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
|
||||||
|
CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
|
||||||
|
namespace { \
|
||||||
|
struct TestName : INTERNAL_CATCH_REMOVE_PARENS( ClassName ) { \
|
||||||
|
void test() const; \
|
||||||
|
}; \
|
||||||
|
const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
|
||||||
|
Catch::makeTestInvokerFixture( &TestName::test ), \
|
||||||
|
CATCH_INTERNAL_LINEINFO, \
|
||||||
|
#ClassName##_catch_sr, \
|
||||||
|
Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
|
||||||
|
} \
|
||||||
|
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
|
||||||
|
void TestName::test() const
|
||||||
|
#define INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE( ClassName, ... ) \
|
||||||
|
INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ )
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
|
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
|
||||||
@ -6158,6 +6190,7 @@ static int catchInternalSectionHint = 0;
|
|||||||
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
||||||
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
||||||
|
#define CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, __VA_ARGS__ )
|
||||||
#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
||||||
#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
||||||
#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
|
#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
|
||||||
@ -6212,6 +6245,7 @@ static int catchInternalSectionHint = 0;
|
|||||||
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
||||||
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
||||||
#define CATCH_METHOD_AS_TEST_CASE( method, ... )
|
#define CATCH_METHOD_AS_TEST_CASE( method, ... )
|
||||||
|
#define CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
||||||
#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
||||||
#define CATCH_SECTION( ... )
|
#define CATCH_SECTION( ... )
|
||||||
#define CATCH_DYNAMIC_SECTION( ... )
|
#define CATCH_DYNAMIC_SECTION( ... )
|
||||||
@ -6257,6 +6291,7 @@ static int catchInternalSectionHint = 0;
|
|||||||
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
|
||||||
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
|
||||||
#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
|
||||||
|
#define TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, __VA_ARGS__ )
|
||||||
#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
|
||||||
#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
|
||||||
#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
|
#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
|
||||||
@ -6310,6 +6345,7 @@ static int catchInternalSectionHint = 0;
|
|||||||
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__)
|
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__)
|
||||||
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
|
||||||
#define METHOD_AS_TEST_CASE( method, ... )
|
#define METHOD_AS_TEST_CASE( method, ... )
|
||||||
|
#define TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__)
|
||||||
#define REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
#define REGISTER_TEST_CASE( Function, ... ) (void)(0)
|
||||||
#define SECTION( ... )
|
#define SECTION( ... )
|
||||||
#define DYNAMIC_SECTION( ... )
|
#define DYNAMIC_SECTION( ... )
|
||||||
@ -7103,6 +7139,14 @@ namespace Catch {
|
|||||||
TestCaseHandle(TestCaseInfo* info, ITestInvoker* invoker) :
|
TestCaseHandle(TestCaseInfo* info, ITestInvoker* invoker) :
|
||||||
m_info(info), m_invoker(invoker) {}
|
m_info(info), m_invoker(invoker) {}
|
||||||
|
|
||||||
|
void prepareTestCase() const {
|
||||||
|
m_invoker->prepareTestCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDownTestCase() const {
|
||||||
|
m_invoker->tearDownTestCase();
|
||||||
|
}
|
||||||
|
|
||||||
void invoke() const {
|
void invoke() const {
|
||||||
m_invoker->invoke();
|
m_invoker->invoke();
|
||||||
}
|
}
|
||||||
@ -7271,7 +7315,7 @@ namespace Catch {
|
|||||||
#define CATCH_VERSION_MACROS_HPP_INCLUDED
|
#define CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||||
|
|
||||||
#define CATCH_VERSION_MAJOR 3
|
#define CATCH_VERSION_MAJOR 3
|
||||||
#define CATCH_VERSION_MINOR 6
|
#define CATCH_VERSION_MINOR 7
|
||||||
#define CATCH_VERSION_PATCH 0
|
#define CATCH_VERSION_PATCH 0
|
||||||
|
|
||||||
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||||
@ -10033,106 +10077,67 @@ namespace Catch {
|
|||||||
#define CATCH_OUTPUT_REDIRECT_HPP_INCLUDED
|
#define CATCH_OUTPUT_REDIRECT_HPP_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cassert>
|
||||||
#include <iosfwd>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
class RedirectedStream {
|
|
||||||
std::ostream& m_originalStream;
|
|
||||||
std::ostream& m_redirectionStream;
|
|
||||||
std::streambuf* m_prevBuf;
|
|
||||||
|
|
||||||
public:
|
|
||||||
RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream );
|
|
||||||
~RedirectedStream();
|
|
||||||
};
|
|
||||||
|
|
||||||
class RedirectedStdOut {
|
|
||||||
ReusableStringStream m_rss;
|
|
||||||
RedirectedStream m_cout;
|
|
||||||
public:
|
|
||||||
RedirectedStdOut();
|
|
||||||
auto str() const -> std::string;
|
|
||||||
};
|
|
||||||
|
|
||||||
// StdErr has two constituent streams in C++, std::cerr and std::clog
|
|
||||||
// This means that we need to redirect 2 streams into 1 to keep proper
|
|
||||||
// order of writes
|
|
||||||
class RedirectedStdErr {
|
|
||||||
ReusableStringStream m_rss;
|
|
||||||
RedirectedStream m_cerr;
|
|
||||||
RedirectedStream m_clog;
|
|
||||||
public:
|
|
||||||
RedirectedStdErr();
|
|
||||||
auto str() const -> std::string;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RedirectedStreams {
|
|
||||||
public:
|
|
||||||
RedirectedStreams(RedirectedStreams const&) = delete;
|
|
||||||
RedirectedStreams& operator=(RedirectedStreams const&) = delete;
|
|
||||||
RedirectedStreams(RedirectedStreams&&) = delete;
|
|
||||||
RedirectedStreams& operator=(RedirectedStreams&&) = delete;
|
|
||||||
|
|
||||||
RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr);
|
|
||||||
~RedirectedStreams();
|
|
||||||
private:
|
|
||||||
std::string& m_redirectedCout;
|
|
||||||
std::string& m_redirectedCerr;
|
|
||||||
RedirectedStdOut m_redirectedStdOut;
|
|
||||||
RedirectedStdErr m_redirectedStdErr;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(CATCH_CONFIG_NEW_CAPTURE)
|
|
||||||
|
|
||||||
// Windows's implementation of std::tmpfile is terrible (it tries
|
|
||||||
// to create a file inside system folder, thus requiring elevated
|
|
||||||
// privileges for the binary), so we have to use tmpnam(_s) and
|
|
||||||
// create the file ourselves there.
|
|
||||||
class TempFile {
|
|
||||||
public:
|
|
||||||
TempFile(TempFile const&) = delete;
|
|
||||||
TempFile& operator=(TempFile const&) = delete;
|
|
||||||
TempFile(TempFile&&) = delete;
|
|
||||||
TempFile& operator=(TempFile&&) = delete;
|
|
||||||
|
|
||||||
TempFile();
|
|
||||||
~TempFile();
|
|
||||||
|
|
||||||
std::FILE* getFile();
|
|
||||||
std::string getContents();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::FILE* m_file = nullptr;
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
char m_buffer[L_tmpnam] = { 0 };
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class OutputRedirect {
|
class OutputRedirect {
|
||||||
|
bool m_redirectActive = false;
|
||||||
|
virtual void activateImpl() = 0;
|
||||||
|
virtual void deactivateImpl() = 0;
|
||||||
public:
|
public:
|
||||||
OutputRedirect(OutputRedirect const&) = delete;
|
enum Kind {
|
||||||
OutputRedirect& operator=(OutputRedirect const&) = delete;
|
//! No redirect (noop implementation)
|
||||||
OutputRedirect(OutputRedirect&&) = delete;
|
None,
|
||||||
OutputRedirect& operator=(OutputRedirect&&) = delete;
|
//! Redirect std::cout/std::cerr/std::clog streams internally
|
||||||
|
Streams,
|
||||||
|
//! Redirect the stdout/stderr file descriptors into files
|
||||||
OutputRedirect(std::string& stdout_dest, std::string& stderr_dest);
|
FileDescriptors,
|
||||||
~OutputRedirect();
|
|
||||||
|
|
||||||
private:
|
|
||||||
int m_originalStdout = -1;
|
|
||||||
int m_originalStderr = -1;
|
|
||||||
TempFile m_stdoutFile;
|
|
||||||
TempFile m_stderrFile;
|
|
||||||
std::string& m_stdoutDest;
|
|
||||||
std::string& m_stderrDest;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
virtual ~OutputRedirect(); // = default;
|
||||||
|
|
||||||
|
// TODO: Do we want to check that redirect is not active before retrieving the output?
|
||||||
|
virtual std::string getStdout() = 0;
|
||||||
|
virtual std::string getStderr() = 0;
|
||||||
|
virtual void clearBuffers() = 0;
|
||||||
|
bool isActive() const { return m_redirectActive; }
|
||||||
|
void activate() {
|
||||||
|
assert( !m_redirectActive && "redirect is already active" );
|
||||||
|
activateImpl();
|
||||||
|
m_redirectActive = true;
|
||||||
|
}
|
||||||
|
void deactivate() {
|
||||||
|
assert( m_redirectActive && "redirect is not active" );
|
||||||
|
deactivateImpl();
|
||||||
|
m_redirectActive = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isRedirectAvailable( OutputRedirect::Kind kind);
|
||||||
|
Detail::unique_ptr<OutputRedirect> makeOutputRedirect( bool actual );
|
||||||
|
|
||||||
|
class RedirectGuard {
|
||||||
|
OutputRedirect* m_redirect;
|
||||||
|
bool m_activate;
|
||||||
|
bool m_previouslyActive;
|
||||||
|
bool m_moved = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RedirectGuard( bool activate, OutputRedirect& redirectImpl );
|
||||||
|
~RedirectGuard() noexcept( false );
|
||||||
|
|
||||||
|
RedirectGuard( RedirectGuard const& ) = delete;
|
||||||
|
RedirectGuard& operator=( RedirectGuard const& ) = delete;
|
||||||
|
|
||||||
|
// C++14 needs move-able guards to return them from functions
|
||||||
|
RedirectGuard( RedirectGuard&& rhs ) noexcept;
|
||||||
|
RedirectGuard& operator=( RedirectGuard&& rhs ) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
RedirectGuard scopedActivate( OutputRedirect& redirectImpl );
|
||||||
|
RedirectGuard scopedDeactivate( OutputRedirect& redirectImpl );
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
|
||||||
@ -10455,6 +10460,7 @@ namespace Catch {
|
|||||||
class IConfig;
|
class IConfig;
|
||||||
class IEventListener;
|
class IEventListener;
|
||||||
using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
|
using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
|
||||||
|
class OutputRedirect;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -10541,7 +10547,7 @@ namespace Catch {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr );
|
void runCurrentTest();
|
||||||
void invokeActiveTestCase();
|
void invokeActiveTestCase();
|
||||||
|
|
||||||
void resetAssertionInfo();
|
void resetAssertionInfo();
|
||||||
@ -10574,6 +10580,7 @@ namespace Catch {
|
|||||||
std::vector<SectionEndInfo> m_unfinishedSections;
|
std::vector<SectionEndInfo> m_unfinishedSections;
|
||||||
std::vector<ITracker*> m_activeSections;
|
std::vector<ITracker*> m_activeSections;
|
||||||
TrackerContext m_trackerContext;
|
TrackerContext m_trackerContext;
|
||||||
|
Detail::unique_ptr<OutputRedirect> m_outputRedirect;
|
||||||
FatalConditionHandler m_fatalConditionhandler;
|
FatalConditionHandler m_fatalConditionhandler;
|
||||||
bool m_lastAssertionPassed = false;
|
bool m_lastAssertionPassed = false;
|
||||||
bool m_shouldReportUnexpected = true;
|
bool m_shouldReportUnexpected = true;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
project(
|
project(
|
||||||
'catch2',
|
'catch2',
|
||||||
'cpp',
|
'cpp',
|
||||||
version: '3.6.0', # CML version placeholder, don't delete
|
version: '3.7.0', # CML version placeholder, don't delete
|
||||||
license: 'BSL-1.0',
|
license: 'BSL-1.0',
|
||||||
meson_version: '>=0.54.1',
|
meson_version: '>=0.54.1',
|
||||||
)
|
)
|
||||||
|
@ -36,7 +36,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Version const& libraryVersion() {
|
Version const& libraryVersion() {
|
||||||
static Version version( 3, 6, 0, "", 0 );
|
static Version version( 3, 7, 0, "", 0 );
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#define CATCH_VERSION_MACROS_HPP_INCLUDED
|
#define CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||||
|
|
||||||
#define CATCH_VERSION_MAJOR 3
|
#define CATCH_VERSION_MAJOR 3
|
||||||
#define CATCH_VERSION_MINOR 6
|
#define CATCH_VERSION_MINOR 7
|
||||||
#define CATCH_VERSION_PATCH 0
|
#define CATCH_VERSION_PATCH 0
|
||||||
|
|
||||||
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
|
||||||
|
Loading…
Reference in New Issue
Block a user