diff --git a/README.md b/README.md index 14a391d0..a621a74c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![catch logo](catch-logo-small.png) -*v1.0 build 25 (master branch)* +*v1.0 build 26 (master branch)* Build status (on Travis CI) [![Build Status](https://travis-ci.org/philsquared/Catch.png)](https://travis-ci.org/philsquared/Catch) diff --git a/include/catch_runner.hpp b/include/catch_runner.hpp index f2495e56..913d2699 100644 --- a/include/catch_runner.hpp +++ b/include/catch_runner.hpp @@ -8,12 +8,12 @@ #ifndef TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED +#include "internal/catch_text.h" #include "internal/catch_commandline.hpp" #include "internal/catch_list.hpp" #include "internal/catch_runner_impl.hpp" #include "internal/catch_test_spec.h" #include "internal/catch_version.h" -#include "internal/catch_text.h" #include #include diff --git a/include/internal/catch_clara.h b/include/internal/catch_clara.h new file mode 100644 index 00000000..d9ecbed1 --- /dev/null +++ b/include/internal/catch_clara.h @@ -0,0 +1,20 @@ +/* + * Created by Phil on 10/2/2014. + * Copyright 2014 Two Blue Cubes Ltd. All rights reserved. + * + * 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) + * + */ +#ifndef TWOBLUECUBES_CATCH_CLARA_H_INCLUDED +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + + +// Declare Clara inside the Catch namespace +#define CLICHE_CLARA_OUTER_NAMESPACE Catch +#include "clara.h" +#undef CLICHE_CLARA_OUTER_NAMESPACE + +#endif // TWOBLUECUBES_CATCH_CLARA_H_INCLUDED diff --git a/include/internal/catch_commandline.hpp b/include/internal/catch_commandline.hpp index 5b80761f..ee19de85 100644 --- a/include/internal/catch_commandline.hpp +++ b/include/internal/catch_commandline.hpp @@ -10,7 +10,7 @@ #include "catch_config.hpp" #include "catch_common.h" -#include "clara.h" +#include "catch_clara.h" #include diff --git a/include/internal/catch_impl.hpp b/include/internal/catch_impl.hpp index 01522355..e19c159f 100644 --- a/include/internal/catch_impl.hpp +++ b/include/internal/catch_impl.hpp @@ -28,7 +28,6 @@ #include "catch_tags.hpp" #include "catch_test_spec.hpp" #include "catch_version.hpp" -#include "catch_text.hpp" #include "catch_message.hpp" #include "catch_legacy_reporter_adapter.hpp" #include "catch_timer.hpp" diff --git a/include/internal/catch_text.h b/include/internal/catch_text.h index e713f7b7..4657f744 100644 --- a/include/internal/catch_text.h +++ b/include/internal/catch_text.h @@ -1,6 +1,6 @@ /* - * Created by Phil on 18/4/2013. - * Copyright 2013 Two Blue Cubes Ltd. All rights reserved. + * Created by Phil on 10/2/2014. + * Copyright 2014 Two Blue Cubes Ltd. All rights reserved. * * 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) @@ -10,52 +10,15 @@ #include "catch_config.hpp" -#include -#include +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +#include "tbc_text_format.h" +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE namespace Catch { - - struct TextAttributes { - TextAttributes() - : initialIndent( std::string::npos ), - indent( 0 ), - width( CATCH_CONFIG_CONSOLE_WIDTH-1 ), - tabChar( '\t' ) - {} - - TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } - TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } - TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } - TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } - - std::size_t initialIndent; // indent of first line, or npos - std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos - std::size_t width; // maximum width of text, including indent. Longer text will wrap - char tabChar; // If this char is seen the indent is changed to current pos - }; - - class Text { - public: - Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ); - void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ); - - typedef std::vector::const_iterator const_iterator; - - const_iterator begin() const { return lines.begin(); } - const_iterator end() const { return lines.end(); } - std::string const& last() const { return lines.back(); } - std::size_t size() const { return lines.size(); } - std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } - std::string toString() const; - - friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ); - - private: - std::string str; - TextAttributes attr; - std::vector lines; - }; - -} // end namespace Catch + using Tbc::Text; + using Tbc::TextAttributes; +} #endif // TWOBLUECUBES_CATCH_TEXT_H_INCLUDED diff --git a/include/internal/catch_text.hpp b/include/internal/catch_text.hpp deleted file mode 100644 index 03cc05ef..00000000 --- a/include/internal/catch_text.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Created by Phil on 20/4/2013. - * Copyright 2013 Two Blue Cubes Ltd. All rights reserved. - * - * 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) - */ -#ifndef TWOBLUECUBES_CATCH_TEXT_HPP_INCLUDED -#define TWOBLUECUBES_CATCH_TEXT_HPP_INCLUDED - -#include -#include - -namespace Catch { - - INTERNAL_CATCH_INLINE Text::Text( std::string const& _str, TextAttributes const& _attr ) - : attr( _attr ) - { - std::string wrappableChars = " [({.,/|\\-"; - std::size_t indent = _attr.initialIndent != std::string::npos - ? _attr.initialIndent - : _attr.indent; - std::string remainder = _str; - - while( !remainder.empty() ) { - if( lines.size() >= 1000 ) { - lines.push_back( "... message truncated due to excessive size" ); - return; - } - std::size_t tabPos = std::string::npos; - std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); - std::size_t pos = remainder.find_first_of( '\n' ); - if( pos <= width ) { - width = pos; - } - pos = remainder.find_last_of( _attr.tabChar, width ); - if( pos != std::string::npos ) { - tabPos = pos; - if( remainder[width] == '\n' ) - width--; - remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); - } - - if( width == remainder.size() ) { - spliceLine( indent, remainder, width ); - } - else if( remainder[width] == '\n' ) { - spliceLine( indent, remainder, width ); - if( width <= 1 || remainder.size() != 1 ) - remainder = remainder.substr( 1 ); - indent = _attr.indent; - } - else { - pos = remainder.find_last_of( wrappableChars, width ); - if( pos != std::string::npos && pos > 0 ) { - spliceLine( indent, remainder, pos ); - if( remainder[0] == ' ' ) - remainder = remainder.substr( 1 ); - } - else { - spliceLine( indent, remainder, width-1 ); - lines.back() += "-"; - } - if( lines.size() == 1 ) - indent = _attr.indent; - if( tabPos != std::string::npos ) - indent += tabPos; - } - } - } - - INTERNAL_CATCH_INLINE void Text::spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { - lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); - _remainder = _remainder.substr( _pos ); - } - - INTERNAL_CATCH_INLINE std::string Text::toString() const { - std::ostringstream oss; - oss << *this; - return oss.str(); - } - - INTERNAL_CATCH_INLINE std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { - for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); - it != itEnd; ++it ) { - if( it != _text.begin() ) - _stream << "\n"; - _stream << *it; - } - return _stream; - } - -} // end namespace Catch - -#endif // TWOBLUECUBES_CATCH_TEXT_HPP_INCLUDED diff --git a/include/internal/catch_version.hpp b/include/internal/catch_version.hpp index c970ee3c..ae5ece83 100644 --- a/include/internal/catch_version.hpp +++ b/include/internal/catch_version.hpp @@ -14,7 +14,7 @@ namespace Catch { // These numbers are maintained by a script template - const T LibraryVersionInfo::value( 1, 0, 25, "master" ); + const T LibraryVersionInfo::value( 1, 0, 26, "master" ); } #endif // TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED diff --git a/include/internal/catch_vs_test_registry.hpp b/include/internal/catch_vs_test_registry.hpp index d2e80d61..1eced33a 100644 --- a/include/internal/catch_vs_test_registry.hpp +++ b/include/internal/catch_vs_test_registry.hpp @@ -463,8 +463,6 @@ private: #include "catch_assertionresult.hpp" #include "catch_expressionresult_builder.hpp" #include "catch_version.hpp" -#include "catch_text.h" -#include "catch_text.hpp" #include "catch_runner_impl.hpp" #include "catch_message.hpp" #include "catch_context_impl.hpp" diff --git a/include/internal/clara.h b/include/internal/clara.h index b44d129a..5b79e04c 100644 --- a/include/internal/clara.h +++ b/include/internal/clara.h @@ -5,13 +5,48 @@ * 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) */ -#ifndef TWOBLUECUBES_CLARA_H_INCLUDED -#define TWOBLUECUBES_CLARA_H_INCLUDED -#include "catch_text.h" // This will get moved out too +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_CLARA_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_CLARA_H_INCLUDED +# ifndef TWOBLUECUBES_CLARA_H_ALREADY_INCLUDED +# define TWOBLUECUBES_CLARA_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_CLARA_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_CLARA_H_ALREADY_INCLUDED + +#ifndef CLICHE_CLARA_OUTER_NAMESPACE +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Clara +#include "tbc_text_format.h" +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#endif + +#include +#include +#include +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_CLARA_OUTER_NAMESPACE +namespace CLICHE_CLARA_OUTER_NAMESPACE { +#endif namespace Clara { namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + using namespace Tbc; + template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; @@ -401,18 +436,18 @@ namespace Clara { m_boundProcessName = Detail::makeBoundField( f ); } - void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = CATCH_CONFIG_CONSOLE_WIDTH ) const { + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; std::size_t maxWidth = 0; for( it = itBegin; it != itEnd; ++it ) maxWidth = (std::max)( maxWidth, it->commands().size() ); for( it = itBegin; it != itEnd; ++it ) { - Catch::Text usage( it->commands(), Catch::TextAttributes() + Detail::Text usage( it->commands(), Detail::TextAttributes() .setWidth( maxWidth+indent ) .setIndent( indent ) ); // !TBD handle longer usage strings - Catch::Text desc( it->description, Catch::TextAttributes() + Detail::Text desc( it->description, Detail::TextAttributes() .setWidth( width - maxWidth -3 ) ); for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { @@ -582,5 +617,9 @@ namespace Clara { } // end namespace Clara +#ifdef CLICHE_CLARA_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_CLARA_H_ALREADY_INCLUDED -#endif // TWOBLUECUBES_CLARA_H_INCLUDED diff --git a/include/internal/tbc_text_format.h b/include/internal/tbc_text_format.h new file mode 100644 index 00000000..a63d6a14 --- /dev/null +++ b/include/internal/tbc_text_format.h @@ -0,0 +1,153 @@ +/* + * Created by Phil on 18/4/2013. + * Copyright 2013 Two Blue Cubes Ltd. All rights reserved. + * + * 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) + */ +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED diff --git a/include/reporters/catch_reporter_bases.hpp b/include/reporters/catch_reporter_bases.hpp index 21e70980..ee255406 100644 --- a/include/reporters/catch_reporter_bases.hpp +++ b/include/reporters/catch_reporter_bases.hpp @@ -99,6 +99,8 @@ namespace Catch { return node->stats.sectionInfo.lineInfo == m_other.lineInfo; } private: + BySectionInfo& operator=( BySectionInfo const& other ); // = delete; + SectionInfo const& m_other; }; diff --git a/projects/SelfTest/CmdLineTests.cpp b/projects/SelfTest/CmdLineTests.cpp index 3eb54d2f..8d003fed 100644 --- a/projects/SelfTest/CmdLineTests.cpp +++ b/projects/SelfTest/CmdLineTests.cpp @@ -9,7 +9,7 @@ #pragma clang diagnostic ignored "-Wpadded" #endif -#include "internal/clara.h" +#include "internal/clara.h" // This will does not declare Clara within the Catch namespace #include "catch.hpp" diff --git a/projects/SelfTest/TestMain.cpp b/projects/SelfTest/TestMain.cpp index 0b8ede82..9ed89634 100644 --- a/projects/SelfTest/TestMain.cpp +++ b/projects/SelfTest/TestMain.cpp @@ -18,7 +18,7 @@ template void parseIntoConfig( const char * (&argv)[size], Catch::ConfigData& config ) { - Clara::CommandLine parser = Catch::makeCommandLineParser(); + Catch::Clara::CommandLine parser = Catch::makeCommandLineParser(); parser.parseInto( size, argv, config ); } diff --git a/projects/SelfTest/makefile b/projects/SelfTest/makefile index 2954e370..41bdc6a1 100644 --- a/projects/SelfTest/makefile +++ b/projects/SelfTest/makefile @@ -1,5 +1,7 @@ SOURCES = ApproxTests.cpp \ + BDDTests.cpp \ ClassTests.cpp \ + CmdLineTests.cpp \ ConditionTests.cpp \ ExceptionTests.cpp \ GeneratorTests.cpp \ @@ -7,7 +9,6 @@ SOURCES = ApproxTests.cpp \ MiscTests.cpp \ TestMain.cpp \ TrickyTests.cpp \ - BDDTests.cpp \ VariadicMacrosTests.cpp OBJECTS = $(patsubst %.cpp, %.o, $(SOURCES)) CXX = g++ diff --git a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj index e61b82de..4c3d6af2 100644 --- a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj +++ b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj @@ -77,6 +77,8 @@ 26847E5B16BBAB790043B9C1 /* catch_message.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_message.h; sourceTree = ""; }; 26847E5C16BBACB60043B9C1 /* catch_message.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_message.hpp; sourceTree = ""; }; 26847E5D16BBADB40043B9C1 /* catch_message.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_message.cpp; path = ../../../SelfTest/SurrogateCpps/catch_message.cpp; sourceTree = ""; }; + 268F47B018A93F7800D8C14F /* catch_clara.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_clara.h; sourceTree = ""; }; + 268F47B118A944DB00D8C14F /* tbc_text_format.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tbc_text_format.h; path = ../../../../include/internal/tbc_text_format.h; sourceTree = ""; }; 26948284179A9AB900ED166E /* SectionTrackerTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SectionTrackerTests.cpp; path = ../../../SelfTest/SectionTrackerTests.cpp; sourceTree = ""; }; 26948287179EF7F900ED166E /* catch_test_case_tracker.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_test_case_tracker.hpp; sourceTree = ""; }; 2694A1FB16A0000E004816E3 /* catch_text.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = catch_text.cpp; sourceTree = ""; }; @@ -201,6 +203,7 @@ isa = PBXGroup; children = ( 26C5F3EC17514B970056FB3C /* clara.h */, + 268F47B118A944DB00D8C14F /* tbc_text_format.h */, ); name = External; sourceTree = ""; @@ -438,6 +441,7 @@ 26AEAF1617BEA18E009E32C9 /* catch_platform.h */, 262E739A1846759000CAC268 /* catch_common.hpp */, 261488FC184D1DC10041FBEB /* catch_stream.h */, + 268F47B018A93F7800D8C14F /* catch_clara.h */, ); name = Infrastructure; sourceTree = ""; diff --git a/projects/XCode4/CatchSelfTest/CatchSelfTestSingle.xcodeproj/project.pbxproj b/projects/XCode4/CatchSelfTest/CatchSelfTestSingle.xcodeproj/project.pbxproj index 209296a4..1eee6eb6 100644 --- a/projects/XCode4/CatchSelfTest/CatchSelfTestSingle.xcodeproj/project.pbxproj +++ b/projects/XCode4/CatchSelfTest/CatchSelfTestSingle.xcodeproj/project.pbxproj @@ -128,7 +128,7 @@ 4A90B5CD15D2E3E900EF71BC /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0440; + LastUpgradeCheck = 0500; ORGANIZATIONNAME = "Phil Nash"; }; buildConfigurationList = 4A90B5D015D2E3E900EF71BC /* Build configuration list for PBXProject "CatchSelfTestSingle" */; @@ -172,7 +172,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; @@ -199,7 +198,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; diff --git a/scripts/generateSingleHeader.py b/scripts/generateSingleHeader.py index 88d12986..82c85296 100644 --- a/scripts/generateSingleHeader.py +++ b/scripts/generateSingleHeader.py @@ -8,10 +8,10 @@ from scriptCommon import catchPath versionParser = re.compile( r'(\s*const\sT\sLibraryVersionInfo::value)\s*\(\s*(.*)\s*,\s*(.*)\s*,\s*(.*)\s*,\s*\"(.*)\"\s*\).*' ) includesParser = re.compile( r'\s*#include\s*"(.*)"' ) -guardParser = re.compile( r'\s*#.*_INCLUDED') +guardParser = re.compile( r'\s*#.*TWOBLUECUBES_CATCH_.*_INCLUDED') defineParser = re.compile( r'\s*#define') -ifParser = re.compile( r'\s*#if') -endIfParser = re.compile( r'\s*#endif') +ifParser = re.compile( r'\s*#ifndef TWOBLUECUBES_CATCH_.*_INCLUDED') +endIfParser = re.compile( r'\s*#endif // TWOBLUECUBES_CATCH_.*_INCLUDED') ifImplParser = re.compile( r'\s*#if.*(CATCH_CONFIG_MAIN|CATCH_CONFIG_RUNNER)') commentParser1 = re.compile( r'^\s*/\*') commentParser2 = re.compile( r'^\s*\*') @@ -62,7 +62,8 @@ def parseFile( path, filename ): header = m.group(1) headerPath, sep, headerFile = header.rpartition( "/" ) if not headerFile in seenHeaders: - seenHeaders.add( headerFile ) + if headerFile != "tbc_text_format.h" and headerFile != "clara.h": + seenHeaders.add( headerFile ) write( "// #included from: {0}\n".format( header ) ) if( headerPath == "internal" and path.endswith( "internal/" ) ): headerPath = "" diff --git a/single_include/catch.hpp b/single_include/catch.hpp index 24868a68..8469fcfe 100644 --- a/single_include/catch.hpp +++ b/single_include/catch.hpp @@ -1,6 +1,6 @@ /* - * CATCH v1.0 build 25 (master branch) - * Generated: 2014-01-23 10:56:27.233000 + * CATCH v1.0 build 26 (master branch) + * Generated: 2014-02-20 15:47:53.508000 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. @@ -3996,21 +3996,55 @@ namespace Catch { } // #included from: internal/clara.h -#define TWOBLUECUBES_CLARA_H_INCLUDED -// #included from: catch_text.h -#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_CLARA_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_CLARA_H_INCLUDED +# ifndef TWOBLUECUBES_CLARA_H_ALREADY_INCLUDED +# define TWOBLUECUBES_CLARA_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_CLARA_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_CLARA_H_ALREADY_INCLUDED +#ifndef CLICHE_CLARA_OUTER_NAMESPACE +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Clara +// #included from: tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED #include #include +#include -namespace Catch { +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif struct TextAttributes { TextAttributes() : initialIndent( std::string::npos ), indent( 0 ), - width( CATCH_CONFIG_CONSOLE_WIDTH-1 ), + width( consoleWidth-1 ), tabChar( '\t' ) {} @@ -4027,8 +4061,66 @@ namespace Catch { class Text { public: - Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ); - void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ); + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } typedef std::vector::const_iterator const_iterator; @@ -4037,9 +4129,21 @@ namespace Catch { std::string const& last() const { return lines.back(); } std::size_t size() const { return lines.size(); } std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } - std::string toString() const; + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } - friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ); + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } private: std::string str; @@ -4047,10 +4151,39 @@ namespace Catch { std::vector lines; }; -} // end namespace Catch +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#endif + +#include +#include +#include +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_CLARA_OUTER_NAMESPACE +namespace CLICHE_CLARA_OUTER_NAMESPACE { +#endif namespace Clara { namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + using namespace Tbc; + template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; template struct RemoveConstRef{ typedef T type; }; @@ -4439,18 +4572,18 @@ namespace Clara { m_boundProcessName = Detail::makeBoundField( f ); } - void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = CATCH_CONFIG_CONSOLE_WIDTH ) const { + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; std::size_t maxWidth = 0; for( it = itBegin; it != itEnd; ++it ) maxWidth = (std::max)( maxWidth, it->commands().size() ); for( it = itBegin; it != itEnd; ++it ) { - Catch::Text usage( it->commands(), Catch::TextAttributes() + Detail::Text usage( it->commands(), Detail::TextAttributes() .setWidth( maxWidth+indent ) .setIndent( indent ) ); // !TBD handle longer usage strings - Catch::Text desc( it->description, Catch::TextAttributes() + Detail::Text desc( it->description, Detail::TextAttributes() .setWidth( width - maxWidth -3 ) ); for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { @@ -4620,6 +4753,12 @@ namespace Clara { } // end namespace Clara +#ifdef CLICHE_CLARA_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_CLARA_H_ALREADY_INCLUDED + #include namespace Catch { @@ -5389,96 +5528,9 @@ namespace Catch { // These numbers are maintained by a script template - const T LibraryVersionInfo::value( 1, 0, 25, "master" ); + const T LibraryVersionInfo::value( 1, 0, 26, "master" ); } -// #included from: catch_text.hpp -#define TWOBLUECUBES_CATCH_TEXT_HPP_INCLUDED - -#include -#include - -namespace Catch { - - INTERNAL_CATCH_INLINE Text::Text( std::string const& _str, TextAttributes const& _attr ) - : attr( _attr ) - { - std::string wrappableChars = " [({.,/|\\-"; - std::size_t indent = _attr.initialIndent != std::string::npos - ? _attr.initialIndent - : _attr.indent; - std::string remainder = _str; - - while( !remainder.empty() ) { - if( lines.size() >= 1000 ) { - lines.push_back( "... message truncated due to excessive size" ); - return; - } - std::size_t tabPos = std::string::npos; - std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); - std::size_t pos = remainder.find_first_of( '\n' ); - if( pos <= width ) { - width = pos; - } - pos = remainder.find_last_of( _attr.tabChar, width ); - if( pos != std::string::npos ) { - tabPos = pos; - if( remainder[width] == '\n' ) - width--; - remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); - } - - if( width == remainder.size() ) { - spliceLine( indent, remainder, width ); - } - else if( remainder[width] == '\n' ) { - spliceLine( indent, remainder, width ); - if( width <= 1 || remainder.size() != 1 ) - remainder = remainder.substr( 1 ); - indent = _attr.indent; - } - else { - pos = remainder.find_last_of( wrappableChars, width ); - if( pos != std::string::npos && pos > 0 ) { - spliceLine( indent, remainder, pos ); - if( remainder[0] == ' ' ) - remainder = remainder.substr( 1 ); - } - else { - spliceLine( indent, remainder, width-1 ); - lines.back() += "-"; - } - if( lines.size() == 1 ) - indent = _attr.indent; - if( tabPos != std::string::npos ) - indent += tabPos; - } - } - } - - INTERNAL_CATCH_INLINE void Text::spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { - lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); - _remainder = _remainder.substr( _pos ); - } - - INTERNAL_CATCH_INLINE std::string Text::toString() const { - std::ostringstream oss; - oss << *this; - return oss.str(); - } - - INTERNAL_CATCH_INLINE std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { - for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); - it != itEnd; ++it ) { - if( it != _text.begin() ) - _stream << "\n"; - _stream << *it; - } - return _stream; - } - -} // end namespace Catch - // #included from: catch_runner_impl.hpp #define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED @@ -6524,6 +6576,166 @@ namespace Catch { // #included from: reporters/catch_vs_reporter.hpp #define TWOBLUECUBES_CATCH_REPORTER_MSTEST_HPP_INCLUDED +// #included from: ../internal/catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + // #included from: ../internal/catch_console_colour.hpp #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED @@ -7603,6 +7815,779 @@ namespace Catch { // #included from: internal/catch_commandline.hpp #define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define CLICHE_CLARA_OUTER_NAMESPACE Catch +// #included from: clara.h + +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_CLARA_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_CLARA_H_INCLUDED +# ifndef TWOBLUECUBES_CLARA_H_ALREADY_INCLUDED +# define TWOBLUECUBES_CLARA_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_CLARA_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_CLARA_H_ALREADY_INCLUDED + +#ifndef CLICHE_CLARA_OUTER_NAMESPACE +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Clara +// #included from: tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#endif + +#include +#include +#include +#include +#include +#include + +// Use optional outer namespace +#ifdef CLICHE_CLARA_OUTER_NAMESPACE +namespace CLICHE_CLARA_OUTER_NAMESPACE { +#endif + +namespace Clara { + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + using namespace Tbc; + + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + template struct RemoveConstRef{ typedef T type; }; + + template struct IsBool { static const bool value = false; }; + template<> struct IsBool { static const bool value = true; }; + + template + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); + } + inline void convertInto( bool _source, bool& _dest ) { + _dest = _source; + } + template + inline void convertInto( bool, T& ) { + throw std::runtime_error( "Invalid conversion" ); + } + + template + struct IArgFunction { + virtual ~IArgFunction() {} + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual void setFlag( ConfigT& config ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; + }; + + template + class BoundArgFunction { + public: + BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj->clone() ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction* newFunctionObj = other.functionObj->clone(); + delete functionObj; + functionObj = newFunctionObj; + return *this; + } + ~BoundArgFunction() { delete functionObj; } + + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + void setFlag( ConfigT& config ) const { + functionObj->setFlag( config ); + } + bool takesArg() const { return functionObj->takesArg(); } + private: + IArgFunction* functionObj; + }; + + template + struct NullBinder : IArgFunction{ + virtual void set( C&, std::string const& ) const {} + virtual void setFlag( C& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction* clone() const { return new NullBinder( *this ); } + }; + + template + struct BoundDataMember : IArgFunction{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); + } + virtual void setFlag( C& p ) const { + convertInto( true, p.*member ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template + struct BoundUnaryMethod : IArgFunction{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + (p.*member)( value ); + } + virtual void setFlag( C& p ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + (p.*member)( value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template + struct BoundNullaryMethod : IArgFunction{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual void setFlag( C& p ) const { + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; + + template + struct BoundUnaryFunction : IArgFunction{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual void setFlag( C& p ) const { + function( p ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; + + template + struct BoundBinaryFunction : IArgFunction{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual void setFlag( C& obj ) const { + typename RemoveConstRef::type value; + convertInto( true, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool::value; } + virtual IArgFunction* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; + + template + BoundArgFunction makeBoundField( M C::* _member ) { + return BoundArgFunction( new BoundDataMember( _member ) ); + } + template + BoundArgFunction makeBoundField( void (C::*_member)( M ) ) { + return BoundArgFunction( new BoundUnaryMethod( _member ) ); + } + template + BoundArgFunction makeBoundField( void (C::*_member)() ) { + return BoundArgFunction( new BoundNullaryMethod( _member ) ); + } + template + BoundArgFunction makeBoundField( void (*_function)( C& ) ) { + return BoundArgFunction( new BoundUnaryFunction( _function ) ); + } + template + BoundArgFunction makeBoundField( void (*_function)( C&, T ) ) { + return BoundArgFunction( new BoundBinaryFunction( _function ) ); + } + } // namespace Detail + + struct Parser { + Parser() : separators( " \t=:" ) {} + + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + void parseIntoTokens( int argc, char const * const * argv, std::vector& tokens ) const { + const std::string doubleDash = "--"; + for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) + parseIntoTokens( argv[i] , tokens); + } + void parseIntoTokens( std::string arg, std::vector& tokens ) const { + while( !arg.empty() ) { + Parser::Token token( Parser::Token::Positional, arg ); + arg = ""; + if( token.data[0] == '-' ) { + if( token.data.size() > 1 && token.data[1] == '-' ) { + token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); + } + else { + token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); + if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { + arg = "-" + token.data.substr( 1 ); + token.data = token.data.substr( 0, 1 ); + } + } + } + if( token.type != Parser::Token::Positional ) { + std::size_t pos = token.data.find_first_of( separators ); + if( pos != std::string::npos ) { + arg = token.data.substr( pos+1 ); + token.data = token.data.substr( 0, pos ); + } + } + tokens.push_back( token ); + } + } + std::string separators; + }; + + template + class CommandLine { + + struct Arg { + Arg( Detail::BoundArgFunction const& _boundField ) : boundField( _boundField ), position( -1 ) {} + + bool hasShortName( std::string const& shortName ) const { + for( std::vector::const_iterator + it = shortNames.begin(), itEnd = shortNames.end(); + it != itEnd; + ++it ) + if( *it == shortName ) + return true; + return false; + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + bool takesArg() const { + return !hint.empty(); + } + bool isFixedPositional() const { + return position != -1; + } + bool isAnyPositional() const { + return position == -1 && shortNames.empty() && longName.empty(); + } + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + void validate() const { + if( boundField.takesArg() && !takesArg() ) + throw std::logic_error( dbgName() + " must specify an arg name" ); + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !hint.empty() ) + oss << " <" << hint << ">"; + return oss.str(); + } + + Detail::BoundArgFunction boundField; + std::vector shortNames; + std::string longName; + std::string description; + std::string hint; + int position; + }; + + // NOTE: std::auto_ptr is deprecated in c++11/c++0x +#if defined(__cplusplus) && __cplusplus > 199711L + typedef std::unique_ptr ArgAutoPtr; +#else + typedef std::auto_ptr ArgAutoPtr; +#endif + + class ArgBinder { + public: + template + ArgBinder( CommandLine* cl, F f ) + : m_cl( cl ), + m_arg( Detail::makeBoundField( f ) ) + {} + ArgBinder( ArgBinder& other ) + : m_cl( other.m_cl ), + m_arg( other.m_arg ) + { + other.m_cl = NULL; + } + ~ArgBinder() { + if( m_cl ) { + m_arg.validate(); + if( m_arg.isFixedPositional() ) { + m_cl->m_positionalArgs.insert( std::make_pair( m_arg.position, m_arg ) ); + if( m_arg.position > m_cl->m_highestSpecifiedArgPosition ) + m_cl->m_highestSpecifiedArgPosition = m_arg.position; + } + else if( m_arg.isAnyPositional() ) { + if( m_cl->m_arg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_cl->m_arg = ArgAutoPtr( new Arg( m_arg ) ); + } + else + m_cl->m_options.push_back( m_arg ); + } + } + ArgBinder& shortOpt( std::string const& name ) { + m_arg.shortNames.push_back( name ); + return *this; + } + ArgBinder& longOpt( std::string const& name ) { + m_arg.longName = name; + return *this; + } + ArgBinder& describe( std::string const& description ) { + m_arg.description = description; + return *this; + } + ArgBinder& hint( std::string const& hint ) { + m_arg.hint = hint; + return *this; + } + ArgBinder& position( int position ) { + m_arg.position = position; + return *this; + } + private: + CommandLine* m_cl; + Arg m_arg; + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_arg.get() ) + m_arg = ArgAutoPtr( new Arg( *other.m_arg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + template + ArgBinder bind( F f ) { + ArgBinder binder( this, f ); + return binder; + } + template + void bindProcessName( F f ) { + m_boundProcessName = Detail::makeBoundField( f ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + // !TBD handle longer usage strings + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth -3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.hint << ">"; + else if( m_arg.get() ) + os << "<" << m_arg->hint << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_arg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_arg->hint << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + std::vector parseInto( int argc, char const * const * argv, ConfigT& config ) const { + std::string processName = argv[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector tokens; + Parser parser; + parser.parseIntoTokens( argc, argv, tokens ); + return populate( tokens, config ); + } + + std::vector populate( std::vector const& tokens, ConfigT& config ) const { + if( m_options.empty() && m_positionalArgs.empty() ) + throw std::logic_error( "No options or arguments specified" ); + + std::vector unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector populateOptions( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + std::vector errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.setFlag( config ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector populateFixedArgs( std::vector const& tokens, ConfigT& config ) const { + std::vector unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector populateFloatingArgs( std::vector const& tokens, ConfigT& config ) const { + if( !m_arg.get() ) + return tokens; + std::vector unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_arg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + private: + Detail::BoundArgFunction m_boundProcessName; + std::vector m_options; + std::map m_positionalArgs; + ArgAutoPtr m_arg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +#ifdef CLICHE_CLARA_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_CLARA_H_ALREADY_INCLUDED + +#undef CLICHE_CLARA_OUTER_NAMESPACE + #include namespace Catch { @@ -8393,6 +9378,8 @@ namespace Catch { return node->stats.sectionInfo.lineInfo == m_other.lineInfo; } private: + BySectionInfo& operator=( BySectionInfo const& other ); // = delete; + SectionInfo const& m_other; };