Phil Nash | d802600 | 2010-11-09 23:24:00 +0000 | [diff] [blame] | 1 | /* |
Phil Nash | d802600 | 2010-11-09 23:24:00 +0000 | [diff] [blame] | 2 | * Created by Phil on 31/10/2010. |
| 3 | * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. |
| 4 | * |
| 5 | * Distributed under the Boost Software License, Version 1.0. (See accompanying |
| 6 | * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
Phil Nash | d802600 | 2010-11-09 23:24:00 +0000 | [diff] [blame] | 7 | */ |
Phil Nash | d802600 | 2010-11-09 23:24:00 +0000 | [diff] [blame] | 8 | #ifndef TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED |
| 9 | #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED |
| 10 | |
Phil Nash | a695eb9 | 2012-08-13 07:46:10 +0100 | [diff] [blame] | 11 | #include "internal/catch_commandline.hpp" |
| 12 | #include "internal/catch_list.hpp" |
Phil Nash | 4cb7476 | 2015-08-05 19:02:17 +0100 | [diff] [blame] | 13 | #include "internal/catch_run_context.hpp" |
Phil Nash | b1e7d16 | 2014-05-16 18:28:58 +0100 | [diff] [blame] | 14 | #include "internal/catch_test_spec.hpp" |
Phil Nash | 7673a30 | 2012-11-15 22:15:41 +0000 | [diff] [blame] | 15 | #include "internal/catch_version.h" |
Phil Nash | 7059c6e | 2013-04-19 19:08:32 +0100 | [diff] [blame] | 16 | #include "internal/catch_text.h" |
Phil Nash | a695eb9 | 2012-08-13 07:46:10 +0100 | [diff] [blame] | 17 | |
Phil Nash | e846e07 | 2010-12-31 22:07:47 +0000 | [diff] [blame] | 18 | #include <fstream> |
Phil Nash | 9d12592 | 2011-02-04 09:30:36 +0000 | [diff] [blame] | 19 | #include <stdlib.h> |
Phil Nash | 1e15669 | 2011-03-15 22:41:27 +0000 | [diff] [blame] | 20 | #include <limits> |
Phil Nash | e846e07 | 2010-12-31 22:07:47 +0000 | [diff] [blame] | 21 | |
Phil Nash | ee18b8c | 2012-05-16 15:02:51 +0100 | [diff] [blame] | 22 | namespace Catch { |
| 23 | |
Phil Nash | 4cb7476 | 2015-08-05 19:02:17 +0100 | [diff] [blame] | 24 | Ptr<IStreamingReporter> createReporter( std::string const& reporterName, Ptr<Config> const& config ) { |
Phil Nash | 34fa25e | 2015-07-28 18:55:11 +0100 | [diff] [blame] | 25 | Ptr<IStreamingReporter> reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); |
| 26 | if( !reporter ) { |
| 27 | std::ostringstream oss; |
| 28 | oss << "No reporter registered with name: '" << reporterName << "'"; |
| 29 | throw std::domain_error( oss.str() ); |
Phil Nash | 56d5c42 | 2012-08-23 20:08:50 +0100 | [diff] [blame] | 30 | } |
Phil Nash | 34fa25e | 2015-07-28 18:55:11 +0100 | [diff] [blame] | 31 | return reporter; |
| 32 | } |
Phil Nash | e917381 | 2015-11-04 18:01:28 +0000 | [diff] [blame] | 33 | |
Phil Nash | 4cb7476 | 2015-08-05 19:02:17 +0100 | [diff] [blame] | 34 | Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) { |
| 35 | std::vector<std::string> reporters = config->getReporterNames(); |
| 36 | if( reporters.empty() ) |
| 37 | reporters.push_back( "console" ); |
| 38 | |
| 39 | Ptr<IStreamingReporter> reporter; |
| 40 | for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end(); |
| 41 | it != itEnd; |
| 42 | ++it ) |
Phil Nash | e917381 | 2015-11-04 18:01:28 +0000 | [diff] [blame] | 43 | reporter = addReporter( reporter, createReporter( *it, config ) ); |
Phil Nash | 4cb7476 | 2015-08-05 19:02:17 +0100 | [diff] [blame] | 44 | return reporter; |
| 45 | } |
Phil Nash | a0de07d | 2015-09-28 01:09:06 -0700 | [diff] [blame] | 46 | Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters ) { |
Phil Nash | 368714e | 2015-08-07 08:20:56 +0100 | [diff] [blame] | 47 | IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); |
| 48 | for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); |
| 49 | it != itEnd; |
| 50 | ++it ) |
| 51 | reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); |
| 52 | return reporters; |
| 53 | } |
Phil Nash | e917381 | 2015-11-04 18:01:28 +0000 | [diff] [blame] | 54 | |
| 55 | |
Phil Nash | 34fa25e | 2015-07-28 18:55:11 +0100 | [diff] [blame] | 56 | Totals runTests( Ptr<Config> const& config ) { |
Phil Nash | f3d1f08 | 2013-07-03 19:14:59 +0100 | [diff] [blame] | 57 | |
Phil Nash | a0de07d | 2015-09-28 01:09:06 -0700 | [diff] [blame] | 58 | Ptr<IConfig const> iconfig = config.get(); |
Phil Nash | e917381 | 2015-11-04 18:01:28 +0000 | [diff] [blame] | 59 | |
Phil Nash | 34fa25e | 2015-07-28 18:55:11 +0100 | [diff] [blame] | 60 | Ptr<IStreamingReporter> reporter = makeReporter( config ); |
Phil Nash | a0de07d | 2015-09-28 01:09:06 -0700 | [diff] [blame] | 61 | reporter = addListeners( iconfig, reporter ); |
Phil Nash | e917381 | 2015-11-04 18:01:28 +0000 | [diff] [blame] | 62 | |
Phil Nash | a0de07d | 2015-09-28 01:09:06 -0700 | [diff] [blame] | 63 | RunContext context( iconfig, reporter ); |
Phil Nash | 34fa25e | 2015-07-28 18:55:11 +0100 | [diff] [blame] | 64 | |
| 65 | Totals totals; |
| 66 | |
| 67 | context.testGroupStarting( config->name(), 1, 1 ); |
| 68 | |
| 69 | TestSpec testSpec = config->testSpec(); |
| 70 | if( !testSpec.hasFilters() ) |
| 71 | testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests |
| 72 | |
Phil Nash | a0de07d | 2015-09-28 01:09:06 -0700 | [diff] [blame] | 73 | std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig ); |
Phil Nash | c06e190 | 2015-08-04 23:11:56 +0100 | [diff] [blame] | 74 | for( std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); |
Phil Nash | 34fa25e | 2015-07-28 18:55:11 +0100 | [diff] [blame] | 75 | it != itEnd; |
| 76 | ++it ) { |
Phil Nash | a0de07d | 2015-09-28 01:09:06 -0700 | [diff] [blame] | 77 | if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) |
Phil Nash | 34fa25e | 2015-07-28 18:55:11 +0100 | [diff] [blame] | 78 | totals += context.runTest( *it ); |
Phil Nash | c06e190 | 2015-08-04 23:11:56 +0100 | [diff] [blame] | 79 | else |
| 80 | reporter->skipTest( *it ); |
Phil Nash | 34fa25e | 2015-07-28 18:55:11 +0100 | [diff] [blame] | 81 | } |
Phil Nash | 34fa25e | 2015-07-28 18:55:11 +0100 | [diff] [blame] | 82 | |
Phil Nash | a0de07d | 2015-09-28 01:09:06 -0700 | [diff] [blame] | 83 | context.testGroupEnded( iconfig->name(), totals, 1, 1 ); |
Phil Nash | 34fa25e | 2015-07-28 18:55:11 +0100 | [diff] [blame] | 84 | return totals; |
| 85 | } |
Phil Nash | e917381 | 2015-11-04 18:01:28 +0000 | [diff] [blame] | 86 | |
Phil Nash | c06e190 | 2015-08-04 23:11:56 +0100 | [diff] [blame] | 87 | void applyFilenamesAsTags( IConfig const& config ) { |
| 88 | std::vector<TestCase> const& tests = getAllTestCasesSorted( config ); |
Phil Nash | 088c5bc | 2015-07-02 08:20:18 +0100 | [diff] [blame] | 89 | for(std::size_t i = 0; i < tests.size(); ++i ) { |
| 90 | TestCase& test = const_cast<TestCase&>( tests[i] ); |
| 91 | std::set<std::string> tags = test.tags; |
Phil Nash | e917381 | 2015-11-04 18:01:28 +0000 | [diff] [blame] | 92 | |
Phil Nash | 088c5bc | 2015-07-02 08:20:18 +0100 | [diff] [blame] | 93 | std::string filename = test.lineInfo.file; |
Phil Nash | 62e517f | 2015-07-03 18:07:13 +0100 | [diff] [blame] | 94 | std::string::size_type lastSlash = filename.find_last_of( "\\/" ); |
Phil Nash | 088c5bc | 2015-07-02 08:20:18 +0100 | [diff] [blame] | 95 | if( lastSlash != std::string::npos ) |
| 96 | filename = filename.substr( lastSlash+1 ); |
| 97 | |
| 98 | std::string::size_type lastDot = filename.find_last_of( "." ); |
| 99 | if( lastDot != std::string::npos ) |
| 100 | filename = filename.substr( 0, lastDot ); |
Phil Nash | e917381 | 2015-11-04 18:01:28 +0000 | [diff] [blame] | 101 | |
Phil Nash | 02e1966 | 2015-07-06 18:46:50 +0100 | [diff] [blame] | 102 | tags.insert( "#" + filename ); |
Phil Nash | 088c5bc | 2015-07-02 08:20:18 +0100 | [diff] [blame] | 103 | setTags( test, tags ); |
| 104 | } |
| 105 | } |
Phil Nash | 56d5c42 | 2012-08-23 20:08:50 +0100 | [diff] [blame] | 106 | |
Phil Nash | 12fe67c | 2014-10-03 08:15:27 +0100 | [diff] [blame] | 107 | class Session : NonCopyable { |
Phil Nash | c1196b6 | 2013-06-05 18:48:18 +0100 | [diff] [blame] | 108 | static bool alreadyInstantiated; |
Phil Nash | f3d1f08 | 2013-07-03 19:14:59 +0100 | [diff] [blame] | 109 | |
Phil Nash | c1196b6 | 2013-06-05 18:48:18 +0100 | [diff] [blame] | 110 | public: |
Phil Nash | f3d1f08 | 2013-07-03 19:14:59 +0100 | [diff] [blame] | 111 | |
Phil Nash | a7e657f | 2013-06-06 18:51:24 +0100 | [diff] [blame] | 112 | struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; |
| 113 | |
| 114 | Session() |
Phil Nash | 8055764 | 2013-06-07 18:41:22 +0100 | [diff] [blame] | 115 | : m_cli( makeCommandLineParser() ) { |
Phil Nash | c1196b6 | 2013-06-05 18:48:18 +0100 | [diff] [blame] | 116 | if( alreadyInstantiated ) { |
| 117 | std::string msg = "Only one instance of Catch::Session can ever be used"; |
Phil Nash | 383d7c0 | 2014-10-02 19:08:19 +0100 | [diff] [blame] | 118 | Catch::cerr() << msg << std::endl; |
Phil Nash | c1196b6 | 2013-06-05 18:48:18 +0100 | [diff] [blame] | 119 | throw std::logic_error( msg ); |
| 120 | } |
| 121 | alreadyInstantiated = true; |
Phil Nash | 1b47e11 | 2013-06-04 22:49:14 +0100 | [diff] [blame] | 122 | } |
Phil Nash | c1196b6 | 2013-06-05 18:48:18 +0100 | [diff] [blame] | 123 | ~Session() { |
| 124 | Catch::cleanUp(); |
| 125 | } |
Phil Nash | f3d1f08 | 2013-07-03 19:14:59 +0100 | [diff] [blame] | 126 | |
Phil Nash | e035e28 | 2013-06-06 18:56:43 +0100 | [diff] [blame] | 127 | void showHelp( std::string const& processName ) { |
Kevin Ushey | e04dc51 | 2017-03-16 11:17:45 -0700 | [diff] [blame^] | 128 | Catch::cout() << "\nCatch v" << libraryVersion() << "\n"; |
Phil Nash | a7e657f | 2013-06-06 18:51:24 +0100 | [diff] [blame] | 129 | |
Phil Nash | 383d7c0 | 2014-10-02 19:08:19 +0100 | [diff] [blame] | 130 | m_cli.usage( Catch::cout(), processName ); |
| 131 | Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; |
Phil Nash | e035e28 | 2013-06-06 18:56:43 +0100 | [diff] [blame] | 132 | } |
Phil Nash | f3d1f08 | 2013-07-03 19:14:59 +0100 | [diff] [blame] | 133 | |
Phil Nash | 1c47fe0 | 2016-04-23 13:21:29 +0100 | [diff] [blame] | 134 | int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { |
Phil Nash | a7e657f | 2013-06-06 18:51:24 +0100 | [diff] [blame] | 135 | try { |
Phil Nash | 886d9d3 | 2013-12-20 19:06:02 +0000 | [diff] [blame] | 136 | m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); |
Phil Nash | 1c47fe0 | 2016-04-23 13:21:29 +0100 | [diff] [blame] | 137 | m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData ); |
Phil Nash | 8055764 | 2013-06-07 18:41:22 +0100 | [diff] [blame] | 138 | if( m_configData.showHelp ) |
| 139 | showHelp( m_configData.processName ); |
| 140 | m_config.reset(); |
Phil Nash | a7e657f | 2013-06-06 18:51:24 +0100 | [diff] [blame] | 141 | } |
| 142 | catch( std::exception& ex ) { |
Phil Nash | 1870ca8 | 2013-08-16 18:57:57 +0100 | [diff] [blame] | 143 | { |
| 144 | Colour colourGuard( Colour::Red ); |
Phil Nash | 21f7ef6 | 2015-06-29 18:05:23 +0100 | [diff] [blame] | 145 | Catch::cerr() |
| 146 | << "\nError(s) in input:\n" |
| 147 | << Text( ex.what(), TextAttributes().setIndent(2) ) |
| 148 | << "\n\n"; |
Phil Nash | 1870ca8 | 2013-08-16 18:57:57 +0100 | [diff] [blame] | 149 | } |
Phil Nash | 383d7c0 | 2014-10-02 19:08:19 +0100 | [diff] [blame] | 150 | m_cli.usage( Catch::cout(), m_configData.processName ); |
Phil Nash | a7e657f | 2013-06-06 18:51:24 +0100 | [diff] [blame] | 151 | return (std::numeric_limits<int>::max)(); |
| 152 | } |
| 153 | return 0; |
| 154 | } |
| 155 | |
| 156 | void useConfigData( ConfigData const& _configData ) { |
Phil Nash | 8055764 | 2013-06-07 18:41:22 +0100 | [diff] [blame] | 157 | m_configData = _configData; |
| 158 | m_config.reset(); |
Phil Nash | a7e657f | 2013-06-06 18:51:24 +0100 | [diff] [blame] | 159 | } |
| 160 | |
Phil Nash | 1c47fe0 | 2016-04-23 13:21:29 +0100 | [diff] [blame] | 161 | int run( int argc, char const* const* const argv ) { |
Phil Nash | a7e657f | 2013-06-06 18:51:24 +0100 | [diff] [blame] | 162 | |
| 163 | int returnCode = applyCommandLine( argc, argv ); |
| 164 | if( returnCode == 0 ) |
| 165 | returnCode = run(); |
| 166 | return returnCode; |
| 167 | } |
| 168 | |
| 169 | int run() { |
Phil Nash | 8055764 | 2013-06-07 18:41:22 +0100 | [diff] [blame] | 170 | if( m_configData.showHelp ) |
Phil Nash | a7e657f | 2013-06-06 18:51:24 +0100 | [diff] [blame] | 171 | return 0; |
| 172 | |
Phil Nash | c1196b6 | 2013-06-05 18:48:18 +0100 | [diff] [blame] | 173 | try |
| 174 | { |
Phil Nash | 8055764 | 2013-06-07 18:41:22 +0100 | [diff] [blame] | 175 | config(); // Force config to be constructed |
Phil Nash | e917381 | 2015-11-04 18:01:28 +0000 | [diff] [blame] | 176 | |
Phil Nash | d87e551 | 2015-07-02 23:02:35 +0100 | [diff] [blame] | 177 | seedRng( *m_config ); |
Phil Nash | fa0122b | 2014-09-15 18:39:31 +0100 | [diff] [blame] | 178 | |
Phil Nash | c06e190 | 2015-08-04 23:11:56 +0100 | [diff] [blame] | 179 | if( m_configData.filenamesAsTags ) |
| 180 | applyFilenamesAsTags( *m_config ); |
Phil Nash | e917381 | 2015-11-04 18:01:28 +0000 | [diff] [blame] | 181 | |
Phil Nash | c1196b6 | 2013-06-05 18:48:18 +0100 | [diff] [blame] | 182 | // Handle list request |
Phil Nash | 8055764 | 2013-06-07 18:41:22 +0100 | [diff] [blame] | 183 | if( Option<std::size_t> listed = list( config() ) ) |
Phil Nash | f438e04 | 2013-06-06 22:54:42 +0100 | [diff] [blame] | 184 | return static_cast<int>( *listed ); |
Phil Nash | 4c73aa5 | 2012-06-08 08:22:56 +0100 | [diff] [blame] | 185 | |
Phil Nash | 34fa25e | 2015-07-28 18:55:11 +0100 | [diff] [blame] | 186 | return static_cast<int>( runTests( m_config ).assertions.failed ); |
Phil Nash | c1196b6 | 2013-06-05 18:48:18 +0100 | [diff] [blame] | 187 | } |
| 188 | catch( std::exception& ex ) { |
Phil Nash | 383d7c0 | 2014-10-02 19:08:19 +0100 | [diff] [blame] | 189 | Catch::cerr() << ex.what() << std::endl; |
Phil Nash | c1196b6 | 2013-06-05 18:48:18 +0100 | [diff] [blame] | 190 | return (std::numeric_limits<int>::max)(); |
Phil Nash | 4c73aa5 | 2012-06-08 08:22:56 +0100 | [diff] [blame] | 191 | } |
Phil Nash | 4c73aa5 | 2012-06-08 08:22:56 +0100 | [diff] [blame] | 192 | } |
Phil Nash | f3d1f08 | 2013-07-03 19:14:59 +0100 | [diff] [blame] | 193 | |
Phil Nash | 8055764 | 2013-06-07 18:41:22 +0100 | [diff] [blame] | 194 | Clara::CommandLine<ConfigData> const& cli() const { |
| 195 | return m_cli; |
| 196 | } |
| 197 | std::vector<Clara::Parser::Token> const& unusedTokens() const { |
| 198 | return m_unusedTokens; |
| 199 | } |
| 200 | ConfigData& configData() { |
| 201 | return m_configData; |
| 202 | } |
| 203 | Config& config() { |
| 204 | if( !m_config ) |
| 205 | m_config = new Config( m_configData ); |
| 206 | return *m_config; |
| 207 | } |
Phil Nash | f3d1f08 | 2013-07-03 19:14:59 +0100 | [diff] [blame] | 208 | private: |
Phil Nash | 8055764 | 2013-06-07 18:41:22 +0100 | [diff] [blame] | 209 | Clara::CommandLine<ConfigData> m_cli; |
| 210 | std::vector<Clara::Parser::Token> m_unusedTokens; |
| 211 | ConfigData m_configData; |
| 212 | Ptr<Config> m_config; |
Phil Nash | c1196b6 | 2013-06-05 18:48:18 +0100 | [diff] [blame] | 213 | }; |
Phil Nash | a7e657f | 2013-06-06 18:51:24 +0100 | [diff] [blame] | 214 | |
Phil Nash | c1196b6 | 2013-06-05 18:48:18 +0100 | [diff] [blame] | 215 | bool Session::alreadyInstantiated = false; |
Phil Nash | f3d1f08 | 2013-07-03 19:14:59 +0100 | [diff] [blame] | 216 | |
Phil Nash | d802600 | 2010-11-09 23:24:00 +0000 | [diff] [blame] | 217 | } // end namespace Catch |
| 218 | |
Phil Nash | 73acd94 | 2011-02-16 19:02:09 +0000 | [diff] [blame] | 219 | #endif // TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED |