mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-11-03 21:49:32 +01:00 
			
		
		
		
	Reporter command line parser errors more eagerly
- show all “unrecognised option” errors
This commit is contained in:
		@@ -142,9 +142,8 @@ namespace Catch {
 | 
			
		||||
 | 
			
		||||
        int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
 | 
			
		||||
            try {
 | 
			
		||||
                m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
 | 
			
		||||
                m_unusedTokens = m_cli.parseInto( argc, argv, m_configData );
 | 
			
		||||
                if( unusedOptionBehaviour == OnUnusedOptions::Fail )
 | 
			
		||||
                    enforceNoUsedTokens();
 | 
			
		||||
                if( m_configData.showHelp )
 | 
			
		||||
                    showHelp( m_configData.processName );
 | 
			
		||||
                m_config.reset();
 | 
			
		||||
@@ -152,7 +151,7 @@ namespace Catch {
 | 
			
		||||
            catch( std::exception& ex ) {
 | 
			
		||||
                {
 | 
			
		||||
                    Colour colourGuard( Colour::Red );
 | 
			
		||||
                    std::cerr   << "\nError in input:\n"
 | 
			
		||||
                    std::cerr   << "\nError(s) in input:\n"
 | 
			
		||||
                                << Text( ex.what(), TextAttributes().setIndent(2) )
 | 
			
		||||
                                << "\n\n";
 | 
			
		||||
                }
 | 
			
		||||
@@ -167,18 +166,6 @@ namespace Catch {
 | 
			
		||||
            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 returnCode = applyCommandLine( argc, argv );
 | 
			
		||||
 
 | 
			
		||||
@@ -371,18 +371,25 @@ namespace Clara {
 | 
			
		||||
 | 
			
		||||
        CommandLine()
 | 
			
		||||
        :   m_boundProcessName( new Detail::NullBinder<ConfigT>() ),
 | 
			
		||||
            m_highestSpecifiedArgPosition( 0 )
 | 
			
		||||
            m_highestSpecifiedArgPosition( 0 ),
 | 
			
		||||
            m_throwOnUnrecognisedTokens( false )
 | 
			
		||||
        {}
 | 
			
		||||
        CommandLine( CommandLine const& other )
 | 
			
		||||
        :   m_boundProcessName( other.m_boundProcessName ),
 | 
			
		||||
            m_options ( other.m_options ),
 | 
			
		||||
            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() )
 | 
			
		||||
                m_arg = ArgAutoPtr( new Arg( *other.m_arg ) );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) {
 | 
			
		||||
            m_throwOnUnrecognisedTokens = shouldThrow;
 | 
			
		||||
            return *this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        template<typename F>
 | 
			
		||||
        ArgBinder bind( F 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> unusedTokens;
 | 
			
		||||
            std::vector<std::string> errors;
 | 
			
		||||
            for( std::size_t i = 0; i < tokens.size(); ++i ) {
 | 
			
		||||
                Parser::Token const& token = tokens[i];
 | 
			
		||||
                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 ) ) ) {
 | 
			
		||||
                            if( arg.takesArg() ) {
 | 
			
		||||
                                if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional )
 | 
			
		||||
                                    throw std::domain_error( "Expected argument to option " + token.data );
 | 
			
		||||
                                arg.boundField.set( config, tokens[++i].data );
 | 
			
		||||
                                    errors.push_back( "Expected argument to option: " + token.data );
 | 
			
		||||
                                else
 | 
			
		||||
                                    arg.boundField.set( config, tokens[++i].data );
 | 
			
		||||
                            }
 | 
			
		||||
                            else {
 | 
			
		||||
                                arg.boundField.setFlag( config );
 | 
			
		||||
@@ -509,11 +518,26 @@ namespace Clara {
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    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 )
 | 
			
		||||
                    unusedTokens.push_back( token );
 | 
			
		||||
                if( it == itEnd ) {
 | 
			
		||||
                    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;
 | 
			
		||||
        }
 | 
			
		||||
@@ -552,6 +576,7 @@ namespace Clara {
 | 
			
		||||
        std::map<int, Arg> m_positionalArgs;
 | 
			
		||||
        ArgAutoPtr m_arg;
 | 
			
		||||
        int m_highestSpecifiedArgPosition;
 | 
			
		||||
        bool m_throwOnUnrecognisedTokens;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
} // end namespace Clara
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user