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 <fstream> 14 #include <ctime> 15 16 namespace Catch { 17 makeCommandLineParser(ConfigData & config)18 clara::Parser makeCommandLineParser( ConfigData& config ) { 19 20 using namespace clara; 21 22 auto const setWarning = [&]( std::string const& warning ) { 23 auto warningSet = [&]() { 24 if( warning == "NoAssertions" ) 25 return WarnAbout::NoAssertions; 26 27 if ( warning == "NoTests" ) 28 return WarnAbout::NoTests; 29 30 return WarnAbout::Nothing; 31 }(); 32 33 if (warningSet == WarnAbout::Nothing) 34 return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); 35 config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet ); 36 return ParserResult::ok( ParseResultType::Matched ); 37 }; 38 auto const loadTestNamesFromFile = [&]( std::string const& filename ) { 39 std::ifstream f( filename.c_str() ); 40 if( !f.is_open() ) 41 return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); 42 43 std::string line; 44 while( std::getline( f, line ) ) { 45 line = trim(line); 46 if( !line.empty() && !startsWith( line, '#' ) ) { 47 if( !startsWith( line, '"' ) ) 48 line = '"' + line + '"'; 49 config.testsOrTags.push_back( line + ',' ); 50 } 51 } 52 return ParserResult::ok( ParseResultType::Matched ); 53 }; 54 auto const setTestOrder = [&]( std::string const& order ) { 55 if( startsWith( "declared", order ) ) 56 config.runOrder = RunTests::InDeclarationOrder; 57 else if( startsWith( "lexical", order ) ) 58 config.runOrder = RunTests::InLexicographicalOrder; 59 else if( startsWith( "random", order ) ) 60 config.runOrder = RunTests::InRandomOrder; 61 else 62 return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); 63 return ParserResult::ok( ParseResultType::Matched ); 64 }; 65 auto const setRngSeed = [&]( std::string const& seed ) { 66 if( seed != "time" ) 67 return clara::detail::convertInto( seed, config.rngSeed ); 68 config.rngSeed = static_cast<unsigned int>( std::time(nullptr) ); 69 return ParserResult::ok( ParseResultType::Matched ); 70 }; 71 auto const setColourUsage = [&]( std::string const& useColour ) { 72 auto mode = toLower( useColour ); 73 74 if( mode == "yes" ) 75 config.useColour = UseColour::Yes; 76 else if( mode == "no" ) 77 config.useColour = UseColour::No; 78 else if( mode == "auto" ) 79 config.useColour = UseColour::Auto; 80 else 81 return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); 82 return ParserResult::ok( ParseResultType::Matched ); 83 }; 84 auto const setWaitForKeypress = [&]( std::string const& keypress ) { 85 auto keypressLc = toLower( keypress ); 86 if( keypressLc == "start" ) 87 config.waitForKeypress = WaitForKeypress::BeforeStart; 88 else if( keypressLc == "exit" ) 89 config.waitForKeypress = WaitForKeypress::BeforeExit; 90 else if( keypressLc == "both" ) 91 config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; 92 else 93 return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); 94 return ParserResult::ok( ParseResultType::Matched ); 95 }; 96 auto const setVerbosity = [&]( std::string const& verbosity ) { 97 auto lcVerbosity = toLower( verbosity ); 98 if( lcVerbosity == "quiet" ) 99 config.verbosity = Verbosity::Quiet; 100 else if( lcVerbosity == "normal" ) 101 config.verbosity = Verbosity::Normal; 102 else if( lcVerbosity == "high" ) 103 config.verbosity = Verbosity::High; 104 else 105 return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); 106 return ParserResult::ok( ParseResultType::Matched ); 107 }; 108 109 auto cli 110 = ExeName( config.processName ) 111 | Help( config.showHelp ) 112 | Opt( config.listTests ) 113 ["-l"]["--list-tests"] 114 ( "list all/matching test cases" ) 115 | Opt( config.listTags ) 116 ["-t"]["--list-tags"] 117 ( "list all/matching tags" ) 118 | Opt( config.showSuccessfulTests ) 119 ["-s"]["--success"] 120 ( "include successful tests in output" ) 121 | Opt( config.shouldDebugBreak ) 122 ["-b"]["--break"] 123 ( "break into debugger on failure" ) 124 | Opt( config.noThrow ) 125 ["-e"]["--nothrow"] 126 ( "skip exception tests" ) 127 | Opt( config.showInvisibles ) 128 ["-i"]["--invisibles"] 129 ( "show invisibles (tabs, newlines)" ) 130 | Opt( config.outputFilename, "filename" ) 131 ["-o"]["--out"] 132 ( "output filename" ) 133 | Opt( config.reporterNames, "name" ) 134 ["-r"]["--reporter"] 135 ( "reporter to use (defaults to console)" ) 136 | Opt( config.name, "name" ) 137 ["-n"]["--name"] 138 ( "suite name" ) 139 | Opt( [&]( bool ){ config.abortAfter = 1; } ) 140 ["-a"]["--abort"] 141 ( "abort at first failure" ) 142 | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) 143 ["-x"]["--abortx"] 144 ( "abort after x failures" ) 145 | Opt( setWarning, "warning name" ) 146 ["-w"]["--warn"] 147 ( "enable warnings" ) 148 | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) 149 ["-d"]["--durations"] 150 ( "show test durations" ) 151 | Opt( loadTestNamesFromFile, "filename" ) 152 ["-f"]["--input-file"] 153 ( "load test names to run from a file" ) 154 | Opt( config.filenamesAsTags ) 155 ["-#"]["--filenames-as-tags"] 156 ( "adds a tag for the filename" ) 157 | Opt( config.sectionsToRun, "section name" ) 158 ["-c"]["--section"] 159 ( "specify section to run" ) 160 | Opt( setVerbosity, "quiet|normal|high" ) 161 ["-v"]["--verbosity"] 162 ( "set output verbosity" ) 163 | Opt( config.listTestNamesOnly ) 164 ["--list-test-names-only"] 165 ( "list all/matching test cases names only" ) 166 | Opt( config.listReporters ) 167 ["--list-reporters"] 168 ( "list all reporters" ) 169 | Opt( setTestOrder, "decl|lex|rand" ) 170 ["--order"] 171 ( "test case order (defaults to decl)" ) 172 | Opt( setRngSeed, "'time'|number" ) 173 ["--rng-seed"] 174 ( "set a specific seed for random numbers" ) 175 | Opt( setColourUsage, "yes|no" ) 176 ["--use-colour"] 177 ( "should output be colourised" ) 178 | Opt( config.libIdentify ) 179 ["--libidentify"] 180 ( "report name and version according to libidentify standard" ) 181 | Opt( setWaitForKeypress, "start|exit|both" ) 182 ["--wait-for-keypress"] 183 ( "waits for a keypress before exiting" ) 184 | Opt( config.benchmarkResolutionMultiple, "multiplier" ) 185 ["--benchmark-resolution-multiple"] 186 ( "multiple of clock resolution to run benchmarks" ) 187 188 | Arg( config.testsOrTags, "test name|pattern|tags" ) 189 ( "which test or tests to use" ); 190 191 return cli; 192 } 193 194 } // end namespace Catch 195