diff --git a/approvalTests.py b/approvalTests.py index ef9ddbf3..af52f60c 100644 --- a/approvalTests.py +++ b/approvalTests.py @@ -14,7 +14,9 @@ filteredResultsPath = os.path.join( catchPath, 'projects/SelfTest/Baselines/unap cmdPath = sys.argv[1] f = open( rawResultsPath, 'w' ) -subprocess.call([ cmdPath, "~dummy", "-s", "-w", "NoAssertions" ], stdout=f, stderr=f ) +subprocess.call([ cmdPath, "~dummy", "-s", "-w", "NoAssertions", "-r", "basic" ], stdout=f, stderr=f ) +#subprocess.call([ cmdPath, "~dummy", "-s", "-w", "NoAssertions", "-r", "console" ], stdout=f, stderr=f ) +#subprocess.call([ cmdPath, "~dummy", "-s", "-w", "NoAssertions", "-r", "basic", "-a", "4" ], stdout=f, stderr=f ) subprocess.call([ cmdPath, "~dummy", "-s", "-w", "NoAssertions", "-r", "junit" ], stdout=f, stderr=f ) subprocess.call([ cmdPath, "~dummy", "-s", "-w", "NoAssertions", "-r", "xml" ], stdout=f, stderr=f ) f.close() diff --git a/include/internal/catch_interfaces_reporter.h b/include/internal/catch_interfaces_reporter.h index 2743e969..efde354b 100644 --- a/include/internal/catch_interfaces_reporter.h +++ b/include/internal/catch_interfaces_reporter.h @@ -70,12 +70,14 @@ namespace Catch struct ThreadedSectionInfo : SectionInfo, SharedImpl<> { ThreadedSectionInfo( SectionInfo const& _sectionInfo, Ptr const& _parent = Ptr() ) : SectionInfo( _sectionInfo ), - parent( _parent ) + parent( _parent ), + printed( false ) {} virtual ~ThreadedSectionInfo(); std::vector > children; Ptr parent; + bool printed; }; struct AssertionStats : SharedImpl<> { @@ -190,7 +192,8 @@ namespace Catch struct AccumulatingReporter : SharedImpl { AccumulatingReporter( ReporterConfig const& _config ) - : stream( _config.stream() ) + : m_config( _config ), + stream( _config.stream() ) {} virtual ~AccumulatingReporter(); @@ -231,6 +234,7 @@ namespace Catch virtual void testRunEnded( Ptr const& /* _testRunStats */ ) { } + ReporterConfig m_config; Option testRunInfo; Option unusedGroupInfo; Option unusedTestCaseInfo; diff --git a/include/reporters/catch_reporter_console.hpp b/include/reporters/catch_reporter_console.hpp index 3d8abfa7..2b9b75fb 100644 --- a/include/reporters/catch_reporter_console.hpp +++ b/include/reporters/catch_reporter_console.hpp @@ -35,11 +35,13 @@ namespace Catch { } void lazyPrintGroupInfo() { if( !unusedGroupInfo->name.empty() ) - stream << "[Group: '" << unusedGroupInfo->name << "']" << std::endl; +// stream << "[Group: '" << unusedGroupInfo->name << "']" << std::endl; + stream << "[Started group: '" << unusedGroupInfo->name << "']" << std::endl; unusedGroupInfo.reset(); } void lazyPrintTestCaseInfo() { - stream << "[Test case: '" << unusedTestCaseInfo->name << "']" << std::endl; +// stream << "[Test case: '" << unusedTestCaseInfo->name << "']" << std::endl; + stream << "[Running: " << unusedTestCaseInfo->name << "]" << std::endl; unusedTestCaseInfo.reset(); } std::string makeSectionPath( ThreadedSectionInfo const * section, std::string const& delimiter ) { @@ -49,6 +51,7 @@ namespace Catch { return sectionPath; } void lazyPrintSectionInfo() { + // !TBD use printed flag ThreadedSectionInfo* section = unusedSectionInfo.get(); std::string sectionPath = makeSectionPath( section, ", " ); @@ -58,6 +61,21 @@ namespace Catch { stream << "[Section: " << sectionPath << "]" << std::endl; unusedSectionInfo.reset(); } + + void lazyPrintSectionInfoLegacy() { + std::vector sections; + for( ThreadedSectionInfo* section = unusedSectionInfo.get(); + section && !section->printed; + section = section->parent.get() ) + sections.push_back( section ); + + typedef std::vector::const_reverse_iterator It; + for( It it = sections.rbegin(), itEnd = sections.rend(); it != itEnd; ++it ) { + stream << "[Started section: " << "'" + (*it)->name + "'" << "]" << std::endl; + (*it)->printed = true; + } + unusedSectionInfo.reset(); + } void lazyPrint() { if( testRunInfo ) lazyPrintRunInfo(); @@ -65,17 +83,134 @@ namespace Catch { lazyPrintGroupInfo(); if( unusedTestCaseInfo ) lazyPrintTestCaseInfo(); - if( unusedSectionInfo ) - lazyPrintSectionInfo(); + if( currentSectionInfo && !currentSectionInfo->printed ) + lazyPrintSectionInfoLegacy(); // !TBD } - virtual void assertionStarting( AssertionInfo const& _assertionInfo ) { + virtual void assertionStarting( AssertionInfo const& ) { } virtual void assertionEnded( Ptr const& _assertionStats ) { - if( !_assertionStats->assertionResult.isOk() ) - lazyPrint(); - } + AssertionResult const& result = _assertionStats->assertionResult; + + // Drop out if result was successful and we're not printing those + if( !m_config.includeSuccessfulResults() && result.isOk() ) + return; + + lazyPrint(); + + if( !result.getSourceInfo().empty() ) { + TextColour colour( TextColour::FileName ); + stream << result.getSourceInfo(); + } + + if( result.hasExpression() ) { + TextColour colour( TextColour::OriginalExpression ); + stream << result.getExpression(); + if( result.succeeded() ) { + TextColour successColour( TextColour::Success ); + stream << " succeeded"; + } + else { + TextColour errorColour( TextColour::Error ); + stream << " failed"; + if( result.isOk() ) { + TextColour okAnywayColour( TextColour::Success ); + stream << " - but was ok"; + } + } + } + + switch( result.getResultType() ) { + case ResultWas::ThrewException: + { + TextColour colour( TextColour::Error ); + if( result.hasExpression() ) + stream << " with unexpected"; + else + stream << "Unexpected"; + stream << " exception with message: '" << result.getMessage() << "'"; + } + break; + case ResultWas::DidntThrowException: + { + TextColour colour( TextColour::Error ); + if( result.hasExpression() ) + stream << " because no exception was thrown where one was expected"; + else + stream << "No exception thrown where one was expected"; + } + break; + case ResultWas::Info: + { + TextColour colour( TextColour::ReconstructedExpression ); + streamVariableLengthText( "info", result.getMessage() ); + } + break; + case ResultWas::Warning: + { + TextColour colour( TextColour::ReconstructedExpression ); + streamVariableLengthText( "warning", result.getMessage() ); + } + break; + case ResultWas::ExplicitFailure: + { + TextColour colour( TextColour::Error ); + stream << "failed with message: '" << result.getMessage() << "'"; + } + break; + case ResultWas::Unknown: // These cases are here to prevent compiler warnings + case ResultWas::Ok: + case ResultWas::FailureBit: + case ResultWas::ExpressionFailed: + case ResultWas::Exception: + if( !result.hasExpression() ) { + if( result.succeeded() ) { + TextColour colour( TextColour::Success ); + stream << " succeeded"; + } + else { + TextColour colour( TextColour::Error ); + stream << " failed"; + if( result.isOk() ) { + TextColour okAnywayColour( TextColour::Success ); + stream << " - but was ok"; + } + } + } + if( result.hasMessage() ) { + stream << "\n"; + TextColour colour( TextColour::ReconstructedExpression ); + streamVariableLengthText( "with message", result.getMessage() ); + } + break; + } + + if( result.hasExpandedExpression() ) { + stream << " for: "; + if( result.getExpandedExpression().size() > 40 ) { + stream << "\n"; + if( result.getExpandedExpression().size() < 70 ) + stream << "\t"; + } + TextColour colour( TextColour::ReconstructedExpression ); + stream << result.getExpandedExpression(); + } + + stream << std::endl; + } + + void streamVariableLengthText( std::string const& prefix, std::string const& text ) { + std::string trimmed = trim( text ); + if( trimmed.find_first_of( "\r\n" ) == std::string::npos ) { + stream << "[" << prefix << ": " << trimmed << "]"; + } + else { + stream << "\n[" << prefix << "] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" << trimmed + << "\n[end of " << prefix << "] <<<<<<<<<<<<<<<<<<<<<<<<\n"; + } + } + void printAssertionCounts( std::string const& label, Counts const& counts, std::string const& allPrefix = "All " ) { if( counts.passed ) stream << counts.failed << " of " << counts.total() << " " << label << "s failed"; @@ -105,27 +240,58 @@ namespace Catch { } virtual void sectionEnded( Ptr const& _sectionStats ) { - if( !unusedSectionInfo ) { - stream << "[Summary for section '" << _sectionStats->sectionInfo.name << "': "; - printAssertionCounts( "assertion", _sectionStats->assertions ); + if( _sectionStats->missingAssertions ) { + lazyPrint(); + TextColour colour( TextColour::ResultError ); + stream << "\nNo assertions in section, '" << _sectionStats->sectionInfo.name << "'\n" << std::endl; + } + if( currentSectionInfo && currentSectionInfo->printed ) { +// stream << "[Summary for section '" << _sectionStats->sectionInfo.name << "': "; + stream << "[End of section: '" << _sectionStats->sectionInfo.name << "' "; + Counts const& assertions = _sectionStats->assertions; + if( assertions.failed ) { + TextColour colour( TextColour::ResultError ); + printAssertionCounts( "assertion", assertions ); + } + else { + TextColour colour( TextColour::ResultSuccess ); + stream << ( assertions.passed > 1 ? "All " : "" ) + << pluralise( assertions.passed, "assertion" ) << " passed" ; + } stream << "]\n" << std::endl; } AccumulatingReporter::sectionEnded( _sectionStats ); } virtual void testCaseEnded( Ptr const& _testCaseStats ) { + if( _testCaseStats->missingAssertions ) { + lazyPrint(); + TextColour colour( TextColour::ResultError ); + stream << "\nNo assertions in test case, '" << _testCaseStats->testInfo.name << "'\n" << std::endl; + } if( !unusedTestCaseInfo ) { - stream << "[Summary for test case '" << _testCaseStats->testInfo.name << "': "; +// stream << "[Summary for test case '" << _testCaseStats->testInfo.name << "': "; + stream << "[Finished: '" << _testCaseStats->testInfo.name << "' "; printTotals( _testCaseStats->totals ); stream << "]\n" << std::endl; } AccumulatingReporter::testCaseEnded( _testCaseStats ); } virtual void testGroupEnded( Ptr const& _testGroupStats ) { - // !TBD + if( !unusedGroupInfo ) { +// stream << "[Summary for group '" << _testGroupStats->groupInfo.name << "': "; + stream << "[End of group '" << _testGroupStats->groupInfo.name << "'. "; + printTotals( _testGroupStats->totals ); + stream << "]\n" << std::endl; + } AccumulatingReporter::testGroupEnded( _testGroupStats ); } virtual void testRunEnded( Ptr const& _testRunStats ) { - // !TBD + if( !unusedTestCaseInfo ) { +// stream << "[Summary for '" << _testRunStats->runInfo.name << "': "; + stream << "[Testing completed. "; + printTotals( _testRunStats->totals ); + stream << "]\n" << std::endl; + } AccumulatingReporter::testRunEnded( _testRunStats ); }