catch_commandline.cpp 11 KB

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