Home | History | Annotate | Download | only in internal
      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 
     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                     }
     54                 }
     55                 return ParserResult::ok( ParseResultType::Matched );
     56             };
     57         auto const setTestOrder = [&]( std::string const& order ) {
     58                 if( startsWith( "declared", order ) )
     59                     config.runOrder = RunTests::InDeclarationOrder;
     60                 else if( startsWith( "lexical", order ) )
     61                     config.runOrder = RunTests::InLexicographicalOrder;
     62                 else if( startsWith( "random", order ) )
     63                     config.runOrder = RunTests::InRandomOrder;
     64                 else
     65                     return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" );
     66                 return ParserResult::ok( ParseResultType::Matched );
     67             };
     68         auto const setRngSeed = [&]( std::string const& seed ) {
     69                 if( seed != "time" )
     70                     return clara::detail::convertInto( seed, config.rngSeed );
     71                 config.rngSeed = static_cast<unsigned int>( std::time(nullptr) );
     72                 return ParserResult::ok( ParseResultType::Matched );
     73             };
     74         auto const setColourUsage = [&]( std::string const& useColour ) {
     75                     auto mode = toLower( useColour );
     76 
     77                     if( mode == "yes" )
     78                         config.useColour = UseColour::Yes;
     79                     else if( mode == "no" )
     80                         config.useColour = UseColour::No;
     81                     else if( mode == "auto" )
     82                         config.useColour = UseColour::Auto;
     83                     else
     84                         return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" );
     85                 return ParserResult::ok( ParseResultType::Matched );
     86             };
     87         auto const setWaitForKeypress = [&]( std::string const& keypress ) {
     88                 auto keypressLc = toLower( keypress );
     89                 if( keypressLc == "start" )
     90                     config.waitForKeypress = WaitForKeypress::BeforeStart;
     91                 else if( keypressLc == "exit" )
     92                     config.waitForKeypress = WaitForKeypress::BeforeExit;
     93                 else if( keypressLc == "both" )
     94                     config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
     95                 else
     96                     return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" );
     97             return ParserResult::ok( ParseResultType::Matched );
     98             };
     99         auto const setVerbosity = [&]( std::string const& verbosity ) {
    100             auto lcVerbosity = toLower( verbosity );
    101             if( lcVerbosity == "quiet" )
    102                 config.verbosity = Verbosity::Quiet;
    103             else if( lcVerbosity == "normal" )
    104                 config.verbosity = Verbosity::Normal;
    105             else if( lcVerbosity == "high" )
    106                 config.verbosity = Verbosity::High;
    107             else
    108                 return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" );
    109             return ParserResult::ok( ParseResultType::Matched );
    110         };
    111         auto const setReporter = [&]( std::string const& reporter ) {
    112             IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
    113 
    114             auto lcReporter = toLower( reporter );
    115             auto result = factories.find( lcReporter );
    116 
    117             if( factories.end() != result )
    118                 config.reporterName = lcReporter;
    119             else
    120                 return ParserResult::runtimeError( "Unrecognized reporter, '" + reporter + "'. Check available with --list-reporters" );
    121             return ParserResult::ok( ParseResultType::Matched );
    122         };
    123 
    124         auto cli
    125             = ExeName( config.processName )
    126             | Help( config.showHelp )
    127             | Opt( config.listTests )
    128                 ["-l"]["--list-tests"]
    129                 ( "list all/matching test cases" )
    130             | Opt( config.listTags )
    131                 ["-t"]["--list-tags"]
    132                 ( "list all/matching tags" )
    133             | Opt( config.showSuccessfulTests )
    134                 ["-s"]["--success"]
    135                 ( "include successful tests in output" )
    136             | Opt( config.shouldDebugBreak )
    137                 ["-b"]["--break"]
    138                 ( "break into debugger on failure" )
    139             | Opt( config.noThrow )
    140                 ["-e"]["--nothrow"]
    141                 ( "skip exception tests" )
    142             | Opt( config.showInvisibles )
    143                 ["-i"]["--invisibles"]
    144                 ( "show invisibles (tabs, newlines)" )
    145             | Opt( config.outputFilename, "filename" )
    146                 ["-o"]["--out"]
    147                 ( "output filename" )
    148             | Opt( setReporter, "name" )
    149                 ["-r"]["--reporter"]
    150                 ( "reporter to use (defaults to console)" )
    151             | Opt( config.name, "name" )
    152                 ["-n"]["--name"]
    153                 ( "suite name" )
    154             | Opt( [&]( bool ){ config.abortAfter = 1; } )
    155                 ["-a"]["--abort"]
    156                 ( "abort at first failure" )
    157             | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" )
    158                 ["-x"]["--abortx"]
    159                 ( "abort after x failures" )
    160             | Opt( setWarning, "warning name" )
    161                 ["-w"]["--warn"]
    162                 ( "enable warnings" )
    163             | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
    164                 ["-d"]["--durations"]
    165                 ( "show test durations" )
    166             | Opt( loadTestNamesFromFile, "filename" )
    167                 ["-f"]["--input-file"]
    168                 ( "load test names to run from a file" )
    169             | Opt( config.filenamesAsTags )
    170                 ["-#"]["--filenames-as-tags"]
    171                 ( "adds a tag for the filename" )
    172             | Opt( config.sectionsToRun, "section name" )
    173                 ["-c"]["--section"]
    174                 ( "specify section to run" )
    175             | Opt( setVerbosity, "quiet|normal|high" )
    176                 ["-v"]["--verbosity"]
    177                 ( "set output verbosity" )
    178             | Opt( config.listTestNamesOnly )
    179                 ["--list-test-names-only"]
    180                 ( "list all/matching test cases names only" )
    181             | Opt( config.listReporters )
    182                 ["--list-reporters"]
    183                 ( "list all reporters" )
    184             | Opt( setTestOrder, "decl|lex|rand" )
    185                 ["--order"]
    186                 ( "test case order (defaults to decl)" )
    187             | Opt( setRngSeed, "'time'|number" )
    188                 ["--rng-seed"]
    189                 ( "set a specific seed for random numbers" )
    190             | Opt( setColourUsage, "yes|no" )
    191                 ["--use-colour"]
    192                 ( "should output be colourised" )
    193             | Opt( config.libIdentify )
    194                 ["--libidentify"]
    195                 ( "report name and version according to libidentify standard" )
    196             | Opt( setWaitForKeypress, "start|exit|both" )
    197                 ["--wait-for-keypress"]
    198                 ( "waits for a keypress before exiting" )
    199             | Opt( config.benchmarkResolutionMultiple, "multiplier" )
    200                 ["--benchmark-resolution-multiple"]
    201                 ( "multiple of clock resolution to run benchmarks" )
    202 
    203             | Arg( config.testsOrTags, "test name|pattern|tags" )
    204                 ( "which test or tests to use" );
    205 
    206         return cli;
    207     }
    208 
    209 } // end namespace Catch
    210