blob: be51bef8d1eb0891e503e7670be30a99194c0f1e [file] [log] [blame]
Phil Nashd8026002010-11-09 23:24:00 +00001/*
Phil Nashd8026002010-11-09 23:24:00 +00002 * 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 Nashd8026002010-11-09 23:24:00 +00007 */
Phil Nashd8026002010-11-09 23:24:00 +00008#ifndef TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
9#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
10
Phil Nasha695eb92012-08-13 07:46:10 +010011#include "internal/catch_commandline.hpp"
12#include "internal/catch_list.hpp"
Phil Nash4cb74762015-08-05 19:02:17 +010013#include "internal/catch_run_context.hpp"
Phil Nashb1e7d162014-05-16 18:28:58 +010014#include "internal/catch_test_spec.hpp"
Phil Nash7673a302012-11-15 22:15:41 +000015#include "internal/catch_version.h"
Phil Nash7059c6e2013-04-19 19:08:32 +010016#include "internal/catch_text.h"
Phil Nasha695eb92012-08-13 07:46:10 +010017
Phil Nashe846e072010-12-31 22:07:47 +000018#include <fstream>
Phil Nash9d125922011-02-04 09:30:36 +000019#include <stdlib.h>
Phil Nash1e156692011-03-15 22:41:27 +000020#include <limits>
Phil Nashe846e072010-12-31 22:07:47 +000021
Phil Nashee18b8c2012-05-16 15:02:51 +010022namespace Catch {
23
Phil Nash4cb74762015-08-05 19:02:17 +010024 Ptr<IStreamingReporter> createReporter( std::string const& reporterName, Ptr<Config> const& config ) {
Phil Nash34fa25e2015-07-28 18:55:11 +010025 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 Nash56d5c422012-08-23 20:08:50 +010030 }
Phil Nash34fa25e2015-07-28 18:55:11 +010031 return reporter;
32 }
Phil Nashe9173812015-11-04 18:01:28 +000033
Phil Nash4cb74762015-08-05 19:02:17 +010034 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 Nashe9173812015-11-04 18:01:28 +000043 reporter = addReporter( reporter, createReporter( *it, config ) );
Phil Nash4cb74762015-08-05 19:02:17 +010044 return reporter;
45 }
Phil Nasha0de07d2015-09-28 01:09:06 -070046 Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters ) {
Phil Nash368714e2015-08-07 08:20:56 +010047 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 Nashe9173812015-11-04 18:01:28 +000054
55
Phil Nash34fa25e2015-07-28 18:55:11 +010056 Totals runTests( Ptr<Config> const& config ) {
Phil Nashf3d1f082013-07-03 19:14:59 +010057
Phil Nasha0de07d2015-09-28 01:09:06 -070058 Ptr<IConfig const> iconfig = config.get();
Phil Nashe9173812015-11-04 18:01:28 +000059
Phil Nash34fa25e2015-07-28 18:55:11 +010060 Ptr<IStreamingReporter> reporter = makeReporter( config );
Phil Nasha0de07d2015-09-28 01:09:06 -070061 reporter = addListeners( iconfig, reporter );
Phil Nashe9173812015-11-04 18:01:28 +000062
Phil Nasha0de07d2015-09-28 01:09:06 -070063 RunContext context( iconfig, reporter );
Phil Nash34fa25e2015-07-28 18:55:11 +010064
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 Nasha0de07d2015-09-28 01:09:06 -070073 std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig );
Phil Nashc06e1902015-08-04 23:11:56 +010074 for( std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end();
Phil Nash34fa25e2015-07-28 18:55:11 +010075 it != itEnd;
76 ++it ) {
Phil Nasha0de07d2015-09-28 01:09:06 -070077 if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) )
Phil Nash34fa25e2015-07-28 18:55:11 +010078 totals += context.runTest( *it );
Phil Nashc06e1902015-08-04 23:11:56 +010079 else
80 reporter->skipTest( *it );
Phil Nash34fa25e2015-07-28 18:55:11 +010081 }
Phil Nash34fa25e2015-07-28 18:55:11 +010082
Phil Nasha0de07d2015-09-28 01:09:06 -070083 context.testGroupEnded( iconfig->name(), totals, 1, 1 );
Phil Nash34fa25e2015-07-28 18:55:11 +010084 return totals;
85 }
Phil Nashe9173812015-11-04 18:01:28 +000086
Phil Nashc06e1902015-08-04 23:11:56 +010087 void applyFilenamesAsTags( IConfig const& config ) {
88 std::vector<TestCase> const& tests = getAllTestCasesSorted( config );
Phil Nash088c5bc2015-07-02 08:20:18 +010089 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 Nashe9173812015-11-04 18:01:28 +000092
Phil Nash088c5bc2015-07-02 08:20:18 +010093 std::string filename = test.lineInfo.file;
Phil Nash62e517f2015-07-03 18:07:13 +010094 std::string::size_type lastSlash = filename.find_last_of( "\\/" );
Phil Nash088c5bc2015-07-02 08:20:18 +010095 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 Nashe9173812015-11-04 18:01:28 +0000101
Phil Nash02e19662015-07-06 18:46:50 +0100102 tags.insert( "#" + filename );
Phil Nash088c5bc2015-07-02 08:20:18 +0100103 setTags( test, tags );
104 }
105 }
Phil Nash56d5c422012-08-23 20:08:50 +0100106
Phil Nash12fe67c2014-10-03 08:15:27 +0100107 class Session : NonCopyable {
Phil Nashc1196b62013-06-05 18:48:18 +0100108 static bool alreadyInstantiated;
Phil Nashf3d1f082013-07-03 19:14:59 +0100109
Phil Nashc1196b62013-06-05 18:48:18 +0100110 public:
Phil Nashf3d1f082013-07-03 19:14:59 +0100111
Phil Nasha7e657f2013-06-06 18:51:24 +0100112 struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; };
113
114 Session()
Phil Nash80557642013-06-07 18:41:22 +0100115 : m_cli( makeCommandLineParser() ) {
Phil Nashc1196b62013-06-05 18:48:18 +0100116 if( alreadyInstantiated ) {
117 std::string msg = "Only one instance of Catch::Session can ever be used";
Phil Nash383d7c02014-10-02 19:08:19 +0100118 Catch::cerr() << msg << std::endl;
Phil Nashc1196b62013-06-05 18:48:18 +0100119 throw std::logic_error( msg );
120 }
121 alreadyInstantiated = true;
Phil Nash1b47e112013-06-04 22:49:14 +0100122 }
Phil Nashc1196b62013-06-05 18:48:18 +0100123 ~Session() {
124 Catch::cleanUp();
125 }
Phil Nashf3d1f082013-07-03 19:14:59 +0100126
Phil Nashe035e282013-06-06 18:56:43 +0100127 void showHelp( std::string const& processName ) {
Kevin Usheye04dc512017-03-16 11:17:45 -0700128 Catch::cout() << "\nCatch v" << libraryVersion() << "\n";
Phil Nasha7e657f2013-06-06 18:51:24 +0100129
Phil Nash383d7c02014-10-02 19:08:19 +0100130 m_cli.usage( Catch::cout(), processName );
131 Catch::cout() << "For more detail usage please see the project docs\n" << std::endl;
Phil Nashe035e282013-06-06 18:56:43 +0100132 }
Phil Nashf3d1f082013-07-03 19:14:59 +0100133
Phil Nash1c47fe02016-04-23 13:21:29 +0100134 int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
Phil Nasha7e657f2013-06-06 18:51:24 +0100135 try {
Phil Nash886d9d32013-12-20 19:06:02 +0000136 m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
Phil Nash1c47fe02016-04-23 13:21:29 +0100137 m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData );
Phil Nash80557642013-06-07 18:41:22 +0100138 if( m_configData.showHelp )
139 showHelp( m_configData.processName );
140 m_config.reset();
Phil Nasha7e657f2013-06-06 18:51:24 +0100141 }
142 catch( std::exception& ex ) {
Phil Nash1870ca82013-08-16 18:57:57 +0100143 {
144 Colour colourGuard( Colour::Red );
Phil Nash21f7ef62015-06-29 18:05:23 +0100145 Catch::cerr()
146 << "\nError(s) in input:\n"
147 << Text( ex.what(), TextAttributes().setIndent(2) )
148 << "\n\n";
Phil Nash1870ca82013-08-16 18:57:57 +0100149 }
Phil Nash383d7c02014-10-02 19:08:19 +0100150 m_cli.usage( Catch::cout(), m_configData.processName );
Phil Nasha7e657f2013-06-06 18:51:24 +0100151 return (std::numeric_limits<int>::max)();
152 }
153 return 0;
154 }
155
156 void useConfigData( ConfigData const& _configData ) {
Phil Nash80557642013-06-07 18:41:22 +0100157 m_configData = _configData;
158 m_config.reset();
Phil Nasha7e657f2013-06-06 18:51:24 +0100159 }
160
Phil Nash1c47fe02016-04-23 13:21:29 +0100161 int run( int argc, char const* const* const argv ) {
Phil Nasha7e657f2013-06-06 18:51:24 +0100162
163 int returnCode = applyCommandLine( argc, argv );
164 if( returnCode == 0 )
165 returnCode = run();
166 return returnCode;
167 }
168
169 int run() {
Phil Nash80557642013-06-07 18:41:22 +0100170 if( m_configData.showHelp )
Phil Nasha7e657f2013-06-06 18:51:24 +0100171 return 0;
172
Phil Nashc1196b62013-06-05 18:48:18 +0100173 try
174 {
Phil Nash80557642013-06-07 18:41:22 +0100175 config(); // Force config to be constructed
Phil Nashe9173812015-11-04 18:01:28 +0000176
Phil Nashd87e5512015-07-02 23:02:35 +0100177 seedRng( *m_config );
Phil Nashfa0122b2014-09-15 18:39:31 +0100178
Phil Nashc06e1902015-08-04 23:11:56 +0100179 if( m_configData.filenamesAsTags )
180 applyFilenamesAsTags( *m_config );
Phil Nashe9173812015-11-04 18:01:28 +0000181
Phil Nashc1196b62013-06-05 18:48:18 +0100182 // Handle list request
Phil Nash80557642013-06-07 18:41:22 +0100183 if( Option<std::size_t> listed = list( config() ) )
Phil Nashf438e042013-06-06 22:54:42 +0100184 return static_cast<int>( *listed );
Phil Nash4c73aa52012-06-08 08:22:56 +0100185
Phil Nash34fa25e2015-07-28 18:55:11 +0100186 return static_cast<int>( runTests( m_config ).assertions.failed );
Phil Nashc1196b62013-06-05 18:48:18 +0100187 }
188 catch( std::exception& ex ) {
Phil Nash383d7c02014-10-02 19:08:19 +0100189 Catch::cerr() << ex.what() << std::endl;
Phil Nashc1196b62013-06-05 18:48:18 +0100190 return (std::numeric_limits<int>::max)();
Phil Nash4c73aa52012-06-08 08:22:56 +0100191 }
Phil Nash4c73aa52012-06-08 08:22:56 +0100192 }
Phil Nashf3d1f082013-07-03 19:14:59 +0100193
Phil Nash80557642013-06-07 18:41:22 +0100194 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 Nashf3d1f082013-07-03 19:14:59 +0100208 private:
Phil Nash80557642013-06-07 18:41:22 +0100209 Clara::CommandLine<ConfigData> m_cli;
210 std::vector<Clara::Parser::Token> m_unusedTokens;
211 ConfigData m_configData;
212 Ptr<Config> m_config;
Phil Nashc1196b62013-06-05 18:48:18 +0100213 };
Phil Nasha7e657f2013-06-06 18:51:24 +0100214
Phil Nashc1196b62013-06-05 18:48:18 +0100215 bool Session::alreadyInstantiated = false;
Phil Nashf3d1f082013-07-03 19:14:59 +0100216
Phil Nashd8026002010-11-09 23:24:00 +0000217} // end namespace Catch
218
Phil Nash73acd942011-02-16 19:02:09 +0000219#endif // TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED