22#pragma warning(disable:4061)
33class ConsoleAssertionPrinter {
35 ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter
const&) =
delete;
36 ConsoleAssertionPrinter(ConsoleAssertionPrinter
const&) =
delete;
37 ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats
const& _stats,
bool _printInfoMessages)
40 result(_stats.assertionResult),
42 message(result.getMessage()),
43 messages(_stats.infoMessages),
44 printInfoMessages(_printInfoMessages) {
45 switch (result.getResultType()) {
47 colour = Colour::Success;
48 passOrFail =
"PASSED";
50 if (_stats.infoMessages.size() == 1)
51 messageLabel =
"with message";
52 if (_stats.infoMessages.size() > 1)
53 messageLabel =
"with messages";
55 case ResultWas::ExpressionFailed:
57 colour = Colour::Success;
58 passOrFail =
"FAILED - but was ok";
60 colour = Colour::Error;
61 passOrFail =
"FAILED";
63 if (_stats.infoMessages.size() == 1)
64 messageLabel =
"with message";
65 if (_stats.infoMessages.size() > 1)
66 messageLabel =
"with messages";
70 passOrFail =
"FAILED";
71 messageLabel =
"due to unexpected exception with ";
72 if (_stats.infoMessages.size() == 1)
73 messageLabel +=
"message";
74 if (_stats.infoMessages.size() > 1)
75 messageLabel +=
"messages";
79 passOrFail =
"FAILED";
80 messageLabel =
"due to a fatal error condition";
84 passOrFail =
"FAILED";
85 messageLabel =
"because no exception was thrown where one was expected";
88 messageLabel =
"info";
91 messageLabel =
"warning";
94 passOrFail =
"FAILED";
96 if (_stats.infoMessages.size() == 1)
97 messageLabel =
"explicitly with message";
98 if (_stats.infoMessages.size() > 1)
99 messageLabel =
"explicitly with messages";
105 passOrFail =
"** internal error **";
115 printOriginalExpression();
116 printReconstructedExpression();
124 void printResultType()
const {
125 if (!passOrFail.empty()) {
126 Colour colourGuard(colour);
127 stream << passOrFail <<
":\n";
130 void printOriginalExpression()
const {
138 void printReconstructedExpression()
const {
140 stream <<
"with expansion:\n";
145 void printMessage()
const {
146 if (!messageLabel.empty())
147 stream << messageLabel <<
':' <<
'\n';
148 for (
auto const& msg : messages) {
151 stream << Column(msg.message).indent(2) <<
'\n';
154 void printSourceInfo()
const {
159 std::ostream& stream;
160 AssertionStats
const& stats;
161 AssertionResult
const& result;
163 std::string passOrFail;
164 std::string messageLabel;
166 std::vector<MessageInfo> messages;
167 bool printInfoMessages;
170std::size_t makeRatio(std::size_t number, std::size_t total) {
172 return (ratio == 0 && number > 0) ? 1 :
ratio;
175std::size_t& findMax(std::size_t& i, std::size_t&
j, std::size_t& k) {
185 enum Justification { Left, Right };
190struct ColumnBreak {};
202 static const uint64_t s_nanosecondsInAMicrosecond = 1000;
203 static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond;
204 static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
205 static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
211 explicit Duration(
uint64_t inNanoseconds, Unit units = Unit::Auto)
212 : m_inNanoseconds(inNanoseconds),
214 if (m_units == Unit::Auto) {
215 if (m_inNanoseconds < s_nanosecondsInAMicrosecond)
216 m_units = Unit::Nanoseconds;
217 else if (m_inNanoseconds < s_nanosecondsInAMillisecond)
218 m_units = Unit::Microseconds;
219 else if (m_inNanoseconds < s_nanosecondsInASecond)
220 m_units = Unit::Milliseconds;
221 else if (m_inNanoseconds < s_nanosecondsInAMinute)
222 m_units = Unit::Seconds;
224 m_units = Unit::Minutes;
229 auto value() const ->
double {
231 case Unit::Microseconds:
232 return m_inNanoseconds /
static_cast<double>(s_nanosecondsInAMicrosecond);
233 case Unit::Milliseconds:
234 return m_inNanoseconds /
static_cast<double>(s_nanosecondsInAMillisecond);
236 return m_inNanoseconds /
static_cast<double>(s_nanosecondsInASecond);
238 return m_inNanoseconds /
static_cast<double>(s_nanosecondsInAMinute);
240 return static_cast<double>(m_inNanoseconds);
243 auto unitsAsString() const ->
std::
string {
245 case Unit::Nanoseconds:
247 case Unit::Microseconds:
249 case Unit::Milliseconds:
256 return "** internal error **";
260 friend auto operator << (std::ostream&
os, Duration
const& duration) -> std::ostream& {
261 return os << duration.value() <<
" " << duration.unitsAsString();
268 std::vector<ColumnInfo> m_columnInfos;
269 std::ostringstream m_oss;
270 int m_currentColumn = -1;
271 bool m_isOpen =
false;
276 m_columnInfos(
std::move( columnInfos ) ) {}
279 return m_columnInfos;
286 for (
auto const& info : m_columnInfos)
287 *
this << info.name << ColumnBreak();
307 auto colStr = tp.m_oss.str();
312 if (tp.m_currentColumn ==
static_cast<int>(tp.m_columnInfos.size() - 1)) {
313 tp.m_currentColumn = -1;
316 tp.m_currentColumn++;
318 auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
319 auto padding = (strSize + 2 <
static_cast<std::size_t
>(colInfo.width))
320 ? std::string(colInfo.width - (strSize + 2),
' ')
322 if (colInfo.justification == ColumnInfo::Left)
323 tp.m_os << colStr << padding <<
" ";
325 tp.m_os << padding << colStr <<
" ";
330 if (tp.m_currentColumn > 0) {
332 tp.m_currentColumn = -1;
343 {
"iters", 8, ColumnInfo::Right },
344 {
"elapsed ns", 14, ColumnInfo::Right },
345 {
"average", 14, ColumnInfo::Right }
350 return "Reports test results as plain lines of text";
354 stream <<
"No test cases matched '" << spec <<
'\'' << std::endl;
362 bool includeResults =
m_config->includeSuccessfulResults() || !result.isOk();
370 ConsoleAssertionPrinter printer(
stream, _assertionStats, includeResults);
377 m_headerPrinted =
false;
386 stream <<
"\nNo assertions in section";
388 stream <<
"\nNo assertions in test case";
394 if (m_headerPrinted) {
395 m_headerPrinted =
false;
402 lazyPrintWithoutClosingBenchmarkTable();
406 bool firstLine =
true;
407 for (
auto line : nameCol) {
409 (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
413 (*m_tablePrinter) << line << ColumnBreak();
417 Duration average(stats.elapsedTimeInNanoseconds / stats.iterations);
419 << stats.iterations << ColumnBreak()
420 << stats.elapsedTimeInNanoseconds << ColumnBreak()
421 << average << ColumnBreak();
427 m_headerPrinted =
false;
431 printSummaryDivider();
433 printTotals(_testGroupStats.
totals);
434 stream <<
'\n' << std::endl;
439 printTotalsDivider(_testRunStats.
totals);
440 printTotals(_testRunStats.
totals);
449void ConsoleReporter::lazyPrint() {
452 lazyPrintWithoutClosingBenchmarkTable();
455void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() {
460 lazyPrintGroupInfo();
462 if (!m_headerPrinted) {
463 printTestCaseAndSectionHeader();
464 m_headerPrinted =
true;
467void ConsoleReporter::lazyPrintRunInfo() {
472 <<
"Run with -? for options\n\n";
475 stream <<
"Randomness seeded to: " <<
m_config->rngSeed() <<
"\n\n";
479void ConsoleReporter::lazyPrintGroupInfo() {
485void ConsoleReporter::printTestCaseAndSectionHeader() {
495 for (; it != itEnd; ++it)
496 printHeaderString(it->name, 2);
501 if (!lineInfo.empty()) {
504 stream << lineInfo <<
'\n';
509void ConsoleReporter::printClosedHeader(std::string
const& _name) {
510 printOpenHeader(_name);
513void ConsoleReporter::printOpenHeader(std::string
const& _name) {
517 printHeaderString(_name);
523void ConsoleReporter::printHeaderString(std::string
const& _string, std::size_t indent) {
524 std::size_t i = _string.find(
": ");
525 if (i != std::string::npos)
529 stream << Column(_string).indent(indent + i).initialIndent(indent) <<
'\n';
540 std::string row = rss.
str();
541 for (
auto& oldRow :
rows) {
542 while (oldRow.size() < row.size())
543 oldRow =
' ' + oldRow;
544 while (oldRow.size() > row.size())
557void ConsoleReporter::printTotals(
Totals const& totals ) {
568 std::vector<SummaryColumn> columns;
582 printSummaryRow(
"test cases", columns, 0);
583 printSummaryRow(
"assertions", columns, 1);
586void ConsoleReporter::printSummaryRow(std::string
const&
label, std::vector<SummaryColumn>
const& cols, std::size_t row) {
587 for (
auto col : cols) {
588 std::string
value = col.rows[row];
589 if (col.label.empty()) {
595 }
else if (
value !=
"0") {
597 stream << Colour(col.colour)
598 <<
value <<
' ' << col.label;
604void ConsoleReporter::printTotalsDivider(Totals
const& totals) {
605 if (totals.testCases.total() > 0) {
606 std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
607 std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
608 std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());
610 findMax(failedRatio, failedButOkRatio, passedRatio)++;
612 findMax(failedRatio, failedButOkRatio, passedRatio)--;
616 if (totals.testCases.allPassed())
625void ConsoleReporter::printSummaryDivider() {
629void ConsoleReporter::printTestFilters() {
630 if (
m_config->testSpec().hasFilters())
void print(std::ostream &os, int const level, std::string const &title, Catch::SourceLineInfo const &info)
#define CATCH_CONFIG_CONSOLE_WIDTH
Justification justification
#define CATCH_REGISTER_REPORTER(name, reporterType)
bool hasExpandedExpression() const
SourceLineInfo getSourceInfo() const
std::string getExpandedExpression() const
std::string getExpressionInMacro() const
bool hasExpression() const
auto str() const -> std::string
auto numberOfCharacters() const noexcept -> size_type
auto columnInfos() const -> std::vector< ColumnInfo > const &
TablePrinter(std::ostream &os, std::vector< ColumnInfo > columnInfos)
auto width(size_t newWidth) -> Column &
DataStream & operator<<(DataStream &ds, const float64_t &v)
char const * getLineOfChars()
Version const & libraryVersion()
std::string serializeFilters(std::vector< std::string > const &container)
auto operator<<(std::ostream &os, LazyExpression const &lazyExpr) -> std::ostream &
std::string getFormattedDuration(double duration)
impl::ratio< uint64_t > ratio
#define T(meth, val, expected)
unsigned __int64 uint64_t
AssertionResult assertionResult
@ ReconstructedExpression
void testCaseEnded(TestCaseStats const &_testCaseStats) override
static std::string getDescription()
void sectionStarting(SectionInfo const &_sectionInfo) override
void testRunEnded(TestRunStats const &_testRunStats) override
void benchmarkStarting(BenchmarkInfo const &info) override
void noMatchingTestCases(std::string const &spec) override
std::unique_ptr< TablePrinter > m_tablePrinter
void sectionEnded(SectionStats const &_sectionStats) override
void testRunStarting(TestRunInfo const &_testRunInfo) override
bool assertionEnded(AssertionStats const &_assertionStats) override
void assertionStarting(AssertionInfo const &) override
void testGroupEnded(TestGroupStats const &_testGroupStats) override
void benchmarkEnded(BenchmarkStats const &stats) override
~ConsoleReporter() override
std::size_t total() const
LazyStat< GroupInfo > currentGroupInfo
void sectionStarting(SectionInfo const &_sectionInfo) override
void testRunStarting(TestRunInfo const &_testRunInfo) override
std::vector< SectionInfo > m_sectionStack
void testRunEnded(TestRunStats const &) override
LazyStat< TestCaseInfo > currentTestCaseInfo
void sectionEnded(SectionStats const &) override
LazyStat< TestRunInfo > currentTestRunInfo
void testCaseEnded(TestCaseStats const &) override
void testGroupEnded(TestGroupStats const &) override
SummaryColumn(std::string _label, Colour::Code _colour)
std::vector< std::string > rows
SummaryColumn addRow(std::size_t count)