mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 20:27:11 +01:00 
			
		
		
		
	Moved Clara into its (her?) own file
This commit is contained in:
		| @@ -9,513 +9,10 @@ | ||||
| #pragma clang diagnostic ignored "-Wpadded" | ||||
| #endif | ||||
|  | ||||
| #include "internal/clara.h" | ||||
|  | ||||
| #include "catch.hpp" | ||||
| #include "catch_text.h" | ||||
|  | ||||
| namespace Clara { | ||||
|     namespace Detail { | ||||
|         template<typename T> struct RemoveConstRef{ typedef T type; }; | ||||
|         template<typename T> struct RemoveConstRef<T&>{ typedef T type; }; | ||||
|         template<typename T> struct RemoveConstRef<T const&>{ typedef T type; }; | ||||
|         template<typename T> struct RemoveConstRef<T const>{ typedef T type; }; | ||||
|  | ||||
|         template<typename T>    struct IsBool       { static const bool value = false; }; | ||||
|         template<>              struct IsBool<bool> { static const bool value = true; }; | ||||
|  | ||||
|         template<typename T> | ||||
|         void convertInto( std::string const& _source, T& _dest ) { | ||||
|             std::stringstream ss; | ||||
|             ss << _source; | ||||
|             ss >> _dest; | ||||
|             if( ss.fail() ) | ||||
|                 throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); | ||||
|         } | ||||
|         inline void convertInto( std::string const& _source, std::string& _dest ) { | ||||
|             _dest = _source; | ||||
|         } | ||||
|         inline void convertInto( std::string const& _source, bool& _dest ) { | ||||
|             std::string sourceLC = _source; | ||||
|             std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); | ||||
|             if( sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) | ||||
|                 _dest = true; | ||||
|             else if( sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) | ||||
|                 _dest = false; | ||||
|             else | ||||
|                 throw std::runtime_error( "Expected a boolean value but did recognise: '" + _source + "'" ); | ||||
|         } | ||||
|         inline void convertInto( bool _source, bool& _dest ) { | ||||
|             _dest = _source; | ||||
|         } | ||||
|         template<typename T> | ||||
|         inline void convertInto( bool, T& ) { | ||||
|             throw std::runtime_error( "Invalid conversion" ); | ||||
|         } | ||||
|  | ||||
|         template<typename ConfigT> | ||||
|         struct IArgFunction { | ||||
|             virtual ~IArgFunction() {} | ||||
|             virtual void set( ConfigT& config, std::string const& value ) const = 0; | ||||
|             virtual void setFlag( ConfigT& config ) const = 0; | ||||
|             virtual bool takesArg() const = 0; | ||||
|             virtual IArgFunction* clone() const = 0; | ||||
|         }; | ||||
|  | ||||
|         template<typename ConfigT> | ||||
|         class BoundArgFunction { | ||||
|         public: | ||||
|             BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {} | ||||
|             BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj->clone() ) {} | ||||
|             BoundArgFunction& operator = ( BoundArgFunction const& other ) { | ||||
|                 IArgFunction<ConfigT> newFunctionObj = other.clone(); | ||||
|                 delete functionObj; | ||||
|                 functionObj = newFunctionObj; | ||||
|                 return *this; | ||||
|             } | ||||
|             ~BoundArgFunction() { delete functionObj; } | ||||
|  | ||||
|             void set( ConfigT& config, std::string const& value ) const { | ||||
|                 functionObj->set( config, value ); | ||||
|             } | ||||
|             void setFlag( ConfigT& config ) const { | ||||
|                 functionObj->setFlag( config ); | ||||
|             } | ||||
|             bool takesArg() const { return functionObj->takesArg(); } | ||||
|         private: | ||||
|             IArgFunction<ConfigT>* functionObj; | ||||
|         }; | ||||
|  | ||||
|  | ||||
|         template<typename C, typename M> | ||||
|         struct BoundDataMember : IArgFunction<C>{ | ||||
|             BoundDataMember( M C::* _member ) : member( _member ) {} | ||||
|             virtual void set( C& p, std::string const& stringValue ) const { | ||||
|                 convertInto( stringValue, p.*member ); | ||||
|             } | ||||
|             virtual void setFlag( C& p ) const { | ||||
|                 convertInto( true, p.*member ); | ||||
|             } | ||||
|             virtual bool takesArg() const { return !IsBool<M>::value; } | ||||
|             virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); } | ||||
|             M C::* member; | ||||
|         }; | ||||
|         template<typename C, typename M> | ||||
|         struct BoundUnaryMethod : IArgFunction<C>{ | ||||
|             BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} | ||||
|             virtual void set( C& p, std::string const& stringValue ) const { | ||||
|                 typename RemoveConstRef<M>::type value; | ||||
|                 convertInto( stringValue, value ); | ||||
|                 (p.*member)( value ); | ||||
|             } | ||||
|             virtual void setFlag( C& p ) const { | ||||
|                 typename RemoveConstRef<M>::type value; | ||||
|                 convertInto( true, value ); | ||||
|                 (p.*member)( value ); | ||||
|             } | ||||
|             virtual bool takesArg() const { return !IsBool<M>::value; } | ||||
|             virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); } | ||||
|             void (C::*member)( M ); | ||||
|         }; | ||||
|         template<typename C> | ||||
|         struct BoundNullaryMethod : IArgFunction<C>{ | ||||
|             BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} | ||||
|             virtual void set( C& p, std::string const& stringValue ) const { | ||||
|                 bool value; | ||||
|                 convertInto( stringValue, value ); | ||||
|                 if( value ) | ||||
|                     (p.*member)(); | ||||
|             } | ||||
|             virtual void setFlag( C& p ) const { | ||||
|                 (p.*member)(); | ||||
|             } | ||||
|             virtual bool takesArg() const { return false; } | ||||
|             virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); } | ||||
|             void (C::*member)(); | ||||
|         }; | ||||
|  | ||||
|         template<typename C> | ||||
|         struct BoundUnaryFunction : IArgFunction<C>{ | ||||
|             BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} | ||||
|             virtual void set( C& obj, std::string const& stringValue ) const { | ||||
|                 bool value; | ||||
|                 convertInto( stringValue, value ); | ||||
|                 if( value ) | ||||
|                     function( obj ); | ||||
|             } | ||||
|             virtual void setFlag( C& p ) const { | ||||
|                 function( p ); | ||||
|             } | ||||
|             virtual bool takesArg() const { return false; } | ||||
|             virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); } | ||||
|             void (*function)( C& ); | ||||
|         }; | ||||
|          | ||||
|         template<typename C, typename T> | ||||
|         struct BoundBinaryFunction : IArgFunction<C>{ | ||||
|             BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} | ||||
|             virtual void set( C& obj, std::string const& stringValue ) const { | ||||
|                 typename RemoveConstRef<T>::type value; | ||||
|                 convertInto( stringValue, value ); | ||||
|                 function( obj, value ); | ||||
|             } | ||||
|             virtual void setFlag( C& obj ) const { | ||||
|                 typename RemoveConstRef<T>::type value; | ||||
|                 convertInto( true, value ); | ||||
|                 function( obj, value ); | ||||
|             } | ||||
|             virtual bool takesArg() const { return !IsBool<T>::value; } | ||||
|             virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); } | ||||
|             void (*function)( C&, T ); | ||||
|         }; | ||||
|          | ||||
|         template<typename C, typename M> | ||||
|         BoundArgFunction<C> makeBoundField( M C::* _member ) { | ||||
|             return BoundArgFunction<C>( new BoundDataMember<C,M>( _member ) ); | ||||
|         } | ||||
|         template<typename C, typename M> | ||||
|         BoundArgFunction<C> makeBoundField( void (C::*_member)( M ) ) { | ||||
|             return BoundArgFunction<C>( new BoundUnaryMethod<C,M>( _member ) ); | ||||
|         } | ||||
|         template<typename C> | ||||
|         BoundArgFunction<C> makeBoundField( void (C::*_member)() ) { | ||||
|             return BoundArgFunction<C>( new BoundNullaryMethod<C>( _member ) ); | ||||
|         } | ||||
|         template<typename C> | ||||
|         BoundArgFunction<C> makeBoundField( void (*_function)( C& ) ) { | ||||
|             return BoundArgFunction<C>( new BoundUnaryFunction<C>( _function ) ); | ||||
|         } | ||||
|         template<typename C, typename T> | ||||
|         BoundArgFunction<C> makeBoundField( void (*_function)( C&, T ) ) { | ||||
|             return BoundArgFunction<C>( new BoundBinaryFunction<C, T>( _function ) ); | ||||
|         } | ||||
|     } // namespace Detail | ||||
|  | ||||
|     struct Parser { | ||||
|         Parser() : separators( " \t=:" ) {} | ||||
|  | ||||
|         struct Token { | ||||
|             enum Type { Positional, ShortOpt, LongOpt }; | ||||
|             Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} | ||||
|             Type type; | ||||
|             std::string data; | ||||
|         }; | ||||
|  | ||||
|         void parseIntoTokens( int argc, char const* argv[], std::vector<Parser::Token>& tokens ) const { | ||||
|             for( int i = 1; i < argc; ++i ) | ||||
|                 parseIntoTokens( argv[i] , tokens); | ||||
|         }         | ||||
|         void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const { | ||||
|             while( !arg.empty() ) { | ||||
|                 Parser::Token token( Parser::Token::Positional, arg ); | ||||
|                 arg = ""; | ||||
|                 if( token.data[0] == '-' ) { | ||||
|                     if( token.data.size() > 1 && token.data[1] == '-' ) { | ||||
|                         token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); | ||||
|                     } | ||||
|                     else { | ||||
|                         token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); | ||||
|                         if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { | ||||
|                             arg = "-" + token.data.substr( 1 ); | ||||
|                             token.data = token.data.substr( 0, 1 ); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 if( token.type != Parser::Token::Positional ) { | ||||
|                     std::size_t pos = token.data.find_first_of( separators ); | ||||
|                     if( pos != std::string::npos ) { | ||||
|                         arg = token.data.substr( pos+1 ); | ||||
|                         token.data = token.data.substr( 0, pos ); | ||||
|                     } | ||||
|                 } | ||||
|                 tokens.push_back( token ); | ||||
|             } | ||||
|         } | ||||
|         std::string separators; | ||||
|     }; | ||||
|  | ||||
|     template<typename ConfigT> | ||||
|     class CommandLine { | ||||
|  | ||||
|         struct Arg { | ||||
|             Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ), position( -1 ) {} | ||||
|  | ||||
|             bool hasShortName( std::string const& shortName ) const { | ||||
|                 for(    std::vector<std::string>::const_iterator | ||||
|                             it = shortNames.begin(), itEnd = shortNames.end(); | ||||
|                         it != itEnd; | ||||
|                         ++it ) | ||||
|                     if( *it == shortName ) | ||||
|                         return true; | ||||
|                 return false; | ||||
|             } | ||||
|             bool hasLongName( std::string const& _longName ) const { | ||||
|                 return _longName == longName; | ||||
|             } | ||||
|             bool takesArg() const { | ||||
|                 return !argName.empty(); | ||||
|             } | ||||
|             bool isFixedPositional() const { | ||||
|                 return position != -1; | ||||
|             } | ||||
|             bool isAnyPositional() const { | ||||
|                 return position == -1 && shortNames.empty() && longName.empty(); | ||||
|             } | ||||
|             std::string dbgName() const { | ||||
|                 if( !longName.empty() ) | ||||
|                     return "--" + longName; | ||||
|                 if( !shortNames.empty() ) | ||||
|                     return "-" + shortNames[0]; | ||||
|                 return "positional args"; | ||||
|             } | ||||
|             void validate() const { | ||||
|                 if( boundField.takesArg() && !takesArg() ) | ||||
|                     throw std::logic_error( dbgName() + " must specify an arg name" ); | ||||
|             }         | ||||
|             std::string commands() const { | ||||
|                 std::ostringstream oss; | ||||
|                 bool first = true; | ||||
|                 std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); | ||||
|                 for(; it != itEnd; ++it ) { | ||||
|                     if( first ) | ||||
|                         first = false; | ||||
|                     else | ||||
|                         oss << ", "; | ||||
|                     oss << "-" << *it; | ||||
|                 } | ||||
|                 if( !longName.empty() ) { | ||||
|                     if( !first ) | ||||
|                         oss << ", "; | ||||
|                     oss << "--" << longName; | ||||
|                 } | ||||
|                 if( !argName.empty() ) | ||||
|                     oss << " <" << argName << ">"; | ||||
|                 return oss.str(); | ||||
|             } | ||||
|          | ||||
|             Detail::BoundArgFunction<ConfigT> boundField; | ||||
|             std::vector<std::string> shortNames; | ||||
|             std::string longName; | ||||
|             std::string description; | ||||
|             std::string argName; | ||||
|             int position; | ||||
|         }; | ||||
|  | ||||
|         class ArgBinder { | ||||
|         public: | ||||
|             template<typename F> | ||||
|             ArgBinder( CommandLine* cl, F f ) | ||||
|             :   m_cl( cl ), | ||||
|                 m_arg( Detail::makeBoundField( f ) ) | ||||
|             {} | ||||
|             ArgBinder( ArgBinder& other ) | ||||
|             :   m_cl( other.m_cl ), | ||||
|                 m_arg( other.m_arg ) | ||||
|             { | ||||
|                 other.m_cl = NULL; | ||||
|             } | ||||
|             ~ArgBinder() { | ||||
|                 if( m_cl ) { | ||||
|                     m_arg.validate(); | ||||
|                     if( m_arg.isFixedPositional() ) { | ||||
|                         m_cl->m_positionalArgs.insert( std::make_pair( m_arg.position, m_arg ) ); | ||||
|                         if( m_arg.position > m_cl->m_highestSpecifiedArgPosition ) | ||||
|                             m_cl->m_highestSpecifiedArgPosition = m_arg.position; | ||||
|                     } | ||||
|                     else if( m_arg.isAnyPositional() ) { | ||||
|                         if( m_cl->m_arg.get() ) | ||||
|                             throw std::logic_error( "Only one unpositional argument can be added" ); | ||||
|                         m_cl->m_arg = std::auto_ptr<Arg>( new Arg( m_arg ) ); | ||||
|                     } | ||||
|                     else | ||||
|                         m_cl->m_options.push_back( m_arg ); | ||||
|                 } | ||||
|             } | ||||
|             ArgBinder& shortOpt( std::string const& name ) { | ||||
|                 m_arg.shortNames.push_back( name ); | ||||
|                 return *this; | ||||
|             } | ||||
|             ArgBinder& longOpt( std::string const& name ) { | ||||
|                 m_arg.longName = name; | ||||
|                 return *this; | ||||
|             } | ||||
|             ArgBinder& describe( std::string const& description ) { | ||||
|                 m_arg.description = description; | ||||
|                 return *this; | ||||
|             } | ||||
|             ArgBinder& argName( std::string const& argName ) { | ||||
|                 m_arg.argName = argName; | ||||
|                 return *this; | ||||
|             } | ||||
|             ArgBinder& position( int position ) { | ||||
|                 m_arg.position = position; | ||||
|                 return *this; | ||||
|             } | ||||
|         private: | ||||
|             CommandLine* m_cl; | ||||
|             Arg m_arg; | ||||
|         }; | ||||
|  | ||||
|     public: | ||||
|      | ||||
|         CommandLine() : m_highestSpecifiedArgPosition( 0 ) {} | ||||
|  | ||||
|         template<typename F> | ||||
|         ArgBinder bind( F f ) { | ||||
|             ArgBinder binder( this, f ); | ||||
|             return binder; | ||||
|         } | ||||
|  | ||||
|         void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = CATCH_CONFIG_CONSOLE_WIDTH ) const { | ||||
|             typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; | ||||
|             std::size_t maxWidth = 0; | ||||
|             for( it = itBegin; it != itEnd; ++it ) | ||||
|                 maxWidth = (std::max)( maxWidth, it->commands().size() ); | ||||
|  | ||||
|             for( it = itBegin; it != itEnd; ++it ) { | ||||
|                 Catch::Text usage( it->commands(), Catch::TextAttributes() | ||||
|                                                         .setWidth( maxWidth+indent ) | ||||
|                                                         .setIndent( indent ) ); | ||||
|                 // !TBD handle longer usage strings | ||||
|                 Catch::Text desc( it->description, Catch::TextAttributes() | ||||
|                                                         .setWidth( width - maxWidth -3 ) ); | ||||
|  | ||||
|                 for( std::size_t i = 0; i < std::max( usage.size(), desc.size() ); ++i ) { | ||||
|                     std::string usageCol = i < usage.size() ? usage[i] : ""; | ||||
|                     os << usageCol; | ||||
|  | ||||
|                     if( i < desc.size() && !desc[i].empty() ) | ||||
|                         os  << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) | ||||
|                             << desc[i]; | ||||
|                     os << "\n"; | ||||
|                 }                 | ||||
|             }             | ||||
|         } | ||||
|         std::string optUsage() const { | ||||
|             std::ostringstream oss; | ||||
|             optUsage( oss ); | ||||
|             return oss.str(); | ||||
|         } | ||||
|          | ||||
|         void argSynopsis( std::ostream& os ) const { | ||||
|             for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { | ||||
|                 if( i > 1 ) | ||||
|                     os << " "; | ||||
|                 typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i ); | ||||
|                 if( it != m_positionalArgs.end() ) | ||||
|                     os << "<" << it->second.argName << ">"; | ||||
|                 else if( m_arg.get() ) | ||||
|                     os << "<" << m_arg->argName << ">"; | ||||
|                 else | ||||
|                     throw std::logic_error( "non consecutive positional arguments with no floating args" ); | ||||
|             } | ||||
|             // !TBD No indication of mandatory args | ||||
|             if( m_arg.get() ) { | ||||
|                 if( m_highestSpecifiedArgPosition > 1 ) | ||||
|                     os << " "; | ||||
|                 os << "[<" << m_arg->argName << "> ...]"; | ||||
|             } | ||||
|         } | ||||
|         std::string argSynopsis() const { | ||||
|             std::ostringstream oss; | ||||
|             argSynopsis( oss ); | ||||
|             return oss.str(); | ||||
|         } | ||||
|          | ||||
|  | ||||
|         void usage( std::ostream& os, std::string const& procName ) const { | ||||
|             os << "usage:\n  " << procName << " "; | ||||
|             argSynopsis( os ); | ||||
|             if( !m_options.empty() ) { | ||||
|                 os << " [options]\n\nwhere options are: \n"; | ||||
|                 optUsage( os, 2 );                 | ||||
|             } | ||||
|             os << "\n"; | ||||
|         } | ||||
|         std::string usage( std::string const& procName ) const { | ||||
|             std::ostringstream oss; | ||||
|             usage( oss, procName ); | ||||
|             return oss.str(); | ||||
|         }         | ||||
|          | ||||
|         std::vector<Parser::Token> parseInto( int argc, char const* argv[], ConfigT& config ) const { | ||||
|             std::vector<Parser::Token> tokens; | ||||
|             Parser parser; | ||||
|             parser.parseIntoTokens( argc, argv, tokens ); | ||||
|             return populate( tokens, config ); | ||||
|         } | ||||
|  | ||||
|         std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { | ||||
|             if( m_options.empty() && m_positionalArgs.empty() ) | ||||
|                 throw std::logic_error( "No options or arguments specified" ); | ||||
|  | ||||
|             std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config ); | ||||
|             unusedTokens = populateFixedArgs( unusedTokens, config ); | ||||
|             unusedTokens = populateFloatingArgs( unusedTokens, config ); | ||||
|             return unusedTokens; | ||||
|         } | ||||
|  | ||||
|         std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { | ||||
|             std::vector<Parser::Token> unusedTokens; | ||||
|             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(); | ||||
|                 for(; it != itEnd; ++it ) { | ||||
|                     Arg const& arg = *it; | ||||
|                      | ||||
|                     if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || | ||||
|                         ( 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 ); | ||||
|                         } | ||||
|                         else { | ||||
|                             arg.boundField.setFlag( config ); | ||||
|                         } | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|                 if( it == itEnd ) | ||||
|                     unusedTokens.push_back( token ); | ||||
|             } | ||||
|             return unusedTokens; | ||||
|         } | ||||
|         std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { | ||||
|             std::vector<Parser::Token> unusedTokens; | ||||
|             int position = 1; | ||||
|             for( std::size_t i = 0; i < tokens.size(); ++i ) { | ||||
|                 Parser::Token const& token = tokens[i]; | ||||
|                 typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position ); | ||||
|                 if( it != m_positionalArgs.end() ) | ||||
|                     it->second.boundField.set( config, token.data ); | ||||
|                 else | ||||
|                     unusedTokens.push_back( token ); | ||||
|                 if( token.type == Parser::Token::Positional ) | ||||
|                     position++;                 | ||||
|             } | ||||
|             return unusedTokens; | ||||
|         } | ||||
|         std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { | ||||
|             if( !m_arg.get() ) | ||||
|                 return tokens; | ||||
|             std::vector<Parser::Token> unusedTokens; | ||||
|             for( std::size_t i = 0; i < tokens.size(); ++i ) { | ||||
|                 Parser::Token const& token = tokens[i]; | ||||
|                 if( token.type == Parser::Token::Positional ) | ||||
|                     m_arg->boundField.set( config, token.data ); | ||||
|                 else | ||||
|                     unusedTokens.push_back( token ); | ||||
|             } | ||||
|             return unusedTokens; | ||||
|         } | ||||
|          | ||||
|     private: | ||||
|         std::vector<Arg> m_options; | ||||
|         std::map<int, Arg> m_positionalArgs; | ||||
|         std::auto_ptr<Arg> m_arg; | ||||
|         int m_highestSpecifiedArgPosition; | ||||
|     }; | ||||
|      | ||||
| } // end namespace Clara | ||||
|  | ||||
| // Helper to deduce size from array literals and pass on to parser | ||||
| template<size_t size, typename ConfigT> | ||||
| @@ -684,6 +181,10 @@ TEST_CASE( "cmdline" ) { | ||||
| } | ||||
|  | ||||
| struct Config { | ||||
|  | ||||
|     struct Verbosity { enum Level { NoOutput = 0, Quiet, Normal }; }; | ||||
|     struct Warning { enum Types { Nothing = 0x00, NoAssertions = 0x01 }; }; | ||||
|  | ||||
|     Config() | ||||
|     :   listTests( false ), | ||||
|         listTags( false ), | ||||
| @@ -692,7 +193,7 @@ struct Config { | ||||
|         noThrow( false ), | ||||
|         showHelp( false ), | ||||
|         abortAfter( 0 ), | ||||
|         verbosity( Normal ) | ||||
|         verbosity( Verbosity::Normal ) | ||||
|     {} | ||||
|  | ||||
|     bool listTests; | ||||
| @@ -705,21 +206,33 @@ struct Config { | ||||
|     bool showHelp; | ||||
|  | ||||
|     int abortAfter; | ||||
|     enum Verbosity { NoOutput = 0, Quiet, Normal }; | ||||
|     Verbosity verbosity; | ||||
|  | ||||
|     Verbosity::Level verbosity; | ||||
|     Warning::Types warnings; | ||||
|  | ||||
|     std::string reporterName; | ||||
|     std::string fileName; | ||||
|     std::string suiteName; | ||||
|     std::string reporter; | ||||
|     std::vector<std::string> warnings; | ||||
|  | ||||
|     std::vector<std::string> testsOrTags; | ||||
| }; | ||||
|  | ||||
| inline void abortAfterFirst( Config& config ) { config.abortAfter = 1; } | ||||
| inline void abortAfterX( Config& config, int x ) { config.abortAfter = x; } | ||||
| inline void addWarning( Config& config, std::string const& _warning ) { config.warnings.push_back( _warning ); } | ||||
| inline void addTestOrTags( Config& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }     | ||||
| inline void setVerbosity( Config& config, int level ) { config.verbosity = (Config::Verbosity)level; } | ||||
| inline void addTestOrTags( Config& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } | ||||
|  | ||||
| inline void addWarning( Config& config, std::string const& _warning ) { | ||||
|     if( _warning == "NoAssertions" ) | ||||
|         config.warnings = (Config::Warning::Types)( config.warnings | Config::Warning::NoAssertions ); | ||||
|     else | ||||
|         throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); | ||||
|  | ||||
| } | ||||
| inline void setVerbosity( Config& config, int level ) { | ||||
|     // !TBD: accept strings? | ||||
|     config.verbosity = (Config::Verbosity::Level)level; | ||||
| } | ||||
|  | ||||
|  | ||||
| SCENARIO( "New Catch commandline interface", "[cli]" ) { | ||||
| @@ -857,13 +370,13 @@ SCENARIO( "New Catch commandline interface", "[cli]" ) { | ||||
|             } | ||||
|         } | ||||
|         WHEN( "And enum opt is set by numeric value" ) { | ||||
|             CHECK( config.verbosity == Config::Normal ); | ||||
|             CHECK( config.verbosity == Config::Verbosity::Normal ); | ||||
|  | ||||
|             const char* argv[] = { "test", "-v 0" }; | ||||
|             parseInto( cli, argv, config ); | ||||
|              | ||||
|             THEN( "The member is set to the enum value" ) | ||||
|                 REQUIRE( config.verbosity == Config::NoOutput ); | ||||
|                 REQUIRE( config.verbosity == Config::Verbosity::NoOutput ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Phil Nash
					Phil Nash