| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  Created by Phil on 22/10/2010. | 
					
						
							|  |  |  |  *  Copyright 2010 Two Blue Cubes Ltd | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Distributed under the Boost Software License, Version 1.0. (See accompanying | 
					
						
							|  |  |  |  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #ifdef __clang__
 | 
					
						
							|  |  |  | #pragma clang diagnostic ignored "-Wpadded"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "catch.hpp"
 | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  | #include "catch_text.h"
 | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  | namespace Clara { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |     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" ); | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |     inline void convertInto( std::string const& _source, std::string& _dest ) { | 
					
						
							|  |  |  |         _dest = _source; | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |     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 + "'" ); | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |     inline void convertInto( bool _source, bool& _dest ) { | 
					
						
							|  |  |  |         _dest = _source; | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |     template<typename T> | 
					
						
							|  |  |  |     inline void convertInto( bool, T& ) { | 
					
						
							|  |  |  |         throw std::runtime_error( "Invalid conversion" ); | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     template<typename ConfigT> | 
					
						
							|  |  |  |     struct IBoundMember { | 
					
						
							|  |  |  |         virtual ~IBoundMember() {} | 
					
						
							|  |  |  |         virtual void set( ConfigT& config, std::string const& value ) const = 0; | 
					
						
							|  |  |  |         virtual void setFlag( ConfigT& config ) const = 0; | 
					
						
							|  |  |  |         virtual bool takesArg() const = 0; | 
					
						
							|  |  |  |         virtual IBoundMember* clone() const = 0; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template<typename ConfigT> | 
					
						
							|  |  |  |     class BoundField { | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         BoundField( IBoundMember<ConfigT>* _boundMember ) : boundMember( _boundMember ) {} | 
					
						
							|  |  |  |         BoundField( BoundField const& other ) : boundMember( other.boundMember->clone() ) {} | 
					
						
							|  |  |  |         BoundField& operator = ( BoundField const& other ) { | 
					
						
							|  |  |  |             IBoundMember<ConfigT> newMember = other.clone(); | 
					
						
							|  |  |  |             delete boundMember; | 
					
						
							|  |  |  |             boundMember = newMember; | 
					
						
							|  |  |  |             return *this; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         ~BoundField() { delete boundMember; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         void set( ConfigT& config, std::string const& value ) const { | 
					
						
							|  |  |  |             boundMember->set( config, value ); | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |         void setFlag( ConfigT& config ) const { | 
					
						
							|  |  |  |             boundMember->setFlag( config ); | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |         bool takesArg() const { return boundMember->takesArg(); } | 
					
						
							|  |  |  |     private: | 
					
						
							|  |  |  |         IBoundMember<ConfigT>* boundMember; | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  |     template<typename C, typename M> | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |     struct BoundDataMember : IBoundMember<C>{ | 
					
						
							|  |  |  |         BoundDataMember( M C::* _member ) : member( _member ) {} | 
					
						
							|  |  |  |         virtual void set( C& p, std::string const& stringValue ) const { | 
					
						
							|  |  |  |             convertInto( stringValue, p.*member ); | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |         virtual void setFlag( C& p ) const { | 
					
						
							|  |  |  |             convertInto( true, p.*member ); | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |         virtual bool takesArg() const { return !IsBool<M>::value; } | 
					
						
							|  |  |  |         virtual IBoundMember<C>* clone() const { return new BoundDataMember( *this ); } | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |         M C::* member; | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  |     template<typename C, typename M> | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |     struct BoundUnaryMethod : IBoundMember<C>{ | 
					
						
							|  |  |  |         BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} | 
					
						
							|  |  |  |         virtual void set( C& p, std::string const& stringValue ) const { | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |             typename RemoveConstRef<M>::type value; | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |             convertInto( stringValue, value ); | 
					
						
							|  |  |  |             (p.*member)( value ); | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |         virtual void setFlag( C& p ) const { | 
					
						
							|  |  |  |             typename RemoveConstRef<M>::type value; | 
					
						
							|  |  |  |             convertInto( true, value ); | 
					
						
							|  |  |  |             (p.*member)( value ); | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |         virtual bool takesArg() const { return !IsBool<M>::value; } | 
					
						
							|  |  |  |         virtual IBoundMember<C>* clone() const { return new BoundUnaryMethod( *this ); } | 
					
						
							|  |  |  |         void (C::*member)( M ); | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |     template<typename C> | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |     struct BoundNullaryMethod : IBoundMember<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)(); | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |         virtual void setFlag( C& p ) const { | 
					
						
							|  |  |  |             (p.*member)(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         virtual bool takesArg() const { return false; } | 
					
						
							|  |  |  |         virtual IBoundMember<C>* clone() const { return new BoundNullaryMethod( *this ); } | 
					
						
							|  |  |  |         void (C::*member)(); | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |     }; | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |     template<typename C, typename M> | 
					
						
							|  |  |  |     BoundField<C> makeBoundField( M C::* _member ) { | 
					
						
							|  |  |  |         return BoundField<C>( new BoundDataMember<C,M>( _member ) ); | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |     template<typename C, typename M> | 
					
						
							|  |  |  |     BoundField<C> makeBoundField( void (C::*_member)( M ) ) { | 
					
						
							|  |  |  |         return BoundField<C>( new BoundUnaryMethod<C,M>( _member ) ); | 
					
						
							| 
									
										
										
										
											2013-04-29 19:26:18 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |     template<typename C> | 
					
						
							|  |  |  |     BoundField<C> makeBoundField( void (C::*_member)() ) { | 
					
						
							|  |  |  |         return BoundField<C>( new BoundNullaryMethod<C>( _member ) ); | 
					
						
							| 
									
										
										
										
											2013-04-29 19:26:18 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     template<typename ConfigT> | 
					
						
							|  |  |  |     class CommandLine { | 
					
						
							|  |  |  |         struct ArgToken { | 
					
						
							|  |  |  |             enum TokenType { | 
					
						
							|  |  |  |                 Positional, | 
					
						
							|  |  |  |                 ShortOpt, | 
					
						
							|  |  |  |                 LongOpt | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  |             ArgToken() : type( Positional ) {} | 
					
						
							|  |  |  |             ArgToken( TokenType _type, std::string const& _arg ) | 
					
						
							|  |  |  |                 : type( _type ), arg( _arg ) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             TokenType type; | 
					
						
							|  |  |  |             std::string arg; | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class ArgBinder { | 
					
						
							|  |  |  |         public: | 
					
						
							|  |  |  |             ArgBinder( CommandLine* cl ) : m_cl( cl ) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             template<typename F> | 
					
						
							|  |  |  |             ArgBinder& bind( F f ) { | 
					
						
							|  |  |  |                 if( !m_cl->opts.empty() ) | 
					
						
							|  |  |  |                     m_cl->opts.back().validate(); | 
					
						
							|  |  |  |                 m_cl->opts.push_back( Opt( makeBoundField( f ) ) ); | 
					
						
							|  |  |  |                 return *this; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ArgBinder& shortOpt( std::string const& name ) { | 
					
						
							|  |  |  |                 m_cl->opts.back().shortNames.push_back( name ); | 
					
						
							|  |  |  |                 return *this; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             ArgBinder& longOpt( std::string const& name ) { | 
					
						
							|  |  |  |                 m_cl->opts.back().longName = name; | 
					
						
							|  |  |  |                 return *this; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             ArgBinder& describe( std::string const& description ) { | 
					
						
							|  |  |  |                 m_cl->opts.back().description = description; | 
					
						
							|  |  |  |                 return *this; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             ArgBinder& argName( std::string const& argName ) { | 
					
						
							|  |  |  |                 m_cl->opts.back().argName = argName; | 
					
						
							|  |  |  |                 return *this; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             ArgBinder& position( int /*position*/ ) { | 
					
						
							|  |  |  |                 // !TBD: Support for positional args in fixed positions
 | 
					
						
							|  |  |  |                 return *this; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         private: | 
					
						
							|  |  |  |             CommandLine* m_cl; | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         struct Opt { | 
					
						
							|  |  |  |             public: | 
					
						
							|  |  |  |                 Opt( BoundField<ConfigT> const& _boundField ) : boundField( _boundField ) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 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; | 
					
						
							| 
									
										
										
										
											2013-05-03 08:08:46 +01:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |                 bool hasLongName( std::string const& _longName ) const { | 
					
						
							|  |  |  |                     return _longName == longName; | 
					
						
							| 
									
										
										
										
											2013-04-29 19:26:18 +01:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |                 bool takesArg() const { | 
					
						
							|  |  |  |                     return !argName.empty(); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 bool isPositional() const { | 
					
						
							|  |  |  |                     return 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; | 
					
						
							| 
									
										
										
										
											2013-05-03 08:08:46 +01:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |                     if( !longName.empty() ) { | 
					
						
							|  |  |  |                         if( !first ) | 
					
						
							|  |  |  |                             oss << ", "; | 
					
						
							|  |  |  |                         oss << "--" << longName; | 
					
						
							| 
									
										
										
										
											2013-05-03 08:08:46 +01:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |                     if( !argName.empty() ) | 
					
						
							|  |  |  |                         oss << " <" << argName << ">"; | 
					
						
							|  |  |  |                     return oss.str(); | 
					
						
							| 
									
										
										
										
											2013-04-29 19:26:18 +01:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |              | 
					
						
							|  |  |  |                 BoundField<ConfigT> boundField; | 
					
						
							|  |  |  |                 std::vector<std::string> shortNames; | 
					
						
							|  |  |  |                 std::string longName; | 
					
						
							|  |  |  |                 std::string description; | 
					
						
							|  |  |  |                 std::string argName; | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public: | 
					
						
							| 
									
										
										
										
											2013-05-16 08:21:13 +01:00
										 |  |  |         CommandLine() : seperators( " \t=:" ) {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |         template<typename F> | 
					
						
							|  |  |  |         ArgBinder bind( F f ) { | 
					
						
							|  |  |  |             ArgBinder binder( this ); | 
					
						
							|  |  |  |             binder.bind( f ); | 
					
						
							|  |  |  |             return binder; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         void parseInto( int argc, char const* argv[], ConfigT& config ) const { | 
					
						
							|  |  |  |             if( opts.empty() ) | 
					
						
							|  |  |  |                 throw std::logic_error( "No options or arguments specified" ); | 
					
						
							|  |  |  |             opts.back().validate(); | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             std::vector<ArgToken> tokens; | 
					
						
							|  |  |  |             parseIntoTokens( argc, argv, tokens );             | 
					
						
							|  |  |  |             setFromTokens( tokens, config ); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         void usage( std::ostream& os ) const { | 
					
						
							|  |  |  |             typename std::vector<Opt>::const_iterator itBegin = opts.begin(), itEnd = opts.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 ) ); | 
					
						
							|  |  |  |                 // !TBD handle longer usage strings
 | 
					
						
							|  |  |  |                 Catch::Text desc( it->description, Catch::TextAttributes().setWidth( CATCH_CONFIG_CONSOLE_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( 2 + maxWidth - usageCol.size(), ' ' ) | 
					
						
							|  |  |  |                             << desc[i]; | 
					
						
							|  |  |  |                     os << "\n"; | 
					
						
							|  |  |  |                 }                 | 
					
						
							| 
									
										
										
										
											2013-04-29 19:26:18 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |              | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         std::string usage() const { | 
					
						
							|  |  |  |             std::ostringstream oss; | 
					
						
							|  |  |  |             usage( oss ); | 
					
						
							|  |  |  |             return oss.str(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         friend std::ostream& operator << ( std::ostream& os, CommandLine const& parser ) { | 
					
						
							|  |  |  |             parser.usage( os ); | 
					
						
							|  |  |  |             return os; | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  |          | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |     private: | 
					
						
							|  |  |  |         void parseIntoTokens( int argc, char const* argv[], std::vector<ArgToken>& tokens ) const { | 
					
						
							|  |  |  |             for( int i = 1; i < argc; ++i ) { | 
					
						
							|  |  |  |                 std::string arg = argv[i]; | 
					
						
							|  |  |  |                 while( !arg.empty() ) { | 
					
						
							|  |  |  |                     ArgToken token( ArgToken::Positional, arg ); | 
					
						
							|  |  |  |                     arg = ""; | 
					
						
							|  |  |  |                     if( token.arg[0] == '-' ) { | 
					
						
							| 
									
										
										
										
											2013-05-16 08:21:13 +01:00
										 |  |  |                         if( token.arg.size() > 1 && token.arg[1] == '-' ) { | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |                             token = ArgToken( ArgToken::LongOpt, token.arg.substr( 2 ) ); | 
					
						
							| 
									
										
										
										
											2013-05-16 08:21:13 +01:00
										 |  |  |                         } | 
					
						
							|  |  |  |                         else { | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |                             token = ArgToken( ArgToken::ShortOpt, token.arg.substr( 1 ) ); | 
					
						
							| 
									
										
										
										
											2013-05-16 08:21:13 +01:00
										 |  |  |                             if( token.arg.size() > 1 && seperators.find( token.arg[1] ) == std::string::npos ) { | 
					
						
							|  |  |  |                                 arg = "-" + token.arg.substr( 1 ); | 
					
						
							|  |  |  |                                 token.arg = token.arg.substr( 0, 1 ); | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                         } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |                     } | 
					
						
							|  |  |  |                     if( token.type != ArgToken::Positional ) { | 
					
						
							| 
									
										
										
										
											2013-05-16 08:21:13 +01:00
										 |  |  |                         std::size_t pos = token.arg.find_first_of( seperators ); | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |                         if( pos != std::string::npos ) { | 
					
						
							|  |  |  |                             arg = token.arg.substr( pos+1 ); | 
					
						
							|  |  |  |                             token.arg = token.arg.substr( 0, pos ); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     tokens.push_back( token ); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  |             }             | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |         void setFromTokens( std::vector<ArgToken>const & tokens, ConfigT& config ) const { | 
					
						
							|  |  |  |             for( std::size_t i = 0; i < tokens.size(); ++i ) { | 
					
						
							|  |  |  |                 ArgToken const& token = tokens[i]; | 
					
						
							|  |  |  |                 typename std::vector<Opt>::const_iterator it = opts.begin(), itEnd = opts.end(); | 
					
						
							|  |  |  |                 for(; it != itEnd; ++it ) { | 
					
						
							|  |  |  |                     Opt const& opt = *it; | 
					
						
							|  |  |  |                      | 
					
						
							|  |  |  |                     if( ( token.type == ArgToken::ShortOpt && opt.hasShortName( token.arg ) ) || | 
					
						
							|  |  |  |                         ( token.type == ArgToken::LongOpt && opt.hasLongName( token.arg ) ) ) { | 
					
						
							|  |  |  |                         if( opt.takesArg() ) { | 
					
						
							|  |  |  |                             if( i == tokens.size()-1 || tokens[i+1].type != ArgToken::Positional ) | 
					
						
							|  |  |  |                                 throw std::domain_error( "Expected argument to option " + token.arg ); | 
					
						
							|  |  |  |                             opt.boundField.set( config, tokens[++i].arg ); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                         else { | 
					
						
							|  |  |  |                             opt.boundField.setFlag( config ); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     else if( token.type == ArgToken::Positional && opt.isPositional() ) { | 
					
						
							|  |  |  |                         opt.boundField.set( config, token.arg ); | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if( it == itEnd ) | 
					
						
							|  |  |  |                     unhandledTokens.push_back( token ); | 
					
						
							| 
									
										
										
										
											2013-05-02 18:41:08 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |          | 
					
						
							| 
									
										
										
										
											2013-05-16 08:21:13 +01:00
										 |  |  |         std::string seperators; | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |         std::vector<Opt> opts; | 
					
						
							|  |  |  |         mutable std::vector<ArgToken> unhandledTokens; // !TBD
 | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |      | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  | } // end namespace Clara
 | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct TestOpt { | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |     TestOpt() : number( 0 ), index( 0 ), flag( false ) {} | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     std::string fileName; | 
					
						
							|  |  |  |     int number; | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  |     int index; | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |     bool flag; | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  |      | 
					
						
							|  |  |  |     void setValidIndex( int i ) { | 
					
						
							|  |  |  |         if( i < 0 || i > 10 ) | 
					
						
							|  |  |  |             throw std::domain_error( "index must be between 0 and 10" ); | 
					
						
							|  |  |  |         index = i; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 19:26:18 +01:00
										 |  |  | struct TestOpt2 { | 
					
						
							|  |  |  |     std::string description; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-14 19:31:21 +01:00
										 |  |  | #ifdef CATCH_CONFIG_VARIADIC_MACROS
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  | TEST_CASE( "cmdline", "" ) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 18:41:08 +01:00
										 |  |  |     TestOpt config; | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |     Clara::CommandLine<TestOpt> parser; | 
					
						
							|  |  |  |     parser.bind( &TestOpt::fileName ) | 
					
						
							|  |  |  |         .describe( "specifies output file" ) | 
					
						
							|  |  |  |         .shortOpt( "o" ) | 
					
						
							|  |  |  |         .longOpt( "output" ) | 
					
						
							|  |  |  |         .argName( "<filename>" ); | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     SECTION( "plain filename" ) { | 
					
						
							| 
									
										
										
										
											2013-05-03 08:08:46 +01:00
										 |  |  |         const char* argv[] = { "test", "-o filename.ext" }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |         parser.parseInto( sizeof(argv)/sizeof(char*), argv, config ); | 
					
						
							| 
									
										
										
										
											2013-05-03 08:08:46 +01:00
										 |  |  |         CHECK( config.fileName == "filename.ext" ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     SECTION( "plain filename with colon" ) { | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |         const char* argv[] = { "test", "-o:filename.ext" }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |         parser.parseInto( sizeof(argv)/sizeof(char*), argv, config ); | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |         CHECK( config.fileName == "filename.ext" ); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-05-03 08:08:46 +01:00
										 |  |  |     SECTION( "plain filename with =" ) { | 
					
						
							|  |  |  |         const char* argv[] = { "test", "-o=filename.ext" }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |         parser.parseInto( sizeof(argv)/sizeof(char*), argv, config ); | 
					
						
							| 
									
										
										
										
											2013-05-03 08:08:46 +01:00
										 |  |  |         CHECK( config.fileName == "filename.ext" ); | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     SECTION( "long opt" ) { | 
					
						
							| 
									
										
										
										
											2013-05-03 08:08:46 +01:00
										 |  |  |         const char* argv[] = { "test", "--output %stdout" }; | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |         parser.parseInto( sizeof(argv)/sizeof(char*), argv, config ); | 
					
						
							|  |  |  |         CHECK( config.fileName == "%stdout" ); | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |     parser.bind( &TestOpt::number ) | 
					
						
							|  |  |  |             .shortOpt( "n" ) | 
					
						
							|  |  |  |             .argName( "<an integral value>" ); | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |      | 
					
						
							|  |  |  |     SECTION( "a number" ) { | 
					
						
							| 
									
										
										
										
											2013-05-03 08:08:46 +01:00
										 |  |  |         const char* argv[] = { "test", "-n 42" }; | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |         parser.parseInto( sizeof(argv)/sizeof(char*), argv, config ); | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |         CHECK( config.number == 42 ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     SECTION( "not a number" ) { | 
					
						
							| 
									
										
										
										
											2013-05-03 08:08:46 +01:00
										 |  |  |         const char* argv[] = { "test", "-n forty-two" }; | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |         CHECK_THROWS( parser.parseInto( sizeof(argv)/sizeof(char*), argv, config ) ); | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  |         CHECK( config.number == 0 ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2013-04-29 19:26:18 +01:00
										 |  |  |     SECTION( "two parsers" ) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         TestOpt config1; | 
					
						
							|  |  |  |         TestOpt2 config2; | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |         Clara::CommandLine<TestOpt2> parser2; | 
					
						
							| 
									
										
										
										
											2013-05-02 18:41:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |         parser2.bind( &TestOpt2::description ) | 
					
						
							|  |  |  |             .describe( "description" ) | 
					
						
							|  |  |  |             .shortOpt( "d" ) | 
					
						
							|  |  |  |             .longOpt( "description" ) | 
					
						
							|  |  |  |             .argName( "<some text>" ); | 
					
						
							| 
									
										
										
										
											2013-04-29 19:26:18 +01:00
										 |  |  |          | 
					
						
							| 
									
										
										
										
											2013-05-03 08:08:46 +01:00
										 |  |  |         const char* argv[] = { "test", "-n 42", "-d some text" }; | 
					
						
							| 
									
										
										
										
											2013-04-29 19:26:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |         parser.parseInto( sizeof(argv)/sizeof(char*), argv, config1 ); | 
					
						
							| 
									
										
										
										
											2013-04-29 19:26:18 +01:00
										 |  |  |         CHECK( config1.number == 42 ); | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // !TBD
 | 
					
						
							|  |  |  | //        parser2.parseRemainingArgs( parser, config2 );
 | 
					
						
							|  |  |  | //        CHECK( config2.description == "some text" );
 | 
					
						
							| 
									
										
										
										
											2013-04-29 19:26:18 +01:00
										 |  |  |          | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     SECTION( "methods" ) { | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |         parser.bind( &TestOpt::setValidIndex ) | 
					
						
							|  |  |  |             .describe( "An index, which is an integer between 0 and 10, inclusive" ) | 
					
						
							|  |  |  |             .shortOpt( "i" ) | 
					
						
							|  |  |  |             .argName( "<index>" ); | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         SECTION( "in range" ) { | 
					
						
							| 
									
										
										
										
											2013-05-03 08:08:46 +01:00
										 |  |  |             const char* argv[] = { "test", "-i 3" }; | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |             parser.parseInto( sizeof(argv)/sizeof(char*), argv, config ); | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  |             REQUIRE( config.index == 3 ); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         SECTION( "out of range" ) { | 
					
						
							| 
									
										
										
										
											2013-05-03 08:08:46 +01:00
										 |  |  |             const char* argv[] = { "test", "-i 42" }; | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |             REQUIRE_THROWS( parser.parseInto( sizeof(argv)/sizeof(char*), argv, config ) ); | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     SECTION( "flags" ) { | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |         parser.bind( &TestOpt::flag ) | 
					
						
							|  |  |  |             .describe( "A flag" ) | 
					
						
							|  |  |  |             .shortOpt( "f" ); | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  |          | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |         SECTION( "set" ) { | 
					
						
							|  |  |  |             const char* argv[] = { "test", "-f" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             parser.parseInto( sizeof(argv)/sizeof(char*), argv, config ); | 
					
						
							|  |  |  |             REQUIRE( config.flag ); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         SECTION( "not set" ) { | 
					
						
							|  |  |  |             const char* argv[] = { "test" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             parser.parseInto( sizeof(argv)/sizeof(char*), argv, config ); | 
					
						
							|  |  |  |             REQUIRE( config.flag == false ); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-05-01 19:01:48 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct Config { | 
					
						
							| 
									
										
										
										
											2013-05-16 08:21:13 +01:00
										 |  |  |     Config() | 
					
						
							|  |  |  |     :   listTests( false ), | 
					
						
							|  |  |  |         listTags( false ), | 
					
						
							|  |  |  |         showPassingTests( false ), | 
					
						
							|  |  |  |         breakIntoDebugger( false ), | 
					
						
							|  |  |  |         noThrow( false ), | 
					
						
							|  |  |  |         showHelp( false ), | 
					
						
							|  |  |  |         abortAfter( 0 ) | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |     bool listTests; | 
					
						
							|  |  |  |     bool listTags; | 
					
						
							|  |  |  |     bool showPassingTests; | 
					
						
							|  |  |  |     bool breakIntoDebugger; | 
					
						
							|  |  |  |     bool noThrow; | 
					
						
							|  |  |  |     bool showHelp; | 
					
						
							| 
									
										
										
										
											2013-04-29 19:26:18 +01:00
										 |  |  |      | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  |     int abortAfter; | 
					
						
							|  |  |  |     std::string reporterName; | 
					
						
							|  |  |  |     std::string fileName; | 
					
						
							|  |  |  |     std::string suiteName; | 
					
						
							|  |  |  |     std::vector<std::string> warnings; | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     void abortAfterFirst() { abortAfter = 1; } | 
					
						
							|  |  |  |     void abortAfterX( int x ) { abortAfter = x; } | 
					
						
							|  |  |  |     void addWarning( std::string const& _warning ) { warnings.push_back( _warning ); } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST_CASE( "growing new Catch cli" ) { | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  |     Clara::CommandLine<Config> parser; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser.bind( &Config::showHelp ) | 
					
						
							|  |  |  |         .describe( "display usage information" ) | 
					
						
							|  |  |  |         .shortOpt( "?") | 
					
						
							|  |  |  |         .shortOpt( "h") | 
					
						
							|  |  |  |         .longOpt( "help" ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser.bind( &Config::listTests ) | 
					
						
							|  |  |  |         .describe( "list all (or matching) test cases" ) | 
					
						
							|  |  |  |         .shortOpt( "l") | 
					
						
							|  |  |  |         .longOpt( "list" ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser.bind( &Config::listTags ) | 
					
						
							|  |  |  |         .describe( "list all (or matching) tags" ) | 
					
						
							|  |  |  |         .shortOpt( "t") | 
					
						
							|  |  |  |         .longOpt( "tags" ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser.bind( &Config::showPassingTests ) | 
					
						
							|  |  |  |         .describe( "show passing test output" ) | 
					
						
							|  |  |  |         .shortOpt( "p") | 
					
						
							|  |  |  |         .longOpt( "passing" ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser.bind( &Config::breakIntoDebugger ) | 
					
						
							|  |  |  |         .describe( "break into debugger on failure" ) | 
					
						
							|  |  |  |         .shortOpt( "b") | 
					
						
							|  |  |  |         .longOpt( "break" ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser.bind( &Config::noThrow ) | 
					
						
							|  |  |  |         .describe( "Skip exception tests" ) | 
					
						
							|  |  |  |         .shortOpt( "e") | 
					
						
							|  |  |  |         .longOpt( "nothrow" ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser.bind( &Config::fileName ) | 
					
						
							|  |  |  |         .describe( "output filename" ) | 
					
						
							|  |  |  |         .shortOpt( "o") | 
					
						
							|  |  |  |         .longOpt( "out" ) | 
					
						
							|  |  |  |         .argName( "file name" ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser.bind( &Config::suiteName ) | 
					
						
							|  |  |  |         .describe( "suite name" ) | 
					
						
							|  |  |  |         .shortOpt( "n") | 
					
						
							|  |  |  |         .longOpt( "name" ) | 
					
						
							|  |  |  |         .argName( "name" ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser.bind( &Config::abortAfterFirst ) | 
					
						
							|  |  |  |         .describe( "abort at first failure" ) | 
					
						
							|  |  |  |         .shortOpt( "a") | 
					
						
							|  |  |  |         .longOpt( "abort" ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser.bind( &Config::abortAfterX ) | 
					
						
							|  |  |  |         .describe( "abort after x failures" ) | 
					
						
							|  |  |  |         .shortOpt( "x") | 
					
						
							|  |  |  |         .longOpt( "abortx" ) | 
					
						
							|  |  |  |         .argName( "number of failures" ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser.bind( &Config::addWarning ) | 
					
						
							|  |  |  |         .describe( "enables warnings" ) | 
					
						
							|  |  |  |         .shortOpt( "w") | 
					
						
							|  |  |  |         .longOpt( "warn" ) | 
					
						
							|  |  |  |         .argName( "warning name" ); | 
					
						
							| 
									
										
										
										
											2013-05-07 18:53:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     std::cout << parser << std::endl; | 
					
						
							| 
									
										
										
										
											2013-05-16 08:21:13 +01:00
										 |  |  |      | 
					
						
							|  |  |  |     Config config; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const char* argv[] = { "test", "-peb" }; | 
					
						
							|  |  |  |     int argc = sizeof(argv)/sizeof(char*); | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     parser.parseInto( argc, argv, config ); | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     CHECK( config.showPassingTests ); | 
					
						
							|  |  |  |     CHECK( config.noThrow ); | 
					
						
							|  |  |  |     CHECK( config.breakIntoDebugger ); | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //        REQUIRE_THROWS( parser.parseInto( sizeof(argv)/sizeof(char*), argv, config ) );
 | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2013-04-27 12:26:13 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-15 19:25:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // !TBD still support this?
 | 
					
						
							|  |  |  | //    Clara::Parser<Config>
 | 
					
						
							|  |  |  | //        ( "-h, --help                         display usage information",           &Config::showHelp )
 | 
					
						
							|  |  |  | //        ( "-l, --list                         list all (or matching) test cases",   &Config::listTests )
 | 
					
						
							|  |  |  | //        ( "-t, --tags                         list all (or matching) tags",         &Config::listTags )
 | 
					
						
							|  |  |  | //        ( "-p, --passing                      show passing test output",            &Config::showPassingTests )
 | 
					
						
							|  |  |  | //        ( "-b, --break                        break into debugger on failure",      &Config::breakIntoDebugger )
 | 
					
						
							|  |  |  | //        ( "-e, --nothrow                      Skip exception tests",                &Config::noThrow )
 | 
					
						
							|  |  |  | //        ( "-o, --out <file name>              output filename",                     &Config::fileName )
 | 
					
						
							|  |  |  | //        ( "-n, --name <name>                  suite name",                          &Config::suiteName )
 | 
					
						
							|  |  |  | //        ( "-a, --abort                        abort at first failure",              &Config::abortAfterFirst )
 | 
					
						
							|  |  |  | //        ( "-x, --abortx <number of failures>  abort after x failures",              &Config::abortAfterX )
 | 
					
						
							|  |  |  | //        ( "-w, --warn <warning name>          enables warnings",                    &Config::addWarning );
 | 
					
						
							|  |  |  | //        .parseInto( argc, argv, config );
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-14 19:31:21 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 |