mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-11-04 09:01:50 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			214 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 *  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_runner_impl.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 {
 | 
						|
 | 
						|
    class Runner {
 | 
						|
 | 
						|
    public:
 | 
						|
        Runner( Ptr<Config> const& config )
 | 
						|
        :   m_config( config )
 | 
						|
        {
 | 
						|
            openStream();
 | 
						|
            makeReporter();
 | 
						|
        }
 | 
						|
 | 
						|
        Totals runTests() {
 | 
						|
 | 
						|
            RunContext context( m_config.get(), m_reporter );
 | 
						|
 | 
						|
            Totals totals;
 | 
						|
 | 
						|
            context.testGroupStarting( "", 1, 1 ); // deprecated?
 | 
						|
 | 
						|
            TestSpec testSpec = m_config->testSpec();
 | 
						|
            if( !testSpec.hasFilters() )
 | 
						|
                testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
 | 
						|
 | 
						|
            std::vector<TestCase> testCases;
 | 
						|
            getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases );
 | 
						|
 | 
						|
            int testsRunForGroup = 0;
 | 
						|
            for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
 | 
						|
                    it != itEnd;
 | 
						|
                    ++it ) {
 | 
						|
                testsRunForGroup++;
 | 
						|
                if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) {
 | 
						|
 | 
						|
                    if( context.aborting() )
 | 
						|
                        break;
 | 
						|
 | 
						|
                    totals += context.runTest( *it );
 | 
						|
                    m_testsAlreadyRun.insert( *it );
 | 
						|
                }
 | 
						|
            }
 | 
						|
            context.testGroupEnded( "", totals, 1, 1 );
 | 
						|
            return totals;
 | 
						|
        }
 | 
						|
 | 
						|
    private:
 | 
						|
        void openStream() {
 | 
						|
            // Open output file, if specified
 | 
						|
            if( !m_config->getFilename().empty() ) {
 | 
						|
                m_ofs.open( m_config->getFilename().c_str() );
 | 
						|
                if( m_ofs.fail() ) {
 | 
						|
                    std::ostringstream oss;
 | 
						|
                    oss << "Unable to open file: '" << m_config->getFilename() << "'";
 | 
						|
                    throw std::domain_error( oss.str() );
 | 
						|
                }
 | 
						|
                m_config->setStreamBuf( m_ofs.rdbuf() );
 | 
						|
            }
 | 
						|
        }
 | 
						|
        void makeReporter() {
 | 
						|
            std::string reporterName = m_config->getReporterName().empty()
 | 
						|
                ? "console"
 | 
						|
                : m_config->getReporterName();
 | 
						|
 | 
						|
            m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() );
 | 
						|
            if( !m_reporter ) {
 | 
						|
                std::ostringstream oss;
 | 
						|
                oss << "No reporter registered with name: '" << reporterName << "'";
 | 
						|
                throw std::domain_error( oss.str() );
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
    private:
 | 
						|
        Ptr<Config> m_config;
 | 
						|
        std::ofstream m_ofs;
 | 
						|
        Ptr<IStreamingReporter> m_reporter;
 | 
						|
        std::set<TestCase> m_testsAlreadyRun;
 | 
						|
    };
 | 
						|
 | 
						|
    class Session {
 | 
						|
        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";
 | 
						|
                std::cerr << msg << std::endl;
 | 
						|
                throw std::logic_error( msg );
 | 
						|
            }
 | 
						|
            alreadyInstantiated = true;
 | 
						|
        }
 | 
						|
        ~Session() {
 | 
						|
            Catch::cleanUp();
 | 
						|
        }
 | 
						|
 | 
						|
        void showHelp( std::string const& processName ) {
 | 
						|
            std::cout << "\nCatch v"    << libraryVersion.majorVersion << "."
 | 
						|
                                        << libraryVersion.minorVersion << " build "
 | 
						|
                                        << libraryVersion.buildNumber;
 | 
						|
            if( libraryVersion.branchName != std::string( "master" ) )
 | 
						|
                std::cout << " (" << libraryVersion.branchName << " branch)";
 | 
						|
            std::cout << "\n";
 | 
						|
 | 
						|
            m_cli.usage( std::cout, processName );
 | 
						|
            std::cout << "For more detail usage please see the project docs\n" << std::endl;
 | 
						|
        }
 | 
						|
 | 
						|
        int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
 | 
						|
            try {
 | 
						|
                m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
 | 
						|
                m_unusedTokens = m_cli.parseInto( argc, argv, m_configData );
 | 
						|
                if( m_configData.showHelp )
 | 
						|
                    showHelp( m_configData.processName );
 | 
						|
                m_config.reset();
 | 
						|
            }
 | 
						|
            catch( std::exception& ex ) {
 | 
						|
                {
 | 
						|
                    Colour colourGuard( Colour::Red );
 | 
						|
                    std::cerr   << "\nError(s) in input:\n"
 | 
						|
                                << Text( ex.what(), TextAttributes().setIndent(2) )
 | 
						|
                                << "\n\n";
 | 
						|
                }
 | 
						|
                m_cli.usage( std::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 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
 | 
						|
                Runner runner( m_config );
 | 
						|
 | 
						|
                // Handle list request
 | 
						|
                if( Option<std::size_t> listed = list( config() ) )
 | 
						|
                    return static_cast<int>( *listed );
 | 
						|
 | 
						|
                return static_cast<int>( runner.runTests().assertions.failed );
 | 
						|
            }
 | 
						|
            catch( std::exception& ex ) {
 | 
						|
                std::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
 |