This commit is contained in:
Phil Nash 2013-03-29 13:44:33 +00:00
parent e324d2829d
commit 38f7eef6fe
3 changed files with 275 additions and 117 deletions

View File

@ -1,6 +1,6 @@
![catch logo](https://raw.github.com/philsquared/Catch/Integration/catch-logo-small.png) ![catch logo](https://raw.github.com/philsquared/Catch/Integration/catch-logo-small.png)
## CATCH v0.9 build 28 (integration branch) ## CATCH v0.9 build 29 (integration branch)
An automated test framework for C, C++ and Objective-C. An automated test framework for C, C++ and Objective-C.
This branch may contain code that is experimental or not yet fully tested. This branch may contain code that is experimental or not yet fully tested.

View File

@ -13,7 +13,7 @@
namespace Catch { namespace Catch {
// These numbers are maintained by a script // These numbers are maintained by a script
Version libraryVersion( 0, 9, 28, "integration" ); Version libraryVersion( 0, 9, 29, "integration" );
} }
#endif // TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED #endif // TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED

View File

@ -1,6 +1,6 @@
/* /*
* CATCH v0.9 build 28 (integration branch) * CATCH v0.9 build 29 (integration branch)
* Generated: 2013-03-25 09:25:14.678493 * Generated: 2013-03-29 13:43:27.058903
* ---------------------------------------------------------- * ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly * This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
@ -1417,6 +1417,7 @@ namespace Catch {
std::string className; std::string className;
std::string description; std::string description;
std::set<std::string> tags; std::set<std::string> tags;
std::string tagsAsString;
SourceLineInfo lineInfo; SourceLineInfo lineInfo;
bool isHidden; bool isHidden;
}; };
@ -1917,9 +1918,8 @@ namespace Catch {
Reports = 1, Reports = 1,
Tests = 2, Tests = 2,
All = 3, Tags = 4,
All = Reports | Tests | Tags,
TestNames = 6,
WhatMask = 0xf, WhatMask = 0xf,
@ -3786,7 +3786,8 @@ namespace Catch {
m_optionNames.push_back( "--list" ); m_optionNames.push_back( "--list" );
} }
virtual std::string argsSynopsis() const { virtual std::string argsSynopsis() const {
return "[all | tests | reporters [xml]]"; // return "[all | tests | reporters | tags [xml]]";
return "[all | tests | reporters | tags]";
} }
virtual std::string optionSummary() const { virtual std::string optionSummary() const {
return "Lists available tests or reporters"; return "Lists available tests or reporters";
@ -3795,29 +3796,32 @@ namespace Catch {
virtual std::string optionDescription() const { virtual std::string optionDescription() const {
return return
"With no arguments this option will list all registered tests - one per line.\n" "With no arguments this option will list all registered tests - one per line.\n"
"Supplying the xml argument formats the list as an xml document (which may be useful for " // "Supplying the xml argument formats the list as an xml document (which may be useful for "
"consumption by other tools).\n" // "consumption by other tools).\n"
"Supplying the tests or reporters lists tests or reporters respectively - with descriptions.\n" "Supplying the tests or reporters lists tests or reporters respectively - with descriptions.\n"
"\n" "\n"
"Examples:\n" "Examples:\n"
"\n" "\n"
" -l\n" " -l\n"
" -l tests\n" " -l tests\n"
" -l tags\n"
" -l reporters xml\n" " -l reporters xml\n"
" -l xml"; ;//" -l xml";
} }
virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) { virtual void parseIntoConfig( const Command& cmd, ConfigData& config ) {
config.listSpec = List::TestNames; config.listSpec = List::Tests;
if( cmd.argsCount() >= 1 ) { if( cmd.argsCount() >= 1 ) {
if( cmd[0] == "all" ) if( cmd[0] == "all" )
config.listSpec = List::All; config.listSpec = List::All;
else if( cmd[0] == "tests" ) else if( cmd[0] == "tests" )
config.listSpec = List::Tests; config.listSpec = List::Tests;
else if( cmd[0] == "tags" )
config.listSpec = List::Tags;
else if( cmd[0] == "reporters" ) else if( cmd[0] == "reporters" )
config.listSpec = List::Reports; config.listSpec = List::Reports;
else else
cmd.raiseError( "Expected [tests] or [reporters]" ); cmd.raiseError( "Expected tests, reporters or tags" );
} }
if( cmd.argsCount() >= 2 ) { if( cmd.argsCount() >= 2 ) {
if( cmd[1] == "xml" ) if( cmd[1] == "xml" )
@ -3825,7 +3829,7 @@ namespace Catch {
else if( cmd[1] == "text" ) else if( cmd[1] == "text" )
config.listSpec = static_cast<List::What>( config.listSpec | List::AsText ); config.listSpec = static_cast<List::What>( config.listSpec | List::AsText );
else else
cmd.raiseError( "Expected [xml] or [text]" ); cmd.raiseError( "Expected xml or text" );
} }
} }
}; };
@ -4144,7 +4148,53 @@ namespace Catch {
// #included from: internal/catch_list.hpp // #included from: internal/catch_list.hpp
#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED #define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
// #included from: catch_line_wrap.h
#define TWOBLUECUBES_CATCH_LINE_WRAP_H_INCLUDED
#include <string>
#include <vector>
namespace Catch {
class LineWrapper {
public:
LineWrapper();
LineWrapper& setIndent( std::size_t _indent );
LineWrapper& setRight( std::size_t _right );
LineWrapper& wrap( std::string const& _str );
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(); }
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]; }
friend std::ostream& operator << ( std::ostream& _stream, LineWrapper const& _lineWrapper );
private:
void wrapInternal( std::string const& _str );
void addLine( const std::string& _line );
bool isWrapPoint( char c );
std::string indent;
std::size_t right;
std::size_t nextTab;
std::size_t tab;
std::string wrappableChars;
int recursionCount;
std::vector<std::string> lines;
};
} // end namespace Catch
#include <limits> #include <limits>
#include <algorithm>
namespace Catch { namespace Catch {
inline bool matchesFilters( const std::vector<TestCaseFilters>& filters, const TestCase& testCase ) { inline bool matchesFilters( const std::vector<TestCaseFilters>& filters, const TestCase& testCase ) {
@ -4155,47 +4205,136 @@ namespace Catch {
return false; return false;
return true; return true;
} }
inline void List( const ConfigData& config ) {
if( config.listSpec & List::Reports ) { inline void listTests( const ConfigData& config ) {
std::cout << "Available reports:\n"; if( config.filters.empty() )
IReporterRegistry::FactoryMap::const_iterator it = getRegistryHub().getReporterRegistry().getFactories().begin(); std::cout << "All available test cases:\n";
IReporterRegistry::FactoryMap::const_iterator itEnd = getRegistryHub().getReporterRegistry().getFactories().end(); else
for(; it != itEnd; ++it ) { std::cout << "Matching test cases:\n";
// !TBD: consider listAs() std::vector<TestCase> const& allTests = getRegistryHub().getTestCaseRegistry().getAllTests();
std::cout << "\t" << it->first << "\n\t\t'" << it->second->getDescription() << "'\n"; std::vector<TestCase>::const_iterator it = allTests.begin(), itEnd = allTests.end();
// First pass - get max tags
std::size_t maxTagLen = 0;
std::size_t maxNameLen = 0;
for(; it != itEnd; ++it ) {
if( matchesFilters( config.filters, *it ) ) {
maxTagLen = (std::max)( it->getTestCaseInfo().tagsAsString.size(), maxTagLen );
maxNameLen = (std::max)( it->getTestCaseInfo().name.size(), maxNameLen );
} }
std::cout << std::endl;
} }
if( config.listSpec & List::Tests ) { // Try to fit everything in. If not shrink tag column first, down to 30
if( config.filters.empty() ) // then shrink name column until it all fits (strings will be wrapped within column)
std::cout << "All available test cases:\n"; while( maxTagLen + maxNameLen > CATCH_CONFIG_CONSOLE_WIDTH-5 ) {
if( maxTagLen > 30 )
--maxTagLen;
else else
std::cout << "Matching test cases:\n"; --maxNameLen;
std::vector<TestCase>::const_iterator it = getRegistryHub().getTestCaseRegistry().getAllTests().begin(); }
std::vector<TestCase>::const_iterator itEnd = getRegistryHub().getTestCaseRegistry().getAllTests().end();
std::size_t matchedTests = 0; std::size_t matchedTests = 0;
for(; it != itEnd; ++it ) { for( it = allTests.begin(); it != itEnd; ++it ) {
if( matchesFilters( config.filters, *it ) ) { if( matchesFilters( config.filters, *it ) ) {
matchedTests++; matchedTests++;
// !TBD: consider listAs() // !TBD: consider listAs()
std::cout << " " << it->getTestCaseInfo().name << "\n"; LineWrapper nameWrapper;
if( ( config.listSpec & List::TestNames ) != List::TestNames ) nameWrapper.setRight( maxNameLen ).setIndent( 2 ).wrap( it->getTestCaseInfo().name );
std::cout << " '" << it->getTestCaseInfo().description << "'\n";
LineWrapper tagsWrapper;
tagsWrapper.setRight( maxTagLen ).wrap( it->getTestCaseInfo().tagsAsString );
for( std::size_t i = 0; i < std::max( nameWrapper.size(), tagsWrapper.size() ); ++i ) {
std::string nameCol;
if( i < nameWrapper.size() )
nameCol = nameWrapper[i];
else
nameCol = " ...";
std::cout << nameCol;
if( i < tagsWrapper.size() && !tagsWrapper[i].empty() ) {
if( i == 0 )
std::cout << " " << std::string( maxNameLen - nameCol.size(), '.' ) << " " << tagsWrapper[i];
else
std::cout << std::string( maxNameLen - nameCol.size(), ' ' ) << " " << tagsWrapper[i];
}
std::cout << "\n";
} }
} }
if( config.filters.empty() )
std::cout << pluralise( matchedTests, "test case" ) << std::endl;
else
std::cout << pluralise( matchedTests, "matching test case" ) << std::endl;
} }
if( config.filters.empty() )
std::cout << pluralise( matchedTests, "test case" ) << std::endl;
else
std::cout << pluralise( matchedTests, "matching test case" ) << std::endl;
}
if( ( config.listSpec & List::All ) == 0 ) { inline void listTags( const ConfigData& config ) {
std::ostringstream oss; if( config.filters.empty() )
oss << "Unknown list type"; std::cout << "All available tags:\n";
throw std::domain_error( oss.str() ); else
std::cout << "Matching tags:\n";
std::vector<TestCase> const& allTests = getRegistryHub().getTestCaseRegistry().getAllTests();
std::vector<TestCase>::const_iterator it = allTests.begin(), itEnd = allTests.end();
std::map<std::string, int> tagCounts;
std::size_t maxTagLen = 0;
for(; it != itEnd; ++it ) {
if( matchesFilters( config.filters, *it ) ) {
for( std::set<std::string>::const_iterator tagIt = it->getTestCaseInfo().tags.begin(),
tagItEnd = it->getTestCaseInfo().tags.end();
tagIt != tagItEnd;
++tagIt ) {
std::string tagName = "[" + *tagIt + "]";
maxTagLen = (std::max)( maxTagLen, tagName.size() );
std::map<std::string, int>::iterator countIt = tagCounts.find( tagName );
if( countIt == tagCounts.end() )
tagCounts.insert( std::make_pair( tagName, 1 ) );
else
countIt->second++;
}
}
} }
maxTagLen +=2;
if( maxTagLen > CATCH_CONFIG_CONSOLE_WIDTH-10 )
maxTagLen = CATCH_CONFIG_CONSOLE_WIDTH-10;
for( std::map<std::string, int>::const_iterator countIt = tagCounts.begin(), countItEnd = tagCounts.end();
countIt != countItEnd;
++countIt ) {
LineWrapper wrapper;
wrapper.setIndent(2).setRight( maxTagLen ).wrap( countIt->first );
std::cout << wrapper;
if( maxTagLen > wrapper.last().size() )
std::cout << std::string( maxTagLen - wrapper.last().size(), '.' );
std::cout << ".. "
<< countIt->second
<< "\n";
}
std::cout << pluralise( tagCounts.size(), "tag" ) << std::endl;
}
inline void listReporters( const ConfigData& /*config*/ ) {
std::cout << "Available reports:\n";
IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
IReporterRegistry::FactoryMap::const_iterator it = factories.begin(), itEnd = factories.end();
for(; it != itEnd; ++it ) {
// !TBD: consider listAs()
std::cout << "\t" << it->first << "\n\t\t'" << it->second->getDescription() << "'\n";
}
std::cout << std::endl;
}
inline void list( const ConfigData& config ) {
if( config.listSpec & List::Tests )
listTests( config );
if( config.listSpec & List::Tags )
listTags( config );
if( config.listSpec & List::Reports )
listReporters( config );
if( ( config.listSpec & List::All ) == 0 )
throw std::logic_error( "Unknown list type" );
} }
} // end namespace Catch } // end namespace Catch
@ -4748,18 +4887,6 @@ namespace Catch {
extern Version libraryVersion; extern Version libraryVersion;
} }
// #included from: internal/catch_line_wrap.h
#define TWOBLUECUBES_CATCH_LINE_WRAP_H_INCLUDED
#include <string>
namespace Catch {
void wrapLongStrings( std::ostream& stream, const std::string& str, std::size_t columns, std::size_t indent = 0 );
std::string wrapLongStrings( const std::string& str, std::size_t columns, std::size_t indent = 0 );
} // end namespace Catch
#include <fstream> #include <fstream>
#include <stdlib.h> #include <stdlib.h>
#include <limits> #include <limits>
@ -4869,7 +4996,7 @@ namespace Catch {
// Handle list request // Handle list request
if( config.listSpec != List::None ) { if( config.listSpec != List::None ) {
List( config ); list( config );
Catch::cleanUp(); Catch::cleanUp();
return 0; return 0;
} }
@ -4906,7 +5033,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() ) << "\n" << std::endl;
} }
} }
@ -5839,13 +5966,19 @@ namespace Catch {
tags( _tags ), tags( _tags ),
lineInfo( _lineInfo ), lineInfo( _lineInfo ),
isHidden( _isHidden ) isHidden( _isHidden )
{} {
std::ostringstream oss;
for( std::set<std::string>::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it )
oss << "[" << *it << "]";
tagsAsString = oss.str();
}
TestCaseInfo::TestCaseInfo( const TestCaseInfo& other ) TestCaseInfo::TestCaseInfo( const TestCaseInfo& other )
: name( other.name ), : name( other.name ),
className( other.className ), className( other.className ),
description( other.description ), description( other.description ),
tags( other.tags ), tags( other.tags ),
tagsAsString( other.tagsAsString ),
lineInfo( other.lineInfo ), lineInfo( other.lineInfo ),
isHidden( other.isHidden ) isHidden( other.isHidden )
{} {}
@ -5919,7 +6052,7 @@ namespace Catch {
namespace Catch { namespace Catch {
// These numbers are maintained by a script // These numbers are maintained by a script
Version libraryVersion( 0, 9, 28, "integration" ); Version libraryVersion( 0, 9, 29, "integration" );
} }
// #included from: catch_line_wrap.hpp // #included from: catch_line_wrap.hpp
@ -5927,62 +6060,91 @@ namespace Catch {
namespace Catch { namespace Catch {
namespace { LineWrapper::LineWrapper()
inline void addIndent( std::ostream& os, std::size_t indent ) { : right( CATCH_CONFIG_CONSOLE_WIDTH-1 ),
while( indent-- > 0 ) nextTab( 0 ),
os << ' '; tab( 0 ),
} wrappableChars( " [({.," ),
recursionCount( 0 )
{}
inline void recursivelyWrapLine( std::ostream& os, std::string paragraph, std::size_t columns, std::size_t indent ) { LineWrapper& LineWrapper::setIndent( std::size_t _indent ) {
std::size_t width = columns-indent; indent = std::string( _indent, ' ' );
std::size_t tab = 0; return *this;
std::size_t wrapPoint = width; }
for( std::size_t pos = 0; pos < paragraph.size(); ++pos ) { LineWrapper& LineWrapper::setRight( std::size_t _right ) {
if( pos == width ) { right = _right;
addIndent( os, indent ); return *this;
if( paragraph[wrapPoint] == ' ' ) { }
os << paragraph.substr( 0, wrapPoint ) << "\n"; LineWrapper& LineWrapper::wrap( std::string const& _str ) {
while( paragraph[++wrapPoint] == ' ' ); nextTab = tab = 0;
} wrapInternal( _str );
else { return *this;
os << paragraph.substr( 0, --wrapPoint ) << "-\n"; }
} bool LineWrapper::isWrapPoint( char c ) {
return recursivelyWrapLine( os, paragraph.substr( wrapPoint ), columns, indent+tab ); return wrappableChars.find( c ) != std::string::npos;
} }
if( paragraph[pos] == '\t' ) { void LineWrapper::wrapInternal( std::string const& _str ) {
tab = pos; assert( ++recursionCount < 100 );
paragraph = paragraph.substr( 0, tab ) + paragraph.substr( tab+1 );
pos--; std::size_t width = right - indent.size();
} std::size_t wrapPoint = width-tab;
else if( paragraph[pos] == ' ' ) { for( std::size_t pos = 0; pos < _str.size(); ++pos ) {
wrapPoint = 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 if( isWrapPoint( _str[wrapPoint] ) ) {
addLine( _str.substr( 0, wrapPoint ) );
}
else {
addLine( _str.substr( 0, --wrapPoint ) + '-' );
}
return wrapInternal( _str.substr( wrapPoint ) );
}
if( _str[pos] == '\t' ) {
nextTab = pos;
std::string withoutTab = _str.substr( 0, nextTab ) + _str.substr( nextTab+1 );
return wrapInternal( withoutTab );
}
else if( pos > 0 && isWrapPoint( _str[pos] ) ) {
wrapPoint = pos;
} }
addIndent( os, indent );
os << paragraph;
} }
addLine( _str );
} }
void wrapLongStrings( std::ostream& stream, const std::string& str, std::size_t columns, std::size_t indent ) { std::ostream& operator << ( std::ostream& _stream, LineWrapper const& _lineWrapper ) {
std::string::size_type pos = 0; for( LineWrapper::const_iterator it = _lineWrapper.begin(), itEnd = _lineWrapper.end();
std::string::size_type newline = str.find_first_of( '\n' ); it != itEnd; ++it ) {
while( newline != std::string::npos ) { if( it != _lineWrapper.begin() )
std::string paragraph = str.substr( pos, newline-pos ); _stream << "\n";
recursivelyWrapLine( stream, paragraph, columns, indent ); _stream << *it;
stream << "\n";
pos = newline+1;
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::string wrapLongStrings( const std::string& str, std::size_t columns, std::size_t indent ) {
std::ostringstream oss; std::ostringstream oss;
wrapLongStrings( oss, str, columns, indent ); oss << *this;
return oss.str(); return oss.str();
} }
void LineWrapper::addLine( const std::string& _line ) {
if( tab > 0 )
lines.push_back( indent + std::string( tab, ' ' ) + _line );
else
lines.push_back( indent + _line );
if( nextTab > 0 )
tab = nextTab;
}
} // end namespace Catch } // end namespace Catch
// #included from: catch_message.hpp // #included from: catch_message.hpp
@ -7207,7 +7369,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() ) << "\n";
} }
} }
void printMessage() const { void printMessage() const {
@ -7216,7 +7378,7 @@ 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"; stream << LineWrapper().setIndent(2).wrap( it->message ) << "\n";
} }
} }
void printSourceInfo() const { void printSourceInfo() const {
@ -7224,10 +7386,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;
@ -7599,11 +7757,11 @@ int main (int argc, char * const argv[]) {
#else #else
#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) #define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags )
#endif #endif
#define GIVEN( desc ) SECTION( "Given: " desc, "" ) #define GIVEN( desc ) SECTION( " Given: " desc, "" )
#define WHEN( desc ) SECTION( " When: " desc, "" ) #define WHEN( desc ) SECTION( " When: " desc, "" )
#define AND_WHEN( desc ) SECTION( " And: " desc, "" ) #define AND_WHEN( desc ) SECTION( "And when: " desc, "" )
#define THEN( desc ) SECTION( " Then: " desc, "" ) #define THEN( desc ) SECTION( " Then: " desc, "" )
#define AND_THEN( desc ) SECTION( " And: " desc, "" ) #define AND_THEN( desc ) SECTION( " And: " desc, "" )
using Catch::Detail::Approx; using Catch::Detail::Approx;