Refactored string wrapper

- to be much more flexible (writes to vector)
- fixed a couple of bugs
This commit is contained in:
Phil Nash 2013-03-27 19:08:16 +00:00
parent dd26e889b5
commit b052bd729a
6 changed files with 806 additions and 316 deletions

View File

@ -161,7 +161,7 @@ namespace Catch {
displayedSpecificOption = true; displayedSpecificOption = true;
std::cout << "\n" << opt.optionNames() << " " << opt.argsSynopsis() << "\n\n" std::cout << "\n" << opt.optionNames() << " " << opt.argsSynopsis() << "\n\n"
<< opt.optionSummary() << "\n\n" << opt.optionSummary() << "\n\n"
<< wrapLongStrings( opt.optionDescription(), 80, 2 ) << "\n" << std::endl; << LineWrapper().setIndent( 2 ).wrap( opt.optionDescription() ).toString() << "\n" << std::endl;
} }
} }

View File

@ -9,11 +9,39 @@
#define TWOBLUECUBES_CATCH_LINE_WRAP_H_INCLUDED #define TWOBLUECUBES_CATCH_LINE_WRAP_H_INCLUDED
#include <string> #include <string>
#include <vector>
namespace Catch { namespace Catch {
void wrapLongStrings( std::ostream& stream, const std::string& str, std::size_t columns, std::size_t indent = 0 ); class LineWrapper {
std::string wrapLongStrings( const std::string& str, std::size_t columns, std::size_t indent = 0 ); public:
LineWrapper( std::size_t _indent, std::size_t _right );
LineWrapper( std::size_t _right );
LineWrapper();
LineWrapper& setIndent( std::size_t _indent );
LineWrapper& setRight( std::size_t _right );
LineWrapper& wrap( std::string const& _str );
std::ostream& intoStream( std::ostream& stream ) const;
std::string toString() const;
typedef std::vector<std::string>::const_iterator const_iterator;
const_iterator begin() const { return lines.begin(); }
const_iterator end() const { return lines.end(); }
private:
void wrapInternal( std::string const& _str );
void addLine( const std::string& _line );
std::string indent;
std::size_t right;
std::size_t nextTab;
std::size_t tab;
std::vector<std::string> lines;
};
} // end namespace Catch } // end namespace Catch

View File

@ -12,60 +12,91 @@
namespace Catch { namespace Catch {
namespace {
inline void addIndent( std::ostream& os, std::size_t indent ) {
while( indent-- > 0 )
os << ' ';
}
inline void recursivelyWrapLine( std::ostream& os, std::string paragraph, std::size_t columns, std::size_t indent ) { LineWrapper::LineWrapper( std::size_t _indent, std::size_t _right )
std::size_t width = columns-indent; : indent( _indent, ' ' ),
std::size_t tab = 0; right( _right ),
std::size_t wrapPoint = width; nextTab( 0 ),
for( std::size_t pos = 0; pos < paragraph.size(); ++pos ) { tab( 0 )
if( pos == width ) { {}
addIndent( os, indent ); LineWrapper::LineWrapper( std::size_t _right )
if( paragraph[wrapPoint] == ' ' ) { : right( _right ),
os << paragraph.substr( 0, wrapPoint ) << "\n"; nextTab( 0 ),
while( paragraph[++wrapPoint] == ' ' ); tab( 0 )
{}
LineWrapper::LineWrapper()
: right( CATCH_CONFIG_CONSOLE_WIDTH-1 ),
nextTab( 0 ),
tab( 0 )
{}
LineWrapper& LineWrapper::setIndent( std::size_t _indent ) {
indent = std::string( _indent, ' ' );
return *this;
}
LineWrapper& LineWrapper::setRight( std::size_t _right ) {
right = _right;
return *this;
}
LineWrapper& LineWrapper::wrap( std::string const& _str ) {
nextTab = tab = 0;
wrapInternal( _str );
return *this;
}
void LineWrapper::wrapInternal( std::string const& _str ) {
std::size_t width = right - indent.size();
std::size_t wrapPoint = width-tab;
for( std::size_t pos = 0; pos < _str.size(); ++pos ) {
if( _str[pos] == '\n' )
{
addLine( _str.substr( 0, pos ) );
nextTab = tab = 0;
return wrapInternal( _str.substr( pos+1 ) );
}
if( pos == width-tab ) {
if( _str[wrapPoint] == ' ' ) {
addLine( _str.substr( 0, wrapPoint ) );
while( _str[++wrapPoint] == ' ' );
} }
else { else {
os << paragraph.substr( 0, --wrapPoint ) << "-\n"; addLine( _str.substr( 0, --wrapPoint ) + '-' );
} }
return recursivelyWrapLine( os, paragraph.substr( wrapPoint ), columns, indent+tab ); return wrapInternal( _str.substr( wrapPoint ) );
} }
if( paragraph[pos] == '\t' ) { if( _str[pos] == '\t' ) {
tab = pos; nextTab = pos;
paragraph = paragraph.substr( 0, tab ) + paragraph.substr( tab+1 ); std::string withoutTab = _str.substr( 0, nextTab ) + _str.substr( nextTab+1 );
pos--; return wrapInternal( withoutTab );
} }
else if( paragraph[pos] == ' ' ) { else if( _str[pos] == ' ' ) {
wrapPoint = pos; wrapPoint = pos;
} }
} }
addIndent( os, indent ); addLine( _str );
os << paragraph;
}
} }
void wrapLongStrings( std::ostream& stream, const std::string& str, std::size_t columns, std::size_t indent ) { std::ostream& LineWrapper::intoStream( std::ostream& stream ) const {
std::string::size_type pos = 0; for( const_iterator it = begin(), itEnd = end();
std::string::size_type newline = str.find_first_of( '\n' ); it != itEnd; ++it ) {
while( newline != std::string::npos ) { if( it != begin() )
std::string paragraph = str.substr( pos, newline-pos );
recursivelyWrapLine( stream, paragraph, columns, indent );
stream << "\n"; stream << "\n";
pos = newline+1; stream << *it;
newline = str.find_first_of( '\n', pos );
} }
if( pos != str.size() ) return stream;
recursivelyWrapLine( stream, str.substr( pos, str.size()-pos ), columns, indent ); }
std::string LineWrapper::toString() const {
std::ostringstream oss;
intoStream( oss );
return oss.str();
} }
std::string wrapLongStrings( const std::string& str, std::size_t columns, std::size_t indent ) { void LineWrapper::addLine( const std::string& _line ) {
std::ostringstream oss; if( tab > 0 )
wrapLongStrings( oss, str, columns, indent ); lines.push_back( indent + std::string( tab, ' ' ) + _line );
return oss.str(); else
lines.push_back( indent + _line );
if( nextTab > 0 )
tab = nextTab;
} }
} // end namespace Catch } // end namespace Catch

View File

@ -211,7 +211,7 @@ namespace Catch {
if( result.hasExpandedExpression() ) { if( result.hasExpandedExpression() ) {
stream << "with expansion:\n"; stream << "with expansion:\n";
TextColour colourGuard( TextColour::ReconstructedExpression ); TextColour colourGuard( TextColour::ReconstructedExpression );
stream << wrapLongStrings( result.getExpandedExpression() ) << "\n"; stream << LineWrapper().setIndent(2).wrap( result.getExpandedExpression() ).toString() << "\n";
} }
} }
void printMessage() const { void printMessage() const {
@ -220,7 +220,8 @@ namespace Catch {
for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end(); for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
it != itEnd; it != itEnd;
++it ) { ++it ) {
stream << wrapLongStrings( it->message ) << "\n"; LineWrapper().setIndent(2).wrap( it->message ).intoStream( stream );
stream << "\n";
} }
} }
void printSourceInfo() const { void printSourceInfo() const {
@ -228,10 +229,6 @@ namespace Catch {
stream << result.getSourceInfo() << ": "; stream << result.getSourceInfo() << ": ";
} }
static std::string wrapLongStrings( std::string const& _string ){
return Catch::wrapLongStrings( _string, CATCH_CONFIG_CONSOLE_WIDTH-1, 2 );
}
std::ostream& stream; std::ostream& stream;
AssertionStats const& stats; AssertionStats const& stats;
AssertionResult const& result; AssertionResult const& result;

File diff suppressed because it is too large Load Diff

View File

@ -426,34 +426,63 @@ TEST_CASE( "selftest/tags", "" ) {
} }
TEST_CASE( "Long strings can be wrapped", "[wrap]" ) { TEST_CASE( "Long strings can be wrapped", "[wrap]" ) {
SECTION( "plain string", "" ) {
// guide: 123456789012345678 // guide: 123456789012345678
std::string testString = "one two three four"; std::string testString = "one two three four";
SECTION( "No wrapping", "" ) { SECTION( "No wrapping", "" ) {
CHECK( Catch::wrapLongStrings( testString, 80, 0 ) == testString ); CHECK( Catch::LineWrapper( 80 ).wrap( testString ).toString() == testString );
CHECK( Catch::wrapLongStrings( testString, 18, 0 ) == testString ); CHECK( Catch::LineWrapper( 18 ).wrap( testString ).toString() == testString );
} }
SECTION( "Wrapped once", "" ) { SECTION( "Wrapped once", "" ) {
CHECK( Catch::wrapLongStrings( testString, 17, 0 ) == "one two three\nfour" ); CHECK( Catch::LineWrapper( 17 ).wrap( testString ).toString() == "one two three\nfour" );
CHECK( Catch::wrapLongStrings( testString, 16, 0 ) == "one two three\nfour" ); CHECK( Catch::LineWrapper( 16 ).wrap( testString ).toString() == "one two three\nfour" );
CHECK( Catch::wrapLongStrings( testString, 15, 0 ) == "one two three\nfour" ); CHECK( Catch::LineWrapper( 15 ).wrap( testString ).toString() == "one two three\nfour" );
CHECK( Catch::wrapLongStrings( testString, 14, 0 ) == "one two three\nfour" ); CHECK( Catch::LineWrapper( 14 ).wrap( testString ).toString() == "one two three\nfour" );
CHECK( Catch::wrapLongStrings( testString, 13, 0 ) == "one two\nthree four" ); CHECK( Catch::LineWrapper( 13 ).wrap( testString ).toString() == "one two\nthree four" );
} }
SECTION( "Wrapped twice", "" ) { SECTION( "Wrapped twice", "" ) {
CHECK( Catch::wrapLongStrings( testString, 9, 0 ) == "one two\nthree\nfour" ); CHECK( Catch::LineWrapper( 9 ).wrap( testString ).toString() == "one two\nthree\nfour" );
CHECK( Catch::wrapLongStrings( testString, 8, 0 ) == "one two\nthree\nfour" ); CHECK( Catch::LineWrapper( 8 ).wrap( testString ).toString() == "one two\nthree\nfour" );
} }
SECTION( "Wrapped three times", "" ) { SECTION( "Wrapped three times", "" ) {
CHECK( Catch::wrapLongStrings( testString, 7, 0 ) == "one\ntwo\nthree\nfour" ); CHECK( Catch::LineWrapper( 7 ).wrap( testString ).toString() == "one\ntwo\nthree\nfour" );
CHECK( Catch::wrapLongStrings( testString, 5, 0 ) == "one\ntwo\nthree\nfour" ); CHECK( Catch::LineWrapper( 5 ).wrap( testString ).toString() == "one\ntwo\nthree\nfour" );
} }
SECTION( "Short wrap", "" ) { SECTION( "Short wrap", "" ) {
CHECK( Catch::wrapLongStrings( "abcdef", 4, 0 ) == "abc-\ndef" ); CHECK( Catch::LineWrapper( 4 ).wrap( "abcdef" ).toString() == "abc-\ndef" );
CHECK( Catch::wrapLongStrings( "abcdefg", 4, 0 ) == "abc-\ndefg" ); CHECK( Catch::LineWrapper( 4 ).wrap( "abcdefg" ).toString() == "abc-\ndefg" );
CHECK( Catch::wrapLongStrings( "abcdefgh", 4, 0 ) == "abc-\ndef-\ngh" ); CHECK( Catch::LineWrapper( 4 ).wrap("abcdefgh" ).toString() == "abc-\ndef-\ngh" );
CHECK( Catch::wrapLongStrings( testString, 4, 0 ) == "one\ntwo\nthr-\nee\nfour" ); CHECK( Catch::LineWrapper( 4 ).wrap( testString ).toString() == "one\ntwo\nthr-\nee\nfour" );
CHECK( Catch::wrapLongStrings( testString, 3, 0 ) == "one\ntwo\nth-\nree\nfo-\nur" ); CHECK( Catch::LineWrapper( 3 ).wrap( testString ).toString() == "one\ntwo\nth-\nree\nfo-\nur" );
} }
}
SECTION( "With newlines", "" ) {
// guide: 1234567890123456789
std::string testString = "one two\nthree four";
SECTION( "No wrapping" , "" ) {
CHECK( Catch::LineWrapper( 80 ).wrap( testString ).toString() == testString );
CHECK( Catch::LineWrapper( 18 ).wrap( testString ).toString() == testString );
CHECK( Catch::LineWrapper( 10 ).wrap( testString ).toString() == testString );
}
SECTION( "Trailing newline" , "" ) {
CHECK( Catch::LineWrapper( 10 ).wrap( "abcdef\n" ).toString() == "abcdef\n" );
CHECK( Catch::LineWrapper( 6 ).wrap( "abcdef" ).toString() == "abcdef" );
CHECK( Catch::LineWrapper( 6 ).wrap( "abcdef\n" ).toString() == "abcdef\n" );
}
SECTION( "Wrapped once", "" ) {
CHECK( Catch::LineWrapper( 9 ).wrap( testString ).toString() == "one two\nthree\nfour" );
CHECK( Catch::LineWrapper( 8 ).wrap( testString ).toString() == "one two\nthree\nfour" );
CHECK( Catch::LineWrapper( 7 ).wrap( testString ).toString() == "one two\nthree\nfour" );
}
SECTION( "Wrapped twice", "" ) {
CHECK( Catch::LineWrapper( 6 ).wrap( testString ).toString() == "one\ntwo\nthree\nfour" );
}
}
} }