diff --git a/CMakeLists.txt b/CMakeLists.txt index 592b7c05..ca86274f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,7 +105,6 @@ CheckFileList(SURROGATE_SOURCES ${SELF_TEST_DIR}/SurrogateCpps) # Please keep these ordered alphabetically set(TOP_LEVEL_HEADERS ${HEADER_DIR}/catch.hpp - ${HEADER_DIR}/catch_session.hpp ${HEADER_DIR}/catch_with_main.hpp ) CheckFileList(TOP_LEVEL_HEADERS ${HEADER_DIR}) @@ -169,6 +168,7 @@ set(INTERNAL_HEADERS ${HEADER_DIR}/internal/catch_benchmark.h ${HEADER_DIR}/internal/catch_section.h ${HEADER_DIR}/internal/catch_section_info.h + ${HEADER_DIR}/internal/catch_session.h ${HEADER_DIR}/internal/catch_startup_exception_registry.h ${HEADER_DIR}/internal/catch_stream.h ${HEADER_DIR}/internal/catch_streambuf.h @@ -222,6 +222,7 @@ set(IMPL_SOURCES ${HEADER_DIR}/internal/catch_run_context.cpp ${HEADER_DIR}/internal/catch_section.cpp ${HEADER_DIR}/internal/catch_section_info.cpp + ${HEADER_DIR}/internal/catch_session.cpp ${HEADER_DIR}/internal/catch_startup_exception_registry.cpp ${HEADER_DIR}/internal/catch_stream.cpp ${HEADER_DIR}/internal/catch_stringref.cpp diff --git a/include/catch_session.hpp b/include/catch_session.hpp deleted file mode 100644 index ed1a826a..00000000 --- a/include/catch_session.hpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Created by Phil on 31/10/2010. - * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED -#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED - -#include "internal/catch_commandline.hpp" -#include "internal/catch_console_colour.hpp" -#include "internal/catch_enforce.h" -#include "internal/catch_list.h" -#include "internal/catch_run_context.hpp" -#include "internal/catch_stream.h" -#include "internal/catch_test_spec.hpp" -#include "internal/catch_version.h" -#include "internal/catch_interfaces_reporter.h" -#include "internal/catch_random_number_generator.h" -#include "internal/catch_startup_exception_registry.h" -#include "internal/catch_text.h" - -#include -#include -#include -#include - -namespace Catch { - - IStreamingReporterPtr createReporter( std::string const& reporterName, IConfigPtr const& config ) { - auto reporter = getRegistryHub().getReporterRegistry().create( reporterName, config ); - CATCH_ENFORCE( reporter, "No reporter registered with name: '" << reporterName << "'" ); - - return reporter; - } - -#ifndef CATCH_CONFIG_DEFAULT_REPORTER -#define CATCH_CONFIG_DEFAULT_REPORTER "console" -#endif - - IStreamingReporterPtr makeReporter( std::shared_ptr const& config ) { - auto const& reporterNames = config->getReporterNames(); - if( reporterNames.empty() ) - return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config ); - - IStreamingReporterPtr reporter; - for( auto const& name : reporterNames ) - addReporter( reporter, createReporter( name, config ) ); - return reporter; - } - void addListeners( IStreamingReporterPtr& reporters, IConfigPtr const& config ) { - auto const& listeners = getRegistryHub().getReporterRegistry().getListeners(); - for( auto const& listener : listeners ) - addReporter(reporters, listener->create( ReporterConfig( config ) ) ); - } - - - Totals runTests( std::shared_ptr const& config ) { - - IStreamingReporterPtr reporter = makeReporter( config ); - addListeners( reporter, config ); - - RunContext context( config, std::move( reporter ) ); - - Totals totals; - - context.testGroupStarting( config->name(), 1, 1 ); - - TestSpec testSpec = config->testSpec(); - if( !testSpec.hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests - - std::vector const& allTestCases = getAllTestCasesSorted( *config ); - for( auto const& testCase : allTestCases ) { - if( !context.aborting() && matchTest( testCase, testSpec, *config ) ) - totals += context.runTest( testCase ); - else - context.reporter().skipTest( testCase ); - } - - context.testGroupEnded( config->name(), totals, 1, 1 ); - return totals; - } - - void applyFilenamesAsTags( IConfig const& config ) { - auto& tests = const_cast&>( getAllTestCasesSorted( config ) ); - for( auto& testCase : tests ) { - auto tags = testCase.tags; - - std::string filename = testCase.lineInfo.file; - std::string::size_type lastSlash = filename.find_last_of( "\\/" ); - if( lastSlash != std::string::npos ) - filename = filename.substr( lastSlash+1 ); - - std::string::size_type lastDot = filename.find_last_of( '.' ); - if( lastDot != std::string::npos ) - filename = filename.substr( 0, lastDot ); - - tags.push_back( '#' + filename ); - setTags( testCase, tags ); - } - } - - - class Session : NonCopyable { - static const int MaxExitCode; - public: - - Session() { - static bool alreadyInstantiated = false; - if( alreadyInstantiated ) - CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); - alreadyInstantiated = true; - m_cli = makeCommandLineParser( m_configData ); - } - ~Session() override { - Catch::cleanUp(); - } - - void showHelp() const { - Catch::cout() - << "\nCatch v" << libraryVersion() << "\n" - << m_cli << std::endl - << "For more detailed usage please see the project docs\n" << std::endl; - } - void libIdentify() { - Catch::cout() - << std::left << std::setw(16) << "description: " << "A Catch test executable\n" - << std::left << std::setw(16) << "category: " << "testframework\n" - << std::left << std::setw(16) << "framework: " << "Catch Test\n" - << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; - } - - int applyCommandLine( int argc, char* argv[] ) { - auto result = m_cli.parse( clara::Args( argc, argv ) ); - if( !result ) { - Catch::cerr() - << Colour( Colour::Red ) - << "\nError(s) in input:\n" - << Column( result.errorMessage() ).indent( 2 ) - << "\n\n"; - Catch::cerr() << "Run with -? for usage\n" << std::endl; - return MaxExitCode; - } - - if( m_configData.showHelp ) - showHelp(); - if( m_configData.libIdentify ) - libIdentify(); - m_config.reset(); - return 0; - } - - void useConfigData( ConfigData const& configData ) { - m_configData = configData; - m_config.reset(); - } - - int run( int argc, char* argv[] ) { - const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); - if ( !exceptions.empty() ) { - Catch::cerr() << "Errors occured during startup!" << '\n'; - // iterate over all exceptions and notify user - for ( const auto& ex_ptr : exceptions ) { - try { - std::rethrow_exception(ex_ptr); - } catch ( std::exception const& ex ) { - Catch::cerr() << ex.what() << '\n'; - } - } - return 1; - } - int returnCode = applyCommandLine( argc, argv ); - if( returnCode == 0 ) - returnCode = run(); - return returnCode; - } - - #if defined(WIN32) && defined(UNICODE) - int run( int argc, wchar_t* const argv[] ) { - - char **utf8Argv = new char *[ argc ]; - - for ( int i = 0; i < argc; ++i ) { - int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); - - utf8Argv[ i ] = new char[ bufSize ]; - - WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); - } - - int returnCode = run( argc, utf8Argv ); - - for ( int i = 0; i < argc; ++i ) - delete [] utf8Argv[ i ]; - - delete [] utf8Argv; - - return returnCode; - } - #endif - int run() { - if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { - Catch::cout() << "...waiting for enter/ return before starting" << std::endl; - static_cast(std::getchar()); - } - int exitCode = runInternal(); - if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { - Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; - static_cast(std::getchar()); - } - return exitCode; - } - - clara::Parser const& cli() const { - return m_cli; - } - void cli( clara::Parser const& newParser ) { - m_cli = newParser; - } - ConfigData& configData() { - return m_configData; - } - Config& config() { - if( !m_config ) - m_config = std::make_shared( m_configData ); - return *m_config; - } - private: - int runInternal() { - if( m_configData.showHelp || m_configData.libIdentify ) - return 0; - - try - { - config(); // Force config to be constructed - - seedRng( *m_config ); - - if( m_configData.filenamesAsTags ) - applyFilenamesAsTags( *m_config ); - - // Handle list request - if( Option listed = list( config() ) ) - return static_cast( *listed ); - - return (std::min)( MaxExitCode, static_cast( runTests( m_config ).assertions.failed ) ); - } - catch( std::exception& ex ) { - Catch::cerr() << ex.what() << std::endl; - return MaxExitCode; - } - } - - clara::Parser m_cli; - ConfigData m_configData; - std::shared_ptr m_config; - }; - - const int Session::MaxExitCode = 255; - -} // end namespace Catch - -#endif // TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED diff --git a/include/internal/catch_common.h b/include/internal/catch_common.h index 53602ee6..5e22825d 100644 --- a/include/internal/catch_common.h +++ b/include/internal/catch_common.h @@ -36,8 +36,8 @@ namespace Catch { NonCopyable& operator = ( NonCopyable && ) = delete; protected: - NonCopyable() {} - virtual ~NonCopyable(); + NonCopyable() = default; + virtual ~NonCopyable() = default; }; struct SourceLineInfo { diff --git a/include/internal/catch_config.hpp b/include/internal/catch_config.hpp index 0f86137f..80847be5 100644 --- a/include/internal/catch_config.hpp +++ b/include/internal/catch_config.hpp @@ -11,6 +11,9 @@ #include "catch_test_spec_parser.hpp" #include "catch_interfaces_config.h" +// Libstdc++ doesn't like incomplete classes for unique_ptr +#include "catch_stream.h" + #include #include #include diff --git a/include/internal/catch_default_main.hpp b/include/internal/catch_default_main.hpp index 9b7c2890..8155c43f 100644 --- a/include/internal/catch_default_main.hpp +++ b/include/internal/catch_default_main.hpp @@ -8,6 +8,8 @@ #ifndef TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED #define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED +#include "catch_session.h" + #ifndef __OBJC__ #if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) diff --git a/include/internal/catch_external_interfaces.h b/include/internal/catch_external_interfaces.h index dffd5187..4eb55256 100644 --- a/include/internal/catch_external_interfaces.h +++ b/include/internal/catch_external_interfaces.h @@ -8,6 +8,7 @@ #define TWOBLUECUBES_CATCH_EXTERNAL_INTERFACES_H_INCLUDED #include "../reporters/catch_reporter_bases.hpp" +#include "catch_console_colour.hpp" #include "catch_reporter_registrars.hpp" #endif // TWOBLUECUBES_CATCH_EXTERNAL_INTERFACES_H_INCLUDED diff --git a/include/internal/catch_impl.hpp b/include/internal/catch_impl.hpp index d9a644d0..5debe23c 100644 --- a/include/internal/catch_impl.hpp +++ b/include/internal/catch_impl.hpp @@ -17,15 +17,8 @@ #endif -// Temporary hack to fix separately provided reporters -#include "../reporters/catch_reporter_bases.hpp" -#include "catch_reporter_registrars.hpp" -// - #include "internal/catch_leak_detector.h" - -#include "../catch_session.hpp" #include "catch_test_spec.hpp" #include "catch_test_case_tracker.hpp" @@ -37,12 +30,6 @@ namespace Catch { // These are all here to avoid warnings about not having any out of line // virtual methods - NonCopyable::~NonCopyable() {} - IStream::~IStream() noexcept {} - FileStream::~FileStream() noexcept {} - CoutStream::~CoutStream() noexcept {} - DebugOutStream::~DebugOutStream() noexcept {} - StreamBufBase::~StreamBufBase() noexcept {} IResultCapture::~IResultCapture() {} ITestInvoker::~ITestInvoker() {} ITestCaseRegistry::~ITestCaseRegistry() {} diff --git a/include/internal/catch_session.cpp b/include/internal/catch_session.cpp new file mode 100644 index 00000000..d10e9510 --- /dev/null +++ b/include/internal/catch_session.cpp @@ -0,0 +1,251 @@ +/* + * Created by Martin on 31/08/2017. + * + * 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) + */ + +#include "catch_session.h" +#include "catch_commandline.hpp" +#include "catch_console_colour.hpp" +#include "catch_enforce.h" +#include "catch_list.h" +#include "catch_run_context.hpp" +#include "catch_stream.h" +#include "catch_test_spec.hpp" +#include "catch_version.h" +#include "catch_interfaces_reporter.h" +#include "catch_random_number_generator.h" +#include "catch_startup_exception_registry.h" +#include "catch_text.h" + +#include +#include + +static const int MaxExitCode = 255; + + +namespace Catch { + + IStreamingReporterPtr createReporter( std::string const& reporterName, IConfigPtr const& config ) { + auto reporter = getRegistryHub().getReporterRegistry().create( reporterName, config ); + CATCH_ENFORCE( reporter, "No reporter registered with name: '" << reporterName << "'" ); + + return reporter; + } + +#ifndef CATCH_CONFIG_DEFAULT_REPORTER +#define CATCH_CONFIG_DEFAULT_REPORTER "console" +#endif + + IStreamingReporterPtr makeReporter( std::shared_ptr const& config ) { + auto const& reporterNames = config->getReporterNames(); + if( reporterNames.empty() ) + return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config ); + + IStreamingReporterPtr reporter; + for( auto const& name : reporterNames ) + addReporter( reporter, createReporter( name, config ) ); + return reporter; + } + void addListeners( IStreamingReporterPtr& reporters, IConfigPtr const& config ) { + auto const& listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( auto const& listener : listeners ) + addReporter(reporters, listener->create( ReporterConfig( config ) ) ); + } + + + Totals runTests( std::shared_ptr const& config ) { + + IStreamingReporterPtr reporter = makeReporter( config ); + addListeners( reporter, config ); + + RunContext context( config, std::move( reporter ) ); + + Totals totals; + + context.testGroupStarting( config->name(), 1, 1 ); + + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector const& allTestCases = getAllTestCasesSorted( *config ); + for( auto const& testCase : allTestCases ) { + if( !context.aborting() && matchTest( testCase, testSpec, *config ) ) + totals += context.runTest( testCase ); + else + context.reporter().skipTest( testCase ); + } + + context.testGroupEnded( config->name(), totals, 1, 1 ); + return totals; + } + + void applyFilenamesAsTags( IConfig const& config ) { + auto& tests = const_cast&>( getAllTestCasesSorted( config ) ); + for( auto& testCase : tests ) { + auto tags = testCase.tags; + + std::string filename = testCase.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); + + std::string::size_type lastDot = filename.find_last_of( '.' ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); + + tags.push_back( '#' + filename ); + setTags( testCase, tags ); + } + } + + + Session::Session() { + static bool alreadyInstantiated = false; + if( alreadyInstantiated ) + CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); + alreadyInstantiated = true; + m_cli = makeCommandLineParser( m_configData ); + } + Session::~Session() { + Catch::cleanUp(); + } + + void Session::showHelp() const { + Catch::cout() + << "\nCatch v" << libraryVersion() << "\n" + << m_cli << std::endl + << "For more detailed usage please see the project docs\n" << std::endl; + } + void Session::libIdentify() { + Catch::cout() + << std::left << std::setw(16) << "description: " << "A Catch test executable\n" + << std::left << std::setw(16) << "category: " << "testframework\n" + << std::left << std::setw(16) << "framework: " << "Catch Test\n" + << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; + } + + int Session::applyCommandLine( int argc, char* argv[] ) { + auto result = m_cli.parse( clara::Args( argc, argv ) ); + if( !result ) { + Catch::cerr() + << Colour( Colour::Red ) + << "\nError(s) in input:\n" + << Column( result.errorMessage() ).indent( 2 ) + << "\n\n"; + Catch::cerr() << "Run with -? for usage\n" << std::endl; + return MaxExitCode; + } + + if( m_configData.showHelp ) + showHelp(); + if( m_configData.libIdentify ) + libIdentify(); + m_config.reset(); + return 0; + } + + void Session::useConfigData( ConfigData const& configData ) { + m_configData = configData; + m_config.reset(); + } + + int Session::run( int argc, char* argv[] ) { + const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); + if ( !exceptions.empty() ) { + Catch::cerr() << "Errors occured during startup!" << '\n'; + // iterate over all exceptions and notify user + for ( const auto& ex_ptr : exceptions ) { + try { + std::rethrow_exception(ex_ptr); + } catch ( std::exception const& ex ) { + Catch::cerr() << ex.what() << '\n'; + } + } + return 1; + } + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + +#if defined(WIN32) && defined(UNICODE) + int Session::run( int argc, wchar_t* const argv[] ) { + + char **utf8Argv = new char *[ argc ]; + + for ( int i = 0; i < argc; ++i ) { + int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); + + utf8Argv[ i ] = new char[ bufSize ]; + + WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); + } + + int returnCode = run( argc, utf8Argv ); + + for ( int i = 0; i < argc; ++i ) + delete [] utf8Argv[ i ]; + + delete [] utf8Argv; + + return returnCode; + } +#endif + int Session::run() { + if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { + Catch::cout() << "...waiting for enter/ return before starting" << std::endl; + static_cast(std::getchar()); + } + int exitCode = runInternal(); + if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { + Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; + static_cast(std::getchar()); + } + return exitCode; + } + + clara::Parser const& Session::cli() const { + return m_cli; + } + void Session::cli( clara::Parser const& newParser ) { + m_cli = newParser; + } + ConfigData& Session::configData() { + return m_configData; + } + Config& Session::config() { + if( !m_config ) + m_config = std::make_shared( m_configData ); + return *m_config; + } + + int Session::runInternal() { + if( m_configData.showHelp || m_configData.libIdentify ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + return (std::min)( MaxExitCode, static_cast( runTests( m_config ).assertions.failed ) ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return MaxExitCode; + } + } + +} // end namespace Catch diff --git a/include/internal/catch_session.h b/include/internal/catch_session.h new file mode 100644 index 00000000..492d6d31 --- /dev/null +++ b/include/internal/catch_session.h @@ -0,0 +1,52 @@ +/* + * Created by Phil on 31/10/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +#include "catch_commandline.hpp" +#include "catch_config.hpp" +#include "catch_text.h" + +#include + +namespace Catch { + + class Session : NonCopyable { + public: + + Session(); + ~Session() override; + + void showHelp() const; + void libIdentify(); + + int applyCommandLine( int argc, char* argv[] ); + + void useConfigData( ConfigData const& configData ); + + int run( int argc, char* argv[] ); + #if defined(WIN32) && defined(UNICODE) + int run( int argc, wchar_t* const argv[] ); + #endif + int run(); + + clara::Parser const& cli() const; + void cli( clara::Parser const& newParser ); + ConfigData& configData(); + Config& config(); + private: + int runInternal(); + + clara::Parser m_cli; + ConfigData m_configData; + std::shared_ptr m_config; + }; + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED diff --git a/include/internal/catch_stream.h b/include/internal/catch_stream.h index 488e8b20..1ab59ca3 100644 --- a/include/internal/catch_stream.h +++ b/include/internal/catch_stream.h @@ -24,7 +24,7 @@ namespace Catch { struct IStream { - virtual ~IStream() noexcept; + virtual ~IStream() = default; virtual std::ostream& stream() const = 0; }; @@ -32,7 +32,7 @@ namespace Catch { mutable std::ofstream m_ofs; public: FileStream( std::string const& filename ); - ~FileStream() noexcept override; + ~FileStream() override = default; public: // IStream std::ostream& stream() const override; }; @@ -42,7 +42,7 @@ namespace Catch { mutable std::ostream m_os; public: CoutStream(); - ~CoutStream() noexcept override; + ~CoutStream() override = default; public: // IStream std::ostream& stream() const override; @@ -54,7 +54,7 @@ namespace Catch { mutable std::ostream m_os; public: DebugOutStream(); - ~DebugOutStream() noexcept override; + ~DebugOutStream() override = default; public: // IStream std::ostream& stream() const override; diff --git a/include/internal/catch_streambuf.h b/include/internal/catch_streambuf.h index dba84357..7fd17e40 100644 --- a/include/internal/catch_streambuf.h +++ b/include/internal/catch_streambuf.h @@ -16,7 +16,7 @@ namespace Catch { class StreamBufBase : public std::streambuf { public: - virtual ~StreamBufBase() noexcept; + virtual ~StreamBufBase() = default; }; }