mirror of https://github.com/catchorg/Catch2.git
Reporter command line parser errors more eagerly
- show all “unrecognised option” errors
This commit is contained in:
parent
f385a0b13d
commit
886d9d397c
|
@ -142,9 +142,8 @@ namespace Catch {
|
||||||
|
|
||||||
int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
|
int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
|
||||||
try {
|
try {
|
||||||
|
m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
|
||||||
m_unusedTokens = m_cli.parseInto( argc, argv, m_configData );
|
m_unusedTokens = m_cli.parseInto( argc, argv, m_configData );
|
||||||
if( unusedOptionBehaviour == OnUnusedOptions::Fail )
|
|
||||||
enforceNoUsedTokens();
|
|
||||||
if( m_configData.showHelp )
|
if( m_configData.showHelp )
|
||||||
showHelp( m_configData.processName );
|
showHelp( m_configData.processName );
|
||||||
m_config.reset();
|
m_config.reset();
|
||||||
|
@ -152,7 +151,7 @@ namespace Catch {
|
||||||
catch( std::exception& ex ) {
|
catch( std::exception& ex ) {
|
||||||
{
|
{
|
||||||
Colour colourGuard( Colour::Red );
|
Colour colourGuard( Colour::Red );
|
||||||
std::cerr << "\nError in input:\n"
|
std::cerr << "\nError(s) in input:\n"
|
||||||
<< Text( ex.what(), TextAttributes().setIndent(2) )
|
<< Text( ex.what(), TextAttributes().setIndent(2) )
|
||||||
<< "\n\n";
|
<< "\n\n";
|
||||||
}
|
}
|
||||||
|
@ -167,18 +166,6 @@ namespace Catch {
|
||||||
m_config.reset();
|
m_config.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void enforceNoUsedTokens() const {
|
|
||||||
if( !m_unusedTokens.empty() ) {
|
|
||||||
std::vector<Clara::Parser::Token>::const_iterator
|
|
||||||
it = m_unusedTokens.begin(),
|
|
||||||
itEnd = m_unusedTokens.end();
|
|
||||||
std::string msg;
|
|
||||||
for(; it != itEnd; ++it )
|
|
||||||
msg += " unrecognised option: " + it->data + "\n";
|
|
||||||
throw std::runtime_error( msg.substr( 0, msg.size()-1 ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int run( int argc, char* const argv[] ) {
|
int run( int argc, char* const argv[] ) {
|
||||||
|
|
||||||
int returnCode = applyCommandLine( argc, argv );
|
int returnCode = applyCommandLine( argc, argv );
|
||||||
|
|
|
@ -371,18 +371,25 @@ namespace Clara {
|
||||||
|
|
||||||
CommandLine()
|
CommandLine()
|
||||||
: m_boundProcessName( new Detail::NullBinder<ConfigT>() ),
|
: m_boundProcessName( new Detail::NullBinder<ConfigT>() ),
|
||||||
m_highestSpecifiedArgPosition( 0 )
|
m_highestSpecifiedArgPosition( 0 ),
|
||||||
|
m_throwOnUnrecognisedTokens( false )
|
||||||
{}
|
{}
|
||||||
CommandLine( CommandLine const& other )
|
CommandLine( CommandLine const& other )
|
||||||
: m_boundProcessName( other.m_boundProcessName ),
|
: m_boundProcessName( other.m_boundProcessName ),
|
||||||
m_options ( other.m_options ),
|
m_options ( other.m_options ),
|
||||||
m_positionalArgs( other.m_positionalArgs ),
|
m_positionalArgs( other.m_positionalArgs ),
|
||||||
m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition )
|
m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ),
|
||||||
|
m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens )
|
||||||
{
|
{
|
||||||
if( other.m_arg.get() )
|
if( other.m_arg.get() )
|
||||||
m_arg = ArgAutoPtr( new Arg( *other.m_arg ) );
|
m_arg = ArgAutoPtr( new Arg( *other.m_arg ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) {
|
||||||
|
m_throwOnUnrecognisedTokens = shouldThrow;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
ArgBinder bind( F f ) {
|
ArgBinder bind( F f ) {
|
||||||
ArgBinder binder( this, f );
|
ArgBinder binder( this, f );
|
||||||
|
@ -488,6 +495,7 @@ namespace Clara {
|
||||||
|
|
||||||
std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
|
std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
|
||||||
std::vector<Parser::Token> unusedTokens;
|
std::vector<Parser::Token> unusedTokens;
|
||||||
|
std::vector<std::string> errors;
|
||||||
for( std::size_t i = 0; i < tokens.size(); ++i ) {
|
for( std::size_t i = 0; i < tokens.size(); ++i ) {
|
||||||
Parser::Token const& token = tokens[i];
|
Parser::Token const& token = tokens[i];
|
||||||
typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
|
typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
|
||||||
|
@ -499,8 +507,9 @@ namespace Clara {
|
||||||
( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) {
|
( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) {
|
||||||
if( arg.takesArg() ) {
|
if( arg.takesArg() ) {
|
||||||
if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional )
|
if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional )
|
||||||
throw std::domain_error( "Expected argument to option " + token.data );
|
errors.push_back( "Expected argument to option: " + token.data );
|
||||||
arg.boundField.set( config, tokens[++i].data );
|
else
|
||||||
|
arg.boundField.set( config, tokens[++i].data );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
arg.boundField.setFlag( config );
|
arg.boundField.setFlag( config );
|
||||||
|
@ -509,11 +518,26 @@ namespace Clara {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch( std::exception& ex ) {
|
catch( std::exception& ex ) {
|
||||||
throw std::runtime_error( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" );
|
errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( it == itEnd )
|
if( it == itEnd ) {
|
||||||
unusedTokens.push_back( token );
|
if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens )
|
||||||
|
unusedTokens.push_back( token );
|
||||||
|
else if( m_throwOnUnrecognisedTokens )
|
||||||
|
errors.push_back( "unrecognised option: " + token.data );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( !errors.empty() ) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end();
|
||||||
|
it != itEnd;
|
||||||
|
++it ) {
|
||||||
|
if( it != errors.begin() )
|
||||||
|
oss << "\n";
|
||||||
|
oss << *it;
|
||||||
|
}
|
||||||
|
throw std::runtime_error( oss.str() );
|
||||||
}
|
}
|
||||||
return unusedTokens;
|
return unusedTokens;
|
||||||
}
|
}
|
||||||
|
@ -552,6 +576,7 @@ namespace Clara {
|
||||||
std::map<int, Arg> m_positionalArgs;
|
std::map<int, Arg> m_positionalArgs;
|
||||||
ArgAutoPtr m_arg;
|
ArgAutoPtr m_arg;
|
||||||
int m_highestSpecifiedArgPosition;
|
int m_highestSpecifiedArgPosition;
|
||||||
|
bool m_throwOnUnrecognisedTokens;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace Clara
|
} // end namespace Clara
|
||||||
|
|
|
@ -116,7 +116,7 @@ TEST_CASE( "cmdline" ) {
|
||||||
.shortOpt( "d" )
|
.shortOpt( "d" )
|
||||||
.longOpt( "description" )
|
.longOpt( "description" )
|
||||||
.hint( "some text" );
|
.hint( "some text" );
|
||||||
|
|
||||||
const char* argv[] = { "test", "-n 42", "-d some text" };
|
const char* argv[] = { "test", "-n 42", "-d some text" };
|
||||||
std::vector<Clara::Parser::Token> unusedTokens = parseInto( cli, argv, config1 );
|
std::vector<Clara::Parser::Token> unusedTokens = parseInto( cli, argv, config1 );
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue