| /* |
| * 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_list.hpp" |
| #include "internal/catch_run_context.hpp" |
| #include "internal/catch_test_spec.hpp" |
| #include "internal/catch_version.h" |
| #include "internal/catch_text.h" |
| |
| #include <fstream> |
| #include <stdlib.h> |
| #include <limits> |
| |
| namespace Catch { |
| |
| Ptr<IStreamingReporter> createReporter( std::string const& reporterName, Ptr<Config> const& config ) { |
| Ptr<IStreamingReporter> reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); |
| if( !reporter ) { |
| std::ostringstream oss; |
| oss << "No reporter registered with name: '" << reporterName << "'"; |
| throw std::domain_error( oss.str() ); |
| } |
| return reporter; |
| } |
| |
| Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) { |
| std::vector<std::string> reporters = config->getReporterNames(); |
| if( reporters.empty() ) |
| reporters.push_back( "console" ); |
| |
| Ptr<IStreamingReporter> reporter; |
| for( auto const& name : reporters ) |
| reporter = addReporter( reporter, createReporter( name, config ) ); |
| return reporter; |
| } |
| Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters ) { |
| IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); |
| for( auto const& listener : listeners ) |
| reporters = addReporter(reporters, listener->create( ReporterConfig( config ) ) ); |
| return reporters; |
| } |
| |
| |
| Totals runTests( Ptr<Config> const& config ) { |
| |
| Ptr<IConfig const> iconfig = config.get(); |
| |
| Ptr<IStreamingReporter> reporter = makeReporter( config ); |
| reporter = addListeners( iconfig, reporter ); |
| |
| RunContext context( iconfig, 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<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig ); |
| for( auto const& testCase : allTestCases ) { |
| if( !context.aborting() && matchTest( testCase, testSpec, *iconfig ) ) |
| totals += context.runTest( testCase ); |
| else |
| reporter->skipTest( testCase ); |
| } |
| |
| context.testGroupEnded( iconfig->name(), totals, 1, 1 ); |
| return totals; |
| } |
| |
| void applyFilenamesAsTags( IConfig const& config ) { |
| auto& tests = const_cast<std::vector<TestCase>&>( getAllTestCasesSorted( config ) ); |
| for( auto& testCase : tests ) { |
| std::set<std::string> 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.insert( "#" + filename ); |
| setTags( testCase, tags ); |
| } |
| } |
| |
| class Session : NonCopyable { |
| static bool alreadyInstantiated; |
| |
| public: |
| |
| struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; |
| |
| Session() |
| : m_cli( makeCommandLineParser() ) { |
| if( alreadyInstantiated ) { |
| std::string msg = "Only one instance of Catch::Session can ever be used"; |
| Catch::cerr() << msg << std::endl; |
| throw std::logic_error( msg ); |
| } |
| alreadyInstantiated = true; |
| } |
| ~Session() { |
| Catch::cleanUp(); |
| } |
| |
| void showHelp( std::string const& processName ) { |
| Catch::cout() << "\nCatch v" << libraryVersion() << "\n"; |
| |
| m_cli.usage( Catch::cout(), processName ); |
| Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; |
| } |
| |
| int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { |
| try { |
| m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); |
| m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData ); |
| if( m_configData.showHelp ) |
| showHelp( m_configData.processName ); |
| m_config.reset(); |
| } |
| catch( std::exception& ex ) { |
| { |
| Colour colourGuard( Colour::Red ); |
| Catch::cerr() |
| << "\nError(s) in input:\n" |
| << Text( ex.what(), TextAttributes().setIndent(2) ) |
| << "\n\n"; |
| } |
| m_cli.usage( Catch::cout(), m_configData.processName ); |
| return (std::numeric_limits<int>::max)(); |
| } |
| return 0; |
| } |
| |
| void useConfigData( ConfigData const& _configData ) { |
| m_configData = _configData; |
| m_config.reset(); |
| } |
| |
| int run( int argc, char const* const* const argv ) { |
| |
| int returnCode = applyCommandLine( argc, argv ); |
| if( returnCode == 0 ) |
| returnCode = run(); |
| return returnCode; |
| } |
| |
| int run() { |
| if( m_configData.showHelp ) |
| return 0; |
| |
| try |
| { |
| config(); // Force config to be constructed |
| |
| seedRng( *m_config ); |
| |
| if( m_configData.filenamesAsTags ) |
| applyFilenamesAsTags( *m_config ); |
| |
| // Handle list request |
| if( Option<std::size_t> listed = list( config() ) ) |
| return static_cast<int>( *listed ); |
| |
| return static_cast<int>( runTests( m_config ).assertions.failed ); |
| } |
| catch( std::exception& ex ) { |
| Catch::cerr() << ex.what() << std::endl; |
| return (std::numeric_limits<int>::max)(); |
| } |
| } |
| |
| Clara::CommandLine<ConfigData> const& cli() const { |
| return m_cli; |
| } |
| std::vector<Clara::Parser::Token> const& unusedTokens() const { |
| return m_unusedTokens; |
| } |
| ConfigData& configData() { |
| return m_configData; |
| } |
| Config& config() { |
| if( !m_config ) |
| m_config = new Config( m_configData ); |
| return *m_config; |
| } |
| private: |
| Clara::CommandLine<ConfigData> m_cli; |
| std::vector<Clara::Parser::Token> m_unusedTokens; |
| ConfigData m_configData; |
| Ptr<Config> m_config; |
| }; |
| |
| bool Session::alreadyInstantiated = false; |
| |
| } // end namespace Catch |
| |
| #endif // TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED |