blob: fed97072a8daa8487b7a8ac1871fed937af5d5a9 [file] [log] [blame]
Phil Nashfe981232012-12-05 08:40:53 +00001/*
2 * Created by Phil on 5/12/2012.
3 * Copyright 2012 Two Blue Cubes Ltd. All rights reserved.
4 *
5 * Distributed under the Boost Software License, Version 1.0. (See accompanying
6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 */
8#ifndef TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
9#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
10
Phil Nashc4a089c2013-12-03 18:52:41 +000011#include "catch_reporter_bases.hpp"
12
Phil Nashfe981232012-12-05 08:40:53 +000013#include "../internal/catch_reporter_registrars.hpp"
14#include "../internal/catch_console_colour.hpp"
15
Martin Hořeňovský061a1832017-02-27 11:34:15 +010016#include <cfloat>
17#include <cstdio>
18
Phil Nashfe981232012-12-05 08:40:53 +000019namespace Catch {
20
Martin Hořeňovský061a1832017-02-27 11:34:15 +010021
Phil Nashbcf722e2013-01-03 09:04:46 +000022 struct ConsoleReporter : StreamingReporterBase {
Phil Nashfe981232012-12-05 08:40:53 +000023 ConsoleReporter( ReporterConfig const& _config )
Phil Nashbcf722e2013-01-03 09:04:46 +000024 : StreamingReporterBase( _config ),
Phil Nash94a1acf2014-07-03 19:06:59 +010025 m_headerPrinted( false )
Phil Nashfe981232012-12-05 08:40:53 +000026 {}
27
Phil Nash368714e2015-08-07 08:20:56 +010028 virtual ~ConsoleReporter() CATCH_OVERRIDE;
Phil Nashfe981232012-12-05 08:40:53 +000029 static std::string getDescription() {
30 return "Reports test results as plain lines of text";
31 }
Phil Nash75426852013-03-12 19:06:40 +000032
Phil Nash368714e2015-08-07 08:20:56 +010033 virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE {
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +010034 stream << "No test cases matched '" << spec << '\'' << std::endl;
Phil Nash75426852013-03-12 19:06:40 +000035 }
Phil Nashf3d1f082013-07-03 19:14:59 +010036
Phil Nash368714e2015-08-07 08:20:56 +010037 virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {
Phil Nashfe981232012-12-05 08:40:53 +000038 }
Phil Nashfe981232012-12-05 08:40:53 +000039
Phil Nash368714e2015-08-07 08:20:56 +010040 virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE {
Phil Nashbcf722e2013-01-03 09:04:46 +000041 AssertionResult const& result = _assertionStats.assertionResult;
Phil Nashf3d1f082013-07-03 19:14:59 +010042
Phil Nashf9db24a2017-03-03 14:19:41 +000043 bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
Phil Nash4f57c8c2013-11-13 08:07:38 +000044
Phil Nashf9db24a2017-03-03 14:19:41 +000045 // Drop out if result was successful but we're not printing them.
46 if( !includeResults && result.getResultType() != ResultWas::Warning )
47 return false;
Phil Nashf3d1f082013-07-03 19:14:59 +010048
Phil Nashe6d1c982012-12-09 11:20:46 +000049 lazyPrint();
50
Phil Nashf9db24a2017-03-03 14:19:41 +000051 AssertionPrinter printer( stream, _assertionStats, includeResults );
Phil Nash36824332013-01-18 17:50:21 +000052 printer.print();
Phil Nash42aef1d2013-01-13 21:51:44 +000053 stream << std::endl;
Phil Nash0d357302013-06-28 16:25:49 +010054 return true;
Phil Nash42aef1d2013-01-13 21:51:44 +000055 }
Phil Nash603002c2013-01-26 20:17:52 +000056
Phil Nash368714e2015-08-07 08:20:56 +010057 virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE {
Phil Nashb7ff9952013-03-06 20:40:16 +010058 m_headerPrinted = false;
Phil Nash603002c2013-01-26 20:17:52 +000059 StreamingReporterBase::sectionStarting( _sectionInfo );
60 }
Phil Nash368714e2015-08-07 08:20:56 +010061 virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE {
Phil Nash60ed3c12013-01-14 18:51:49 +000062 if( _sectionStats.missingAssertions ) {
63 lazyPrint();
Phil Nashf186a912013-04-05 07:59:28 +010064 Colour colour( Colour::ResultError );
Phil Nash29ccaa62013-08-08 08:05:19 +010065 if( m_sectionStack.size() > 1 )
Phil Nashb80280f2013-07-26 19:19:44 +010066 stream << "\nNo assertions in section";
67 else
68 stream << "\nNo assertions in test case";
69 stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
Phil Nash60ed3c12013-01-14 18:51:49 +000070 }
Martin Hořeňovský9bab7c82017-02-17 14:07:56 +000071 if( m_config->showDurations() == ShowDurations::Always ) {
Martin Hořeňovský061a1832017-02-27 11:34:15 +010072 stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
Phil Nashf41fad72013-08-16 18:57:41 +010073 }
Martin Hořeňovský9bab7c82017-02-17 14:07:56 +000074 if( m_headerPrinted ) {
75 m_headerPrinted = false;
Phil Nashf7378ee2013-09-07 12:07:38 +010076 }
Phil Nash60ed3c12013-01-14 18:51:49 +000077 StreamingReporterBase::sectionEnded( _sectionStats );
78 }
79
Phil Nash368714e2015-08-07 08:20:56 +010080 virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE {
Phil Nash60ed3c12013-01-14 18:51:49 +000081 StreamingReporterBase::testCaseEnded( _testCaseStats );
Phil Nashb7ff9952013-03-06 20:40:16 +010082 m_headerPrinted = false;
Phil Nash60ed3c12013-01-14 18:51:49 +000083 }
Phil Nash368714e2015-08-07 08:20:56 +010084 virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE {
Phil Nash1f519dd2013-08-08 08:24:37 +010085 if( currentGroupInfo.used ) {
Phil Nash60ed3c12013-01-14 18:51:49 +000086 printSummaryDivider();
87 stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
88 printTotals( _testGroupStats.totals );
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +010089 stream << '\n' << std::endl;
Phil Nash60ed3c12013-01-14 18:51:49 +000090 }
91 StreamingReporterBase::testGroupEnded( _testGroupStats );
92 }
Phil Nash368714e2015-08-07 08:20:56 +010093 virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE {
Phil Nash9c1f9a82014-07-03 08:09:57 +010094 printTotalsDivider( _testRunStats.totals );
Phil Nash60ed3c12013-01-14 18:51:49 +000095 printTotals( _testRunStats.totals );
Phil Nash9c1f9a82014-07-03 08:09:57 +010096 stream << std::endl;
Phil Nash60ed3c12013-01-14 18:51:49 +000097 StreamingReporterBase::testRunEnded( _testRunStats );
98 }
99
100 private:
Phil Nashf3d1f082013-07-03 19:14:59 +0100101
Phil Nash36824332013-01-18 17:50:21 +0000102 class AssertionPrinter {
Phil Nash503d5d02013-07-03 08:25:11 +0100103 void operator= ( AssertionPrinter const& );
Phil Nash36824332013-01-18 17:50:21 +0000104 public:
Phil Nash4f57c8c2013-11-13 08:07:38 +0000105 AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
Phil Nash36824332013-01-18 17:50:21 +0000106 : stream( _stream ),
107 stats( _stats ),
108 result( _stats.assertionResult ),
Phil Nashf186a912013-04-05 07:59:28 +0100109 colour( Colour::None ),
Phil Nash207b27b2013-02-02 19:58:04 +0000110 message( result.getMessage() ),
Phil Nash4f57c8c2013-11-13 08:07:38 +0000111 messages( _stats.infoMessages ),
112 printInfoMessages( _printInfoMessages )
Phil Nash36824332013-01-18 17:50:21 +0000113 {
114 switch( result.getResultType() ) {
115 case ResultWas::Ok:
Phil Nashf186a912013-04-05 07:59:28 +0100116 colour = Colour::Success;
Phil Nash36824332013-01-18 17:50:21 +0000117 passOrFail = "PASSED";
Phil Nash207b27b2013-02-02 19:58:04 +0000118 //if( result.hasMessage() )
119 if( _stats.infoMessages.size() == 1 )
Phil Nash36824332013-01-18 17:50:21 +0000120 messageLabel = "with message";
Phil Nash207b27b2013-02-02 19:58:04 +0000121 if( _stats.infoMessages.size() > 1 )
122 messageLabel = "with messages";
Phil Nash36824332013-01-18 17:50:21 +0000123 break;
124 case ResultWas::ExpressionFailed:
125 if( result.isOk() ) {
Phil Nashf186a912013-04-05 07:59:28 +0100126 colour = Colour::Success;
Phil Nash36824332013-01-18 17:50:21 +0000127 passOrFail = "FAILED - but was ok";
128 }
129 else {
Phil Nashf186a912013-04-05 07:59:28 +0100130 colour = Colour::Error;
Phil Nash36824332013-01-18 17:50:21 +0000131 passOrFail = "FAILED";
132 }
Phil Nash207b27b2013-02-02 19:58:04 +0000133 if( _stats.infoMessages.size() == 1 )
Phil Nash36824332013-01-18 17:50:21 +0000134 messageLabel = "with message";
Phil Nash207b27b2013-02-02 19:58:04 +0000135 if( _stats.infoMessages.size() > 1 )
136 messageLabel = "with messages";
Phil Nash36824332013-01-18 17:50:21 +0000137 break;
138 case ResultWas::ThrewException:
Phil Nashf186a912013-04-05 07:59:28 +0100139 colour = Colour::Error;
Phil Nash36824332013-01-18 17:50:21 +0000140 passOrFail = "FAILED";
141 messageLabel = "due to unexpected exception with message";
142 break;
Phil Nashc1a8e1c2014-08-22 08:07:39 +0100143 case ResultWas::FatalErrorCondition:
144 colour = Colour::Error;
145 passOrFail = "FAILED";
146 messageLabel = "due to a fatal error condition";
147 break;
Phil Nash36824332013-01-18 17:50:21 +0000148 case ResultWas::DidntThrowException:
Phil Nashf186a912013-04-05 07:59:28 +0100149 colour = Colour::Error;
Phil Nash36824332013-01-18 17:50:21 +0000150 passOrFail = "FAILED";
151 messageLabel = "because no exception was thrown where one was expected";
152 break;
153 case ResultWas::Info:
154 messageLabel = "info";
155 break;
156 case ResultWas::Warning:
157 messageLabel = "warning";
158 break;
159 case ResultWas::ExplicitFailure:
160 passOrFail = "FAILED";
Phil Nashf186a912013-04-05 07:59:28 +0100161 colour = Colour::Error;
Phil Nash207b27b2013-02-02 19:58:04 +0000162 if( _stats.infoMessages.size() == 1 )
163 messageLabel = "explicitly with message";
164 if( _stats.infoMessages.size() > 1 )
165 messageLabel = "explicitly with messages";
Phil Nash36824332013-01-18 17:50:21 +0000166 break;
Phil Nash36824332013-01-18 17:50:21 +0000167 // These cases are here to prevent compiler warnings
168 case ResultWas::Unknown:
169 case ResultWas::FailureBit:
Phil Nash3bd42412013-04-08 12:05:32 +0100170 case ResultWas::Exception:
Phil Nash36824332013-01-18 17:50:21 +0000171 passOrFail = "** internal error **";
Phil Nashf186a912013-04-05 07:59:28 +0100172 colour = Colour::Error;
Phil Nash36824332013-01-18 17:50:21 +0000173 break;
174 }
175 }
Phil Nashf3d1f082013-07-03 19:14:59 +0100176
Phil Nash36824332013-01-18 17:50:21 +0000177 void print() const {
Phil Nash767f1582013-03-04 12:19:15 +0100178 printSourceInfo();
Phil Nash36824332013-01-18 17:50:21 +0000179 if( stats.totals.assertions.total() > 0 ) {
Phil Nash767f1582013-03-04 12:19:15 +0100180 if( result.isOk() )
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100181 stream << '\n';
Phil Nash36824332013-01-18 17:50:21 +0000182 printResultType();
183 printOriginalExpression();
184 printReconstructedExpression();
185 }
Phil Nash767f1582013-03-04 12:19:15 +0100186 else {
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100187 stream << '\n';
Phil Nash767f1582013-03-04 12:19:15 +0100188 }
Phil Nash36824332013-01-18 17:50:21 +0000189 printMessage();
Phil Nash36824332013-01-18 17:50:21 +0000190 }
Phil Nashf3d1f082013-07-03 19:14:59 +0100191
Phil Nash36824332013-01-18 17:50:21 +0000192 private:
193 void printResultType() const {
194 if( !passOrFail.empty() ) {
Phil Nashf186a912013-04-05 07:59:28 +0100195 Colour colourGuard( colour );
Phil Nash36824332013-01-18 17:50:21 +0000196 stream << passOrFail << ":\n";
197 }
198 }
199 void printOriginalExpression() const {
200 if( result.hasExpression() ) {
Phil Nashf186a912013-04-05 07:59:28 +0100201 Colour colourGuard( Colour::OriginalExpression );
Phil Nash36824332013-01-18 17:50:21 +0000202 stream << " ";
Phil Nashd4305372013-05-17 19:35:33 +0100203 stream << result.getExpressionInMacro();
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100204 stream << '\n';
Phil Nash36824332013-01-18 17:50:21 +0000205 }
206 }
207 void printReconstructedExpression() const {
208 if( result.hasExpandedExpression() ) {
209 stream << "with expansion:\n";
Phil Nashf186a912013-04-05 07:59:28 +0100210 Colour colourGuard( Colour::ReconstructedExpression );
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100211 stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n';
Phil Nash36824332013-01-18 17:50:21 +0000212 }
213 }
214 void printMessage() const {
215 if( !messageLabel.empty() )
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100216 stream << messageLabel << ':' << '\n';
Phil Nash207b27b2013-02-02 19:58:04 +0000217 for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
218 it != itEnd;
Phil Nashf3d1f082013-07-03 19:14:59 +0100219 ++it ) {
Phil Nash4f57c8c2013-11-13 08:07:38 +0000220 // If this assertion is a warning ignore any INFO messages
221 if( printInfoMessages || it->type != ResultWas::Info )
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100222 stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n';
Phil Nash207b27b2013-02-02 19:58:04 +0000223 }
Phil Nash36824332013-01-18 17:50:21 +0000224 }
225 void printSourceInfo() const {
Phil Nashf186a912013-04-05 07:59:28 +0100226 Colour colourGuard( Colour::FileName );
Phil Nash767f1582013-03-04 12:19:15 +0100227 stream << result.getSourceInfo() << ": ";
Phil Nash36824332013-01-18 17:50:21 +0000228 }
Phil Nashf3d1f082013-07-03 19:14:59 +0100229
Phil Nash36824332013-01-18 17:50:21 +0000230 std::ostream& stream;
231 AssertionStats const& stats;
232 AssertionResult const& result;
Phil Nashf186a912013-04-05 07:59:28 +0100233 Colour::Code colour;
Phil Nash36824332013-01-18 17:50:21 +0000234 std::string passOrFail;
235 std::string messageLabel;
236 std::string message;
Phil Nash207b27b2013-02-02 19:58:04 +0000237 std::vector<MessageInfo> messages;
Phil Nash4f57c8c2013-11-13 08:07:38 +0000238 bool printInfoMessages;
Phil Nash36824332013-01-18 17:50:21 +0000239 };
Phil Nashf3d1f082013-07-03 19:14:59 +0100240
Phil Nash60ed3c12013-01-14 18:51:49 +0000241 void lazyPrint() {
Phil Nashf3d1f082013-07-03 19:14:59 +0100242
Phil Nash1f519dd2013-08-08 08:24:37 +0100243 if( !currentTestRunInfo.used )
Phil Nash60ed3c12013-01-14 18:51:49 +0000244 lazyPrintRunInfo();
Phil Nash1f519dd2013-08-08 08:24:37 +0100245 if( !currentGroupInfo.used )
Phil Nash60ed3c12013-01-14 18:51:49 +0000246 lazyPrintGroupInfo();
Phil Nashf3d1f082013-07-03 19:14:59 +0100247
Phil Nashb7ff9952013-03-06 20:40:16 +0100248 if( !m_headerPrinted ) {
249 printTestCaseAndSectionHeader();
250 m_headerPrinted = true;
251 }
Phil Nash60ed3c12013-01-14 18:51:49 +0000252 }
253 void lazyPrintRunInfo() {
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100254 stream << '\n' << getLineOfChars<'~'>() << '\n';
Phil Nashf186a912013-04-05 07:59:28 +0100255 Colour colour( Colour::SecondaryText );
Phil Nash1f519dd2013-08-08 08:24:37 +0100256 stream << currentTestRunInfo->name
Kevin Usheye04dc512017-03-16 11:17:45 -0700257 << " is a Catch v" << libraryVersion() << " host application.\n"
Phil Nash60ed3c12013-01-14 18:51:49 +0000258 << "Run with -? for options\n\n";
Phil Nashf3d1f082013-07-03 19:14:59 +0100259
Phil Nashfa0122b2014-09-15 18:39:31 +0100260 if( m_config->rngSeed() != 0 )
261 stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
262
Phil Nash1f519dd2013-08-08 08:24:37 +0100263 currentTestRunInfo.used = true;
Phil Nash60ed3c12013-01-14 18:51:49 +0000264 }
265 void lazyPrintGroupInfo() {
Phil Nash1f519dd2013-08-08 08:24:37 +0100266 if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) {
267 printClosedHeader( "Group: " + currentGroupInfo->name );
268 currentGroupInfo.used = true;
Phil Nash60ed3c12013-01-14 18:51:49 +0000269 }
270 }
Phil Nashb7ff9952013-03-06 20:40:16 +0100271 void printTestCaseAndSectionHeader() {
Phil Nash29ccaa62013-08-08 08:05:19 +0100272 assert( !m_sectionStack.empty() );
Phil Nash1f519dd2013-08-08 08:24:37 +0100273 printOpenHeader( currentTestCaseInfo->name );
Phil Nashf3d1f082013-07-03 19:14:59 +0100274
Phil Nash29ccaa62013-08-08 08:05:19 +0100275 if( m_sectionStack.size() > 1 ) {
276 Colour colourGuard( Colour::Headers );
277
Phil Nash2ddb9d32013-08-15 18:39:55 +0100278 std::vector<SectionInfo>::const_iterator
Phil Nash29ccaa62013-08-08 08:05:19 +0100279 it = m_sectionStack.begin()+1, // Skip first section (test case)
280 itEnd = m_sectionStack.end();
281 for( ; it != itEnd; ++it )
Phil Nash2ddb9d32013-08-15 18:39:55 +0100282 printHeaderString( it->name, 2 );
Phil Nash60ed3c12013-01-14 18:51:49 +0000283 }
Phil Nash29ccaa62013-08-08 08:05:19 +0100284
Phil Nashab44fb62017-02-10 11:56:46 +0000285 SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
Phil Nashf3d1f082013-07-03 19:14:59 +0100286
Phil Nashbd5910e2013-04-17 00:05:25 +0100287 if( !lineInfo.empty() ){
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100288 stream << getLineOfChars<'-'>() << '\n';
Phil Nashbd5910e2013-04-17 00:05:25 +0100289 Colour colourGuard( Colour::FileName );
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100290 stream << lineInfo << '\n';
Phil Nashbd5910e2013-04-17 00:05:25 +0100291 }
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100292 stream << getLineOfChars<'.'>() << '\n' << std::endl;
Phil Nash60ed3c12013-01-14 18:51:49 +0000293 }
Phil Nash0a877952013-01-16 09:39:08 +0000294
Phil Nashb7ff9952013-03-06 20:40:16 +0100295 void printClosedHeader( std::string const& _name ) {
296 printOpenHeader( _name );
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100297 stream << getLineOfChars<'.'>() << '\n';
Phil Nashb7ff9952013-03-06 20:40:16 +0100298 }
Phil Nash7059c6e2013-04-19 19:08:32 +0100299 void printOpenHeader( std::string const& _name ) {
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100300 stream << getLineOfChars<'-'>() << '\n';
Phil Nash2c905332013-04-01 11:25:54 +0100301 {
Phil Nashf186a912013-04-05 07:59:28 +0100302 Colour colourGuard( Colour::Headers );
Phil Nash7059c6e2013-04-19 19:08:32 +0100303 printHeaderString( _name );
Phil Nash2c905332013-04-01 11:25:54 +0100304 }
Phil Nash60ed3c12013-01-14 18:51:49 +0000305 }
Phil Nash7059c6e2013-04-19 19:08:32 +0100306
Phil Nash4746caa2013-04-05 20:55:57 +0100307 // if string has a : in first line will set indent to follow it on
308 // subsequent lines
Phil Nash7059c6e2013-04-19 19:08:32 +0100309 void printHeaderString( std::string const& _string, std::size_t indent = 0 ) {
Phil Nash4746caa2013-04-05 20:55:57 +0100310 std::size_t i = _string.find( ": " );
311 if( i != std::string::npos )
312 i+=2;
313 else
314 i = 0;
Phil Nashb3acf452013-04-20 19:36:40 +0100315 stream << Text( _string, TextAttributes()
316 .setIndent( indent+i)
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100317 .setInitialIndent( indent ) ) << '\n';
Phil Nash4746caa2013-04-05 20:55:57 +0100318 }
Phil Nashf3d1f082013-07-03 19:14:59 +0100319
Phil Nash76f80a62014-07-09 19:20:24 +0100320 struct SummaryColumn {
321
322 SummaryColumn( std::string const& _label, Colour::Code _colour )
323 : label( _label ),
324 colour( _colour )
325 {}
326 SummaryColumn addRow( std::size_t count ) {
327 std::ostringstream oss;
328 oss << count;
329 std::string row = oss.str();
330 for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) {
331 while( it->size() < row.size() )
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100332 *it = ' ' + *it;
Phil Nash76f80a62014-07-09 19:20:24 +0100333 while( it->size() > row.size() )
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100334 row = ' ' + row;
Phil Nash76f80a62014-07-09 19:20:24 +0100335 }
336 rows.push_back( row );
337 return *this;
338 }
339
340 std::string label;
341 Colour::Code colour;
342 std::vector<std::string> rows;
343
344 };
345
Phil Nash9c1f9a82014-07-03 08:09:57 +0100346 void printTotals( Totals const& totals ) {
Phil Nash2f086ae2013-11-12 19:06:08 +0000347 if( totals.testCases.total() == 0 ) {
Phil Nash9c1f9a82014-07-03 08:09:57 +0100348 stream << Colour( Colour::Warning ) << "No tests ran\n";
Phil Nash60ed3c12013-01-14 18:51:49 +0000349 }
Phil Nash447f53e2016-03-14 19:13:34 +0000350 else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) {
Phil Nash9c1f9a82014-07-03 08:09:57 +0100351 stream << Colour( Colour::ResultSuccess ) << "All tests passed";
352 stream << " ("
Phil Nash60ed3c12013-01-14 18:51:49 +0000353 << pluralise( totals.assertions.passed, "assertion" ) << " in "
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100354 << pluralise( totals.testCases.passed, "test case" ) << ')'
355 << '\n';
Phil Nash60ed3c12013-01-14 18:51:49 +0000356 }
Phil Nash76f80a62014-07-09 19:20:24 +0100357 else {
Phil Nash9c1f9a82014-07-03 08:09:57 +0100358
Phil Nash76f80a62014-07-09 19:20:24 +0100359 std::vector<SummaryColumn> columns;
360 columns.push_back( SummaryColumn( "", Colour::None )
361 .addRow( totals.testCases.total() )
362 .addRow( totals.assertions.total() ) );
363 columns.push_back( SummaryColumn( "passed", Colour::Success )
364 .addRow( totals.testCases.passed )
365 .addRow( totals.assertions.passed ) );
366 columns.push_back( SummaryColumn( "failed", Colour::ResultError )
367 .addRow( totals.testCases.failed )
368 .addRow( totals.assertions.failed ) );
369 columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure )
370 .addRow( totals.testCases.failedButOk )
371 .addRow( totals.assertions.failedButOk ) );
Phil Nash9c1f9a82014-07-03 08:09:57 +0100372
Phil Nash76f80a62014-07-09 19:20:24 +0100373 printSummaryRow( "test cases", columns, 0 );
374 printSummaryRow( "assertions", columns, 1 );
Phil Nash6fb82602012-12-11 08:27:21 +0000375 }
Phil Nash76f80a62014-07-09 19:20:24 +0100376 }
377 void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) {
378 for( std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it ) {
379 std::string value = it->rows[row];
380 if( it->label.empty() ) {
381 stream << label << ": ";
382 if( value != "0" )
383 stream << value;
384 else
385 stream << Colour( Colour::Warning ) << "- none -";
386 }
387 else if( value != "0" ) {
388 stream << Colour( Colour::LightGrey ) << " | ";
389 stream << Colour( it->colour )
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100390 << value << ' ' << it->label;
Phil Nash76f80a62014-07-09 19:20:24 +0100391 }
392 }
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100393 stream << '\n';
Phil Nashff03cdf2012-12-06 08:44:51 +0000394 }
Phil Nashf3d1f082013-07-03 19:14:59 +0100395
Phil Nash9c1f9a82014-07-03 08:09:57 +0100396 static std::size_t makeRatio( std::size_t number, std::size_t total ) {
397 std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0;
398 return ( ratio == 0 && number > 0 ) ? 1 : ratio;
399 }
400 static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) {
401 if( i > j && i > k )
402 return i;
403 else if( j > k )
404 return j;
405 else
406 return k;
407 }
408
409 void printTotalsDivider( Totals const& totals ) {
410 if( totals.testCases.total() > 0 ) {
411 std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() );
412 std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() );
413 std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() );
414 while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 )
415 findMax( failedRatio, failedButOkRatio, passedRatio )++;
416 while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 )
417 findMax( failedRatio, failedButOkRatio, passedRatio )--;
418
Phil Nash9c1f9a82014-07-03 08:09:57 +0100419 stream << Colour( Colour::Error ) << std::string( failedRatio, '=' );
420 stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' );
Phil Nashcab91412014-07-09 18:24:24 +0100421 if( totals.testCases.allPassed() )
422 stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' );
423 else
424 stream << Colour( Colour::Success ) << std::string( passedRatio, '=' );
Phil Nash9c1f9a82014-07-03 08:09:57 +0100425 }
426 else {
427 stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' );
428 }
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100429 stream << '\n';
Phil Nasha7079a22012-12-13 12:46:47 +0000430 }
Phil Nash42aef1d2013-01-13 21:51:44 +0000431 void printSummaryDivider() {
Martin Hořeňovskýbcaa2f92017-01-29 23:07:15 +0100432 stream << getLineOfChars<'-'>() << '\n';
Phil Nasha7079a22012-12-13 12:46:47 +0000433 }
Phil Nashf3d1f082013-07-03 19:14:59 +0100434
Phil Nash42aef1d2013-01-13 21:51:44 +0000435 private:
Phil Nashb7ff9952013-03-06 20:40:16 +0100436 bool m_headerPrinted;
Phil Nashfe981232012-12-05 08:40:53 +0000437 };
438
439 INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter )
440
441} // end namespace Catch
442
443#endif // TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED