From b9fea75109c4d4c372067b651a2df9733b748879 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Thu, 6 Mar 2014 08:16:06 +0000 Subject: [PATCH] =?UTF-8?q?New=20version=20of=20Clara.=20-=20updated=20com?= =?UTF-8?q?mand=20line=20setup=20with=20new=20API=20-=20updated=20STITCH?= =?UTF-8?q?=20macros=20-=20force=20embedded=20Clara=20to=20use=20Catch?= =?UTF-8?q?=E2=80=99s=20console=20width=20(but=20restore=20it=20after)=20-?= =?UTF-8?q?=20remove=20command=20line=20tests=20(as=20these=20have=20now?= =?UTF-8?q?=20moved=20into=20the=20Clara=20project)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/internal/catch_clara.h | 16 +- include/internal/catch_commandline.hpp | 109 +++---- include/internal/clara.h | 157 +++++++--- projects/SelfTest/CmdLineTests.cpp | 192 ------------ .../CatchSelfTest.xcodeproj/project.pbxproj | 4 - single_include/catch.hpp | 276 +++++++++++------- 6 files changed, 348 insertions(+), 406 deletions(-) delete mode 100644 projects/SelfTest/CmdLineTests.cpp diff --git a/include/internal/catch_clara.h b/include/internal/catch_clara.h index a07bb624..e1f0c25a 100644 --- a/include/internal/catch_clara.h +++ b/include/internal/catch_clara.h @@ -9,12 +9,24 @@ #ifndef TWOBLUECUBES_CATCH_CLARA_H_INCLUDED #define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH // Declare Clara inside the Catch namespace -#define STITCH_CLARA_OUTER_NAMESPACE Catch +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { #include "clara.h" -#undef STITCH_CLARA_OUTER_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE + + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif #endif // TWOBLUECUBES_CATCH_CLARA_H_INCLUDED diff --git a/include/internal/catch_commandline.hpp b/include/internal/catch_commandline.hpp index ee19de85..126c861c 100644 --- a/include/internal/catch_commandline.hpp +++ b/include/internal/catch_commandline.hpp @@ -55,108 +55,95 @@ namespace Catch { inline Clara::CommandLine makeCommandLineParser() { - Clara::CommandLine cli; + using namespace Clara; + CommandLine cli; cli.bindProcessName( &ConfigData::processName ); - cli.bind( &ConfigData::showHelp ) + cli["-?"]["-h"]["--help"] .describe( "display usage information" ) - .shortOpt( "?") - .shortOpt( "h") - .longOpt( "help" ); + .into( &ConfigData::showHelp ); - cli.bind( &ConfigData::listTests ) + cli["-l"]["--list-tests"] .describe( "list all/matching test cases" ) - .shortOpt( "l") - .longOpt( "list-tests" ); + .into( &ConfigData::listTests ); - cli.bind( &ConfigData::listTags ) + cli["-t"]["--list-tags"] .describe( "list all/matching tags" ) - .shortOpt( "t") - .longOpt( "list-tags" ); + .into( &ConfigData::listTags ); - cli.bind( &ConfigData::showSuccessfulTests ) + cli["-s"]["--success"] .describe( "include successful tests in output" ) - .shortOpt( "s") - .longOpt( "success" ); + .into( &ConfigData::showSuccessfulTests ); - cli.bind( &ConfigData::shouldDebugBreak ) + cli["-b"]["--break"] .describe( "break into debugger on failure" ) - .shortOpt( "b") - .longOpt( "break" ); + .into( &ConfigData::shouldDebugBreak ); - cli.bind( &ConfigData::noThrow ) + cli["-e"]["--nothrow"] .describe( "skip exception tests" ) - .shortOpt( "e") - .longOpt( "nothrow" ); + .into( &ConfigData::noThrow ); - cli.bind( &ConfigData::outputFilename ) + cli["-o"]["--out"] + .placeholder( "filename" ) .describe( "output filename" ) - .shortOpt( "o") - .longOpt( "out" ) - .hint( "filename" ); + .into( &ConfigData::outputFilename ); - cli.bind( &ConfigData::reporterName ) + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .placeholder( "name" ) .describe( "reporter to use (defaults to console)" ) - .shortOpt( "r") - .longOpt( "reporter" ) -// .hint( "name[:filename]" ); - .hint( "name" ); + .into( &ConfigData::reporterName ); - cli.bind( &ConfigData::name ) + cli["-n"]["--name"] + .placeholder( "name" ) .describe( "suite name" ) - .shortOpt( "n") - .longOpt( "name" ) - .hint( "name" ); + .into( &ConfigData::name ); - cli.bind( &abortAfterFirst ) + cli["-a"]["--abort"] .describe( "abort at first failure" ) - .shortOpt( "a") - .longOpt( "abort" ); + .into( &abortAfterFirst ); - cli.bind( &abortAfterX ) + cli["-x"]["--abortx"] + .placeholder( "number of failures" ) .describe( "abort after x failures" ) - .shortOpt( "x") - .longOpt( "abortx" ) - .hint( "number of failures" ); + .into( &abortAfterX ); - cli.bind( &addWarning ) + cli["-w"]["--warn"] + .placeholder( "warning name" ) .describe( "enable warnings" ) - .shortOpt( "w") - .longOpt( "warn" ) - .hint( "warning name" ); + .into( &addWarning ); -// cli.bind( &setVerbosity ) +// - needs updating if reinstated +// cli.into( &setVerbosity ) // .describe( "level of verbosity (0=no output)" ) // .shortOpt( "v") // .longOpt( "verbosity" ) -// .hint( "level" ); +// .placeholder( "level" ); - cli.bind( &addTestOrTags ) + cli[_] + .placeholder( "test name, pattern or tags" ) .describe( "which test or tests to use" ) - .hint( "test name, pattern or tags" ); + .into( &addTestOrTags ); - cli.bind( &setShowDurations ) + cli["-d"]["--durations"] + .placeholder( "yes/no" ) .describe( "show test durations" ) - .shortOpt( "d") - .longOpt( "durations" ) - .hint( "yes/no" ); + .into( &setShowDurations ); - cli.bind( &loadTestNamesFromFile ) + cli["-f"]["--input-file"] + .placeholder( "filename" ) .describe( "load test names to run from a file" ) - .shortOpt( "f") - .longOpt( "input-file" ) - .hint( "filename" ); + .into( &loadTestNamesFromFile ); // Less common commands which don't have a short form - cli.bind( &ConfigData::listTestNamesOnly ) + cli["--list-test-names-only"] .describe( "list all/matching test cases names only" ) - .longOpt( "list-test-names-only" ); + .into( &ConfigData::listTestNamesOnly ); - cli.bind( &ConfigData::listReporters ) + cli["--list-reporters"] .describe( "list all reporters" ) - .longOpt( "list-reporters" ); - + .into( &ConfigData::listReporters ); return cli; } diff --git a/include/internal/clara.h b/include/internal/clara.h index 41e7c221..476f2343 100644 --- a/include/internal/clara.h +++ b/include/internal/clara.h @@ -7,12 +7,18 @@ */ // Only use header guard if we are not using an outer namespace -#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OUTER_NAMESPACE) -#ifndef STITCH_CLARA_OUTER_NAMESPACE +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE #define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } #endif -#define STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE Clara + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE // ----------- #included from tbc_text_format.h ----------- @@ -168,7 +174,7 @@ namespace Tbc { // ----------- end of #include from tbc_text_format.h ----------- // ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h -#undef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE #include #include @@ -176,11 +182,20 @@ namespace Tbc { #include // Use optional outer namespace -#ifdef STITCH_CLARA_OUTER_NAMESPACE -namespace STITCH_CLARA_OUTER_NAMESPACE { +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE #endif namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + namespace Detail { #ifdef CLARA_CONSOLE_WIDTH @@ -189,7 +204,11 @@ namespace Clara { const unsigned int consoleWidth = 80; #endif - using namespace ::Clara::Tbc; + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; @@ -240,6 +259,7 @@ namespace Clara { template class BoundArgFunction { public: + BoundArgFunction() : functionObj( NULL ) {} BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj->clone() ) {} BoundArgFunction& operator = ( BoundArgFunction const& other ) { @@ -422,6 +442,7 @@ namespace Clara { class CommandLine { struct Arg { + Arg() : position( -1 ) {} Arg( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ), position( -1 ) {} bool hasShortName( std::string const& shortName ) const { @@ -437,7 +458,7 @@ namespace Clara { return _longName == longName; } bool takesArg() const { - return !hint.empty(); + return !placeholder.empty(); } bool isFixedPositional() const { return position != -1; @@ -454,7 +475,7 @@ namespace Clara { } void validate() const { if( boundField.takesArg() && !takesArg() ) - throw std::logic_error( "command line argument '" + dbgName() + "' must specify a hint" ); + throw std::logic_error( "command line argument '" + dbgName() + "' must specify a placeholder" ); } std::string commands() const { std::ostringstream oss; @@ -472,8 +493,8 @@ namespace Clara { oss << ", "; oss << "--" << longName; } - if( !hint.empty() ) - oss << " <" << hint << ">"; + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; return oss.str(); } @@ -481,7 +502,7 @@ namespace Clara { std::vector shortNames; std::string longName; std::string description; - std::string hint; + std::string placeholder; int position; }; @@ -492,14 +513,14 @@ namespace Clara { typedef std::auto_ptr ArgAutoPtr; #endif - class ArgBinder { + class ArgBuilder { public: - template - ArgBinder( CommandLine* cl, F f ) - : m_cl( cl ), - m_arg( Detail::makeBoundField( f ) ) + ArgBuilder( CommandLine* cl ) + : m_cl( cl ) {} - ArgBinder( ArgBinder& other ) + + + ArgBuilder( ArgBuilder& other ) : m_cl( other.m_cl ), m_arg( other.m_arg ) { @@ -507,7 +528,7 @@ namespace Clara { } // !TBD: Need to include workarounds to be able to declare this // destructor as able to throw exceptions - ~ArgBinder() /* noexcept(false) */ { + ~ArgBuilder() /* noexcept(false) */ { if( m_cl && !std::uncaught_exception() ) { m_arg.validate(); if( m_arg.isFixedPositional() ) { @@ -524,30 +545,66 @@ namespace Clara { m_cl->m_options.push_back( m_arg ); } } - ArgBinder& shortOpt( std::string const& name ) { - m_arg.shortNames.push_back( name ); + + template + void into( F f ) + { + m_arg.boundField = Detail::makeBoundField( f ); + } + + friend void addOptName( ArgBuilder& builder, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !builder.m_arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + builder.m_arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + builder.m_arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + builder.m_arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( ArgBuilder& builder, int position ) + { + builder.m_arg.position = position; + } + + + // Can only supply placeholder after [str] - if it takes an arg + ArgBuilder& placeholder( std::string const& placeholder ) { + m_arg.placeholder = placeholder; return *this; } - ArgBinder& longOpt( std::string const& name ) { - m_arg.longName = name; - return *this; - } - ArgBinder& describe( std::string const& description ) { + + ArgBuilder& describe( std::string const& description ) { m_arg.description = description; return *this; } - ArgBinder& hint( std::string const& hint ) { - m_arg.hint = hint; - return *this; - } - ArgBinder& position( int position ) { - m_arg.position = position; + ArgBuilder& detail( std::string const& ) { +// m_arg.description = description; +// !TBD return *this; } + private: CommandLine* m_cl; Arg m_arg; }; + class OptBuilder : public ArgBuilder { + public: + OptBuilder( CommandLine* cl ) : ArgBuilder( cl ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *this, optName ); + return *this; + } + }; public: @@ -572,11 +629,25 @@ namespace Clara { return *this; } - template - ArgBinder bind( F f ) { - ArgBinder binder( this, f ); - return binder; + + OptBuilder operator[]( std::string const& optName ) { + OptBuilder builder( this ); + addOptName( builder, optName ); + return builder; } + + ArgBuilder operator[]( int position ) { + ArgBuilder builder( this ); + setPositionalArg( builder, position ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + ArgBuilder builder( this ); + return builder; + } + template void bindProcessName( F f ) { m_boundProcessName = Detail::makeBoundField( f ); @@ -619,9 +690,9 @@ namespace Clara { os << " "; typename std::map::const_iterator it = m_positionalArgs.find( i ); if( it != m_positionalArgs.end() ) - os << "<" << it->second.hint << ">"; + os << "<" << it->second.placeholder << ">"; else if( m_arg.get() ) - os << "<" << m_arg->hint << ">"; + os << "<" << m_arg->placeholder << ">"; else throw std::logic_error( "non consecutive positional arguments with no floating args" ); } @@ -629,7 +700,7 @@ namespace Clara { if( m_arg.get() ) { if( m_highestSpecifiedArgPosition > 1 ) os << " "; - os << "[<" << m_arg->hint << "> ...]"; + os << "[<" << m_arg->placeholder << "> ...]"; } } std::string argSynopsis() const { @@ -769,8 +840,10 @@ namespace Clara { } // end namespace Clara -#ifdef STITCH_CLARA_OUTER_NAMESPACE -} // end outer namespace -#endif + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + #endif // TWOBLUECUBES_CLARA_H_INCLUDED diff --git a/projects/SelfTest/CmdLineTests.cpp b/projects/SelfTest/CmdLineTests.cpp deleted file mode 100644 index 8d003fed..00000000 --- a/projects/SelfTest/CmdLineTests.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - * 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 "internal/clara.h" // This will does not declare Clara within the Catch namespace - -#include "catch.hpp" - - -// Helper to deduce size from array literals and pass on to parser -template -std::vector parseInto( Clara::CommandLine& cli, char const * (&argv)[size], ConfigT& config ) { - return cli.parseInto( size, argv, config ); -} - - -struct TestOpt { - TestOpt() : number( 0 ), index( 0 ), flag( false ) {} - - std::string processName; - std::string fileName; - int number; - int index; - bool flag; - std::string firstPos; - std::string secondPos; - std::string unpositional; - - void setValidIndex( int i ) { - if( i < 0 || i > 10 ) - throw std::domain_error( "index must be between 0 and 10" ); - index = i; - } -}; - -struct TestOpt2 { - std::string description; -}; - -#ifdef CATCH_CONFIG_VARIADIC_MACROS - -TEST_CASE( "cmdline" ) { - - TestOpt config; - Clara::CommandLine cli; - cli.bindProcessName( &TestOpt::processName ); - cli.bind( &TestOpt::fileName ) - .describe( "specifies output file" ) - .shortOpt( "o" ) - .longOpt( "output" ) - .hint( "filename" ); - - SECTION( "process name" ) { - char const * argv[] = { "test", "-o filename.ext" }; - parseInto( cli, argv, config ); - - CHECK( config.processName == "test" ); - } - SECTION( "arg separated by spaces" ) { - char const * argv[] = { "test", "-o filename.ext" }; - parseInto( cli, argv, config ); - - CHECK( config.fileName == "filename.ext" ); - } - SECTION( "arg separated by colon" ) { - const char* argv[] = { "test", "-o:filename.ext" }; - parseInto( cli, argv, config ); - - CHECK( config.fileName == "filename.ext" ); - } - SECTION( "arg separated by =" ) { - const char* argv[] = { "test", "-o=filename.ext" }; - parseInto( cli, argv, config ); - - CHECK( config.fileName == "filename.ext" ); - } - SECTION( "long opt" ) { - const char* argv[] = { "test", "--output %stdout" }; - parseInto( cli, argv, config ); - - CHECK( config.fileName == "%stdout" ); - } - - cli.bind( &TestOpt::number ) - .shortOpt( "n" ) - .hint( "an integral value" ); - - SECTION( "a number" ) { - const char* argv[] = { "test", "-n 42" }; - parseInto( cli, argv, config ); - - CHECK( config.number == 42 ); - } - SECTION( "not a number" ) { - const char* argv[] = { "test", "-n forty-two" }; - CHECK_THROWS( parseInto( cli, argv, config ) ); - - CHECK( config.number == 0 ); - } - - SECTION( "two parsers" ) { - - TestOpt config1; - TestOpt2 config2; - Clara::CommandLine cli2; - - cli2.bind( &TestOpt2::description ) - .describe( "description" ) - .shortOpt( "d" ) - .longOpt( "description" ) - .hint( "some text" ); - - const char* argv[] = { "test", "-n 42", "-d some text" }; - std::vector unusedTokens = parseInto( cli, argv, config1 ); - - CHECK( config1.number == 42 ); - - REQUIRE_FALSE( unusedTokens.empty() ); - cli2.populate( unusedTokens, config2 ); - CHECK( config2.description == "some text" ); - } - - SECTION( "methods" ) { - cli.bind( &TestOpt::setValidIndex ) - .describe( "An index, which is an integer between 0 and 10, inclusive" ) - .shortOpt( "i" ) - .hint( "index" ); - - SECTION( "in range" ) { - const char* argv[] = { "test", "-i 3" }; - parseInto( cli, argv, config ); - - REQUIRE( config.index == 3 ); - } - SECTION( "out of range" ) { - const char* argv[] = { "test", "-i 42" }; - - REQUIRE_THROWS( parseInto( cli, argv, config ) ); - } - } - - SECTION( "flags" ) { - cli.bind( &TestOpt::flag ) - .describe( "A flag" ) - .shortOpt( "f" ); - - SECTION( "set" ) { - const char* argv[] = { "test", "-f" }; - parseInto( cli, argv, config ); - - REQUIRE( config.flag ); - } - SECTION( "not set" ) { - const char* argv[] = { "test" }; - parseInto( cli, argv, config ); - - REQUIRE( config.flag == false ); - } - } - SECTION( "positional" ) { - cli.bind( &TestOpt::secondPos ) - .describe( "Second position" ) - .hint( "second arg" ) - .position( 2 ); - cli.bind( &TestOpt::unpositional ) - .hint( "any arg" ) - .describe( "Unpositional" ); - cli.bind( &TestOpt::firstPos ) - .describe( "First position" ) - .hint( "first arg" ) - .position( 1 ); - -// std::cout << cli.usage( "testApp" ) << std::endl; - - const char* argv[] = { "test", "-f", "1st", "-o", "filename", "2nd", "3rd" }; - parseInto( cli, argv, config ); - - REQUIRE( config.firstPos == "1st" ); - REQUIRE( config.secondPos == "2nd" ); - REQUIRE( config.unpositional == "3rd" ); - } -} - - -#endif diff --git a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj index 4c3d6af2..03225a7f 100644 --- a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj +++ b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ 266B06B816F3A60A004ED264 /* VariadicMacrosTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266B06B616F3A60A004ED264 /* VariadicMacrosTests.cpp */; }; - 266E9AD617290E8E0061DAB2 /* CmdLineTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266E9AD417290E8E0061DAB2 /* CmdLineTests.cpp */; }; 266ECD74170F3C620030D735 /* BDDTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266ECD73170F3C620030D735 /* BDDTests.cpp */; }; 26847E5F16BBADB40043B9C1 /* catch_message.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26847E5D16BBADB40043B9C1 /* catch_message.cpp */; }; 26948286179A9AB900ED166E /* SectionTrackerTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26948284179A9AB900ED166E /* SectionTrackerTests.cpp */; }; @@ -68,7 +67,6 @@ 263FD06117AF8DF200988A20 /* catch_timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_timer.h; sourceTree = ""; }; 266B06B616F3A60A004ED264 /* VariadicMacrosTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VariadicMacrosTests.cpp; path = ../../../SelfTest/VariadicMacrosTests.cpp; sourceTree = ""; }; 266E9AD117230ACF0061DAB2 /* catch_text.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_text.hpp; sourceTree = ""; }; - 266E9AD417290E8E0061DAB2 /* CmdLineTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CmdLineTests.cpp; path = ../../../SelfTest/CmdLineTests.cpp; sourceTree = ""; }; 266ECD73170F3C620030D735 /* BDDTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BDDTests.cpp; path = ../../../SelfTest/BDDTests.cpp; sourceTree = ""; }; 266ECD8C1713614B0030D735 /* catch_legacy_reporter_adapter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_legacy_reporter_adapter.hpp; sourceTree = ""; }; 266ECD8D1713614B0030D735 /* catch_legacy_reporter_adapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_legacy_reporter_adapter.h; sourceTree = ""; }; @@ -193,7 +191,6 @@ 266E9AD317290E710061DAB2 /* Introspective Tests */ = { isa = PBXGroup; children = ( - 266E9AD417290E8E0061DAB2 /* CmdLineTests.cpp */, 26948284179A9AB900ED166E /* SectionTrackerTests.cpp */, ); name = "Introspective Tests"; @@ -535,7 +532,6 @@ 26847E5F16BBADB40043B9C1 /* catch_message.cpp in Sources */, 266B06B816F3A60A004ED264 /* VariadicMacrosTests.cpp in Sources */, 266ECD74170F3C620030D735 /* BDDTests.cpp in Sources */, - 266E9AD617290E8E0061DAB2 /* CmdLineTests.cpp in Sources */, 26948286179A9AB900ED166E /* SectionTrackerTests.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/single_include/catch.hpp b/single_include/catch.hpp index 108bbdb5..88f00889 100644 --- a/single_include/catch.hpp +++ b/single_include/catch.hpp @@ -1,6 +1,6 @@ /* * CATCH v1.0 build 27 (master branch) - * Generated: 2014-03-01 10:36:25.999888 + * Generated: 2014-03-06 08:06:07.489513 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. @@ -3005,19 +3005,29 @@ namespace Catch { // #included from: catch_clara.h #define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH // Declare Clara inside the Catch namespace -#define STITCH_CLARA_OUTER_NAMESPACE Catch +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { // #included from: clara.h // Only use header guard if we are not using an outer namespace -#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OUTER_NAMESPACE) -#ifndef STITCH_CLARA_OUTER_NAMESPACE +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE #define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } #endif -#define STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE Clara +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE // ----------- #included from tbc_text_format.h ----------- @@ -3166,7 +3176,7 @@ namespace Tbc { // ----------- end of #include from tbc_text_format.h ----------- // ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h -#undef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE #include #include @@ -3174,11 +3184,20 @@ namespace Tbc { #include // Use optional outer namespace -#ifdef STITCH_CLARA_OUTER_NAMESPACE -namespace STITCH_CLARA_OUTER_NAMESPACE { +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE #endif namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + namespace Detail { #ifdef CLARA_CONSOLE_WIDTH @@ -3187,7 +3206,11 @@ namespace Clara { const unsigned int consoleWidth = 80; #endif - using namespace ::Clara::Tbc; + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; @@ -3238,6 +3261,7 @@ namespace Clara { template class BoundArgFunction { public: + BoundArgFunction() : functionObj( NULL ) {} BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj->clone() ) {} BoundArgFunction& operator = ( BoundArgFunction const& other ) { @@ -3419,6 +3443,7 @@ namespace Clara { class CommandLine { struct Arg { + Arg() : position( -1 ) {} Arg( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ), position( -1 ) {} bool hasShortName( std::string const& shortName ) const { @@ -3434,7 +3459,7 @@ namespace Clara { return _longName == longName; } bool takesArg() const { - return !hint.empty(); + return !placeholder.empty(); } bool isFixedPositional() const { return position != -1; @@ -3451,7 +3476,7 @@ namespace Clara { } void validate() const { if( boundField.takesArg() && !takesArg() ) - throw std::logic_error( "command line argument '" + dbgName() + "' must specify a hint" ); + throw std::logic_error( "command line argument '" + dbgName() + "' must specify a placeholder" ); } std::string commands() const { std::ostringstream oss; @@ -3469,8 +3494,8 @@ namespace Clara { oss << ", "; oss << "--" << longName; } - if( !hint.empty() ) - oss << " <" << hint << ">"; + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; return oss.str(); } @@ -3478,7 +3503,7 @@ namespace Clara { std::vector shortNames; std::string longName; std::string description; - std::string hint; + std::string placeholder; int position; }; @@ -3489,14 +3514,13 @@ namespace Clara { typedef std::auto_ptr ArgAutoPtr; #endif - class ArgBinder { + class ArgBuilder { public: - template - ArgBinder( CommandLine* cl, F f ) - : m_cl( cl ), - m_arg( Detail::makeBoundField( f ) ) + ArgBuilder( CommandLine* cl ) + : m_cl( cl ) {} - ArgBinder( ArgBinder& other ) + + ArgBuilder( ArgBuilder& other ) : m_cl( other.m_cl ), m_arg( other.m_arg ) { @@ -3504,7 +3528,7 @@ namespace Clara { } // !TBD: Need to include workarounds to be able to declare this // destructor as able to throw exceptions - ~ArgBinder() /* noexcept(false) */ { + ~ArgBuilder() /* noexcept(false) */ { if( m_cl && !std::uncaught_exception() ) { m_arg.validate(); if( m_arg.isFixedPositional() ) { @@ -3521,30 +3545,65 @@ namespace Clara { m_cl->m_options.push_back( m_arg ); } } - ArgBinder& shortOpt( std::string const& name ) { - m_arg.shortNames.push_back( name ); + + template + void into( F f ) + { + m_arg.boundField = Detail::makeBoundField( f ); + } + + friend void addOptName( ArgBuilder& builder, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !builder.m_arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + builder.m_arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + builder.m_arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + builder.m_arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( ArgBuilder& builder, int position ) + { + builder.m_arg.position = position; + } + + // Can only supply placeholder after [str] - if it takes an arg + ArgBuilder& placeholder( std::string const& placeholder ) { + m_arg.placeholder = placeholder; return *this; } - ArgBinder& longOpt( std::string const& name ) { - m_arg.longName = name; - return *this; - } - ArgBinder& describe( std::string const& description ) { + + ArgBuilder& describe( std::string const& description ) { m_arg.description = description; return *this; } - ArgBinder& hint( std::string const& hint ) { - m_arg.hint = hint; - return *this; - } - ArgBinder& position( int position ) { - m_arg.position = position; + ArgBuilder& detail( std::string const& ) { +// m_arg.description = description; +// !TBD return *this; } + private: CommandLine* m_cl; Arg m_arg; }; + class OptBuilder : public ArgBuilder { + public: + OptBuilder( CommandLine* cl ) : ArgBuilder( cl ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *this, optName ); + return *this; + } + }; public: @@ -3569,11 +3628,24 @@ namespace Clara { return *this; } - template - ArgBinder bind( F f ) { - ArgBinder binder( this, f ); - return binder; + OptBuilder operator[]( std::string const& optName ) { + OptBuilder builder( this ); + addOptName( builder, optName ); + return builder; } + + ArgBuilder operator[]( int position ) { + ArgBuilder builder( this ); + setPositionalArg( builder, position ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + ArgBuilder builder( this ); + return builder; + } + template void bindProcessName( F f ) { m_boundProcessName = Detail::makeBoundField( f ); @@ -3616,9 +3688,9 @@ namespace Clara { os << " "; typename std::map::const_iterator it = m_positionalArgs.find( i ); if( it != m_positionalArgs.end() ) - os << "<" << it->second.hint << ">"; + os << "<" << it->second.placeholder << ">"; else if( m_arg.get() ) - os << "<" << m_arg->hint << ">"; + os << "<" << m_arg->placeholder << ">"; else throw std::logic_error( "non consecutive positional arguments with no floating args" ); } @@ -3626,7 +3698,7 @@ namespace Clara { if( m_arg.get() ) { if( m_highestSpecifiedArgPosition > 1 ) os << " "; - os << "[<" << m_arg->hint << "> ...]"; + os << "[<" << m_arg->placeholder << "> ...]"; } } std::string argSynopsis() const { @@ -3766,12 +3838,18 @@ namespace Clara { } // end namespace Clara -#ifdef STITCH_CLARA_OUTER_NAMESPACE -} // end outer namespace -#endif +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE #endif // TWOBLUECUBES_CLARA_H_INCLUDED -#undef STITCH_CLARA_OUTER_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif #include @@ -3816,107 +3894,95 @@ namespace Catch { inline Clara::CommandLine makeCommandLineParser() { - Clara::CommandLine cli; + using namespace Clara; + CommandLine cli; cli.bindProcessName( &ConfigData::processName ); - cli.bind( &ConfigData::showHelp ) + cli["-?"]["-h"]["--help"] .describe( "display usage information" ) - .shortOpt( "?") - .shortOpt( "h") - .longOpt( "help" ); + .into( &ConfigData::showHelp ); - cli.bind( &ConfigData::listTests ) + cli["-l"]["--list-tests"] .describe( "list all/matching test cases" ) - .shortOpt( "l") - .longOpt( "list-tests" ); + .into( &ConfigData::listTests ); - cli.bind( &ConfigData::listTags ) + cli["-t"]["--list-tags"] .describe( "list all/matching tags" ) - .shortOpt( "t") - .longOpt( "list-tags" ); + .into( &ConfigData::listTags ); - cli.bind( &ConfigData::showSuccessfulTests ) + cli["-s"]["--success"] .describe( "include successful tests in output" ) - .shortOpt( "s") - .longOpt( "success" ); + .into( &ConfigData::showSuccessfulTests ); - cli.bind( &ConfigData::shouldDebugBreak ) + cli["-b"]["--break"] .describe( "break into debugger on failure" ) - .shortOpt( "b") - .longOpt( "break" ); + .into( &ConfigData::shouldDebugBreak ); - cli.bind( &ConfigData::noThrow ) + cli["-e"]["--nothrow"] .describe( "skip exception tests" ) - .shortOpt( "e") - .longOpt( "nothrow" ); + .into( &ConfigData::noThrow ); - cli.bind( &ConfigData::outputFilename ) + cli["-o"]["--out"] + .placeholder( "filename" ) .describe( "output filename" ) - .shortOpt( "o") - .longOpt( "out" ) - .hint( "filename" ); + .into( &ConfigData::outputFilename ); - cli.bind( &ConfigData::reporterName ) + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .placeholder( "name" ) .describe( "reporter to use (defaults to console)" ) - .shortOpt( "r") - .longOpt( "reporter" ) -// .hint( "name[:filename]" ); - .hint( "name" ); + .into( &ConfigData::reporterName ); - cli.bind( &ConfigData::name ) + cli["-n"]["--name"] + .placeholder( "name" ) .describe( "suite name" ) - .shortOpt( "n") - .longOpt( "name" ) - .hint( "name" ); + .into( &ConfigData::name ); - cli.bind( &abortAfterFirst ) + cli["-a"]["--abort"] .describe( "abort at first failure" ) - .shortOpt( "a") - .longOpt( "abort" ); + .into( &abortAfterFirst ); - cli.bind( &abortAfterX ) + cli["-x"]["--abortx"] + .placeholder( "number of failures" ) .describe( "abort after x failures" ) - .shortOpt( "x") - .longOpt( "abortx" ) - .hint( "number of failures" ); + .into( &abortAfterX ); - cli.bind( &addWarning ) + cli["-w"]["--warn"] + .placeholder( "warning name" ) .describe( "enable warnings" ) - .shortOpt( "w") - .longOpt( "warn" ) - .hint( "warning name" ); + .into( &addWarning ); -// cli.bind( &setVerbosity ) +// - needs updating if reinstated +// cli.into( &setVerbosity ) // .describe( "level of verbosity (0=no output)" ) // .shortOpt( "v") // .longOpt( "verbosity" ) -// .hint( "level" ); +// .placeholder( "level" ); - cli.bind( &addTestOrTags ) + cli[_] + .placeholder( "test name, pattern or tags" ) .describe( "which test or tests to use" ) - .hint( "test name, pattern or tags" ); + .into( &addTestOrTags ); - cli.bind( &setShowDurations ) + cli["-d"]["--durations"] + .placeholder( "yes/no" ) .describe( "show test durations" ) - .shortOpt( "d") - .longOpt( "durations" ) - .hint( "yes/no" ); + .into( &setShowDurations ); - cli.bind( &loadTestNamesFromFile ) + cli["-f"]["--input-file"] + .placeholder( "filename" ) .describe( "load test names to run from a file" ) - .shortOpt( "f") - .longOpt( "input-file" ) - .hint( "filename" ); + .into( &loadTestNamesFromFile ); // Less common commands which don't have a short form - cli.bind( &ConfigData::listTestNamesOnly ) + cli["--list-test-names-only"] .describe( "list all/matching test cases names only" ) - .longOpt( "list-test-names-only" ); + .into( &ConfigData::listTestNamesOnly ); - cli.bind( &ConfigData::listReporters ) + cli["--list-reporters"] .describe( "list all reporters" ) - .longOpt( "list-reporters" ); + .into( &ConfigData::listReporters ); return cli; }