1 /* 2 * Created by Phil on 02/11/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) 7 */ 8 9 #include "catch_commandline.h" 10 11 #include "catch_string_manip.h" 12 13 #include "catch_interfaces_registry_hub.h" 14 #include "catch_interfaces_reporter.h" 15 16 #include <fstream> 17 #include <ctime> 18 19 namespace Catch { 20 makeCommandLineParser(ConfigData & config)21 clara::Parser makeCommandLineParser( ConfigData& config ) { 22 23 using namespace clara; 24 25 auto const setWarning = [&]( std::string const& warning ) { 26 auto warningSet = [&]() { 27 if( warning == "NoAssertions" ) 28 return WarnAbout::NoAssertions; 29 30 if ( warning == "NoTests" ) 31 return WarnAbout::NoTests; 32 33 return WarnAbout::Nothing; 34 }(); 35 36 if (warningSet == WarnAbout::Nothing) 37 return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); 38 config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet ); 39 return ParserResult::ok( ParseResultType::Matched ); 40 }; 41 auto const loadTestNamesFromFile = [&]( std::string const& filename ) { 42 std::ifstream f( filename.c_str() ); 43 if( !f.is_open() ) 44 return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); 45 46 std::string line; 47 while( std::getline( f, line ) ) { 48 line = trim(line); 49 if( !line.empty() && !startsWith( line, '#' ) ) { 50 if( !startsWith( line, '"' ) ) 51 line = '"' + line + '"'; 52 config.testsOrTags.push_back( line ); 53 config.testsOrTags.emplace_back( "," ); 54 } 55 } 56 //Remove comma in the end 57 if(!config.testsOrTags.empty()) 58 config.testsOrTags.erase( config.testsOrTags.end()-1 ); 59 60 return ParserResult::ok( ParseResultType::Matched ); 61 }; 62 auto const setTestOrder = [&]( std::string const& order ) { 63 if( startsWith( "declared", order ) ) 64 config.runOrder = RunTests::InDeclarationOrder; 65 else if( startsWith( "lexical", order ) ) 66 config.runOrder = RunTests::InLexicographicalOrder; 67 else if( startsWith( "random", order ) ) 68 config.runOrder = RunTests::InRandomOrder; 69 else 70 return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); 71 return ParserResult::ok( ParseResultType::Matched ); 72 }; 73 auto const setRngSeed = [&]( std::string const& seed ) { 74 if( seed != "time" ) 75 return clara::detail::convertInto( seed, config.rngSeed ); 76 config.rngSeed = static_cast<unsigned int>( std::time(nullptr) ); 77 return ParserResult::ok( ParseResultType::Matched ); 78 }; 79 auto const setColourUsage = [&]( std::string const& useColour ) { 80 auto mode = toLower( useColour ); 81 82 if( mode == "yes" ) 83 config.useColour = UseColour::Yes; 84 else if( mode == "no" ) 85 config.useColour = UseColour::No; 86 else if( mode == "auto" ) 87 config.useColour = UseColour::Auto; 88 else 89 return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); 90 return ParserResult::ok( ParseResultType::Matched ); 91 }; 92 auto const setWaitForKeypress = [&]( std::string const& keypress ) { 93 auto keypressLc = toLower( keypress ); 94 if (keypressLc == "never") 95 config.waitForKeypress = WaitForKeypress::Never; 96 else if( keypressLc == "start" ) 97 config.waitForKeypress = WaitForKeypress::BeforeStart; 98 else if( keypressLc == "exit" ) 99 config.waitForKeypress = WaitForKeypress::BeforeExit; 100 else if( keypressLc == "both" ) 101 config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; 102 else 103 return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" ); 104 return ParserResult::ok( ParseResultType::Matched ); 105 }; 106 auto const setVerbosity = [&]( std::string const& verbosity ) { 107 auto lcVerbosity = toLower( verbosity ); 108 if( lcVerbosity == "quiet" ) 109 config.verbosity = Verbosity::Quiet; 110 else if( lcVerbosity == "normal" ) 111 config.verbosity = Verbosity::Normal; 112 else if( lcVerbosity == "high" ) 113 config.verbosity = Verbosity::High; 114 else 115 return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); 116 return ParserResult::ok( ParseResultType::Matched ); 117 }; 118 auto const setReporter = [&]( std::string const& reporter ) { 119 IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); 120 121 auto lcReporter = toLower( reporter ); 122 auto result = factories.find( lcReporter ); 123 124 if( factories.end() != result ) 125 config.reporterName = lcReporter; 126 else 127 return ParserResult::runtimeError( "Unrecognized reporter, '" + reporter + "'. Check available with --list-reporters" ); 128 return ParserResult::ok( ParseResultType::Matched ); 129 }; 130 131 auto cli 132 = ExeName( config.processName ) 133 | Help( config.showHelp ) 134 | Opt( config.listTests ) 135 ["-l"]["--list-tests"] 136 ( "list all/matching test cases" ) 137 | Opt( config.listTags ) 138 ["-t"]["--list-tags"] 139 ( "list all/matching tags" ) 140 | Opt( config.showSuccessfulTests ) 141 ["-s"]["--success"] 142 ( "include successful tests in output" ) 143 | Opt( config.shouldDebugBreak ) 144 ["-b"]["--break"] 145 ( "break into debugger on failure" ) 146 | Opt( config.noThrow ) 147 ["-e"]["--nothrow"] 148 ( "skip exception tests" ) 149 | Opt( config.showInvisibles ) 150 ["-i"]["--invisibles"] 151 ( "show invisibles (tabs, newlines)" ) 152 | Opt( config.outputFilename, "filename" ) 153 ["-o"]["--out"] 154 ( "output filename" ) 155 | Opt( setReporter, "name" ) 156 ["-r"]["--reporter"] 157 ( "reporter to use (defaults to console)" ) 158 | Opt( config.name, "name" ) 159 ["-n"]["--name"] 160 ( "suite name" ) 161 | Opt( [&]( bool ){ config.abortAfter = 1; } ) 162 ["-a"]["--abort"] 163 ( "abort at first failure" ) 164 | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) 165 ["-x"]["--abortx"] 166 ( "abort after x failures" ) 167 | Opt( setWarning, "warning name" ) 168 ["-w"]["--warn"] 169 ( "enable warnings" ) 170 | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) 171 ["-d"]["--durations"] 172 ( "show test durations" ) 173 | Opt( config.minDuration, "seconds" ) 174 ["-D"]["--min-duration"] 175 ( "show test durations for tests taking at least the given number of seconds" ) 176 | Opt( loadTestNamesFromFile, "filename" ) 177 ["-f"]["--input-file"] 178 ( "load test names to run from a file" ) 179 | Opt( config.filenamesAsTags ) 180 ["-#"]["--filenames-as-tags"] 181 ( "adds a tag for the filename" ) 182 | Opt( config.sectionsToRun, "section name" ) 183 ["-c"]["--section"] 184 ( "specify section to run" ) 185 | Opt( setVerbosity, "quiet|normal|high" ) 186 ["-v"]["--verbosity"] 187 ( "set output verbosity" ) 188 | Opt( config.listTestNamesOnly ) 189 ["--list-test-names-only"] 190 ( "list all/matching test cases names only" ) 191 | Opt( config.listReporters ) 192 ["--list-reporters"] 193 ( "list all reporters" ) 194 | Opt( setTestOrder, "decl|lex|rand" ) 195 ["--order"] 196 ( "test case order (defaults to decl)" ) 197 | Opt( setRngSeed, "'time'|number" ) 198 ["--rng-seed"] 199 ( "set a specific seed for random numbers" ) 200 | Opt( setColourUsage, "yes|no" ) 201 ["--use-colour"] 202 ( "should output be colourised" ) 203 | Opt( config.libIdentify ) 204 ["--libidentify"] 205 ( "report name and version according to libidentify standard" ) 206 | Opt( setWaitForKeypress, "never|start|exit|both" ) 207 ["--wait-for-keypress"] 208 ( "waits for a keypress before exiting" ) 209 | Opt( config.benchmarkSamples, "samples" ) 210 ["--benchmark-samples"] 211 ( "number of samples to collect (default: 100)" ) 212 | Opt( config.benchmarkResamples, "resamples" ) 213 ["--benchmark-resamples"] 214 ( "number of resamples for the bootstrap (default: 100000)" ) 215 | Opt( config.benchmarkConfidenceInterval, "confidence interval" ) 216 ["--benchmark-confidence-interval"] 217 ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" ) 218 | Opt( config.benchmarkNoAnalysis ) 219 ["--benchmark-no-analysis"] 220 ( "perform only measurements; do not perform any analysis" ) 221 | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" ) 222 ["--benchmark-warmup-time"] 223 ( "amount of time in milliseconds spent on warming up each test (default: 100)" ) 224 | Arg( config.testsOrTags, "test name|pattern|tags" ) 225 ( "which test or tests to use" ); 226 227 return cli; 228 } 229 230 } // end namespace Catch 231