| /* |
| * Created by Martin on 2017-11-14. |
| * |
| * Distributed under the Boost Software License, Version 1.0. (See accompanying |
| * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| */ |
| |
| #include "catch_reporter_compact.h" |
| |
| #include "../internal/catch_reporter_registrars.hpp" |
| #include "../internal/catch_console_colour.h" |
| |
| namespace { |
| |
| #ifdef CATCH_PLATFORM_MAC |
| const char* failedString() { return "FAILED"; } |
| const char* passedString() { return "PASSED"; } |
| #else |
| const char* failedString() { return "failed"; } |
| const char* passedString() { return "passed"; } |
| #endif |
| |
| // Colour::LightGrey |
| Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } |
| |
| std::string bothOrAll( std::size_t count ) { |
| return count == 1 ? std::string() : |
| count == 2 ? "both " : "all " ; |
| } |
| |
| } // anon namespace |
| |
| |
| namespace Catch { |
| namespace { |
| // Colour, message variants: |
| // - white: No tests ran. |
| // - red: Failed [both/all] N test cases, failed [both/all] M assertions. |
| // - white: Passed [both/all] N test cases (no assertions). |
| // - red: Failed N tests cases, failed M assertions. |
| // - green: Passed [both/all] N tests cases with M assertions. |
| void printTotals(std::ostream& out, const Totals& totals) { |
| if (totals.testCases.total() == 0) { |
| out << "No tests ran."; |
| } else if (totals.testCases.failed == totals.testCases.total()) { |
| Colour colour(Colour::ResultError); |
| const std::string qualify_assertions_failed = |
| totals.assertions.failed == totals.assertions.total() ? |
| bothOrAll(totals.assertions.failed) : std::string(); |
| out << |
| "Failed " << bothOrAll(totals.testCases.failed) |
| << pluralise(totals.testCases.failed, "test case") << ", " |
| "failed " << qualify_assertions_failed << |
| pluralise(totals.assertions.failed, "assertion") << '.'; |
| } else if (totals.assertions.total() == 0) { |
| out << |
| "Passed " << bothOrAll(totals.testCases.total()) |
| << pluralise(totals.testCases.total(), "test case") |
| << " (no assertions)."; |
| } else if (totals.assertions.failed) { |
| Colour colour(Colour::ResultError); |
| out << |
| "Failed " << pluralise(totals.testCases.failed, "test case") << ", " |
| "failed " << pluralise(totals.assertions.failed, "assertion") << '.'; |
| } else { |
| Colour colour(Colour::ResultSuccess); |
| out << |
| "Passed " << bothOrAll(totals.testCases.passed) |
| << pluralise(totals.testCases.passed, "test case") << |
| " with " << pluralise(totals.assertions.passed, "assertion") << '.'; |
| } |
| } |
| |
| // Implementation of CompactReporter formatting |
| class AssertionPrinter { |
| public: |
| AssertionPrinter& operator= (AssertionPrinter const&) = delete; |
| AssertionPrinter(AssertionPrinter const&) = delete; |
| AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) |
| : stream(_stream) |
| , result(_stats.assertionResult) |
| , messages(_stats.infoMessages) |
| , itMessage(_stats.infoMessages.begin()) |
| , printInfoMessages(_printInfoMessages) {} |
| |
| void print() { |
| printSourceInfo(); |
| |
| itMessage = messages.begin(); |
| |
| switch (result.getResultType()) { |
| case ResultWas::Ok: |
| printResultType(Colour::ResultSuccess, passedString()); |
| printOriginalExpression(); |
| printReconstructedExpression(); |
| if (!result.hasExpression()) |
| printRemainingMessages(Colour::None); |
| else |
| printRemainingMessages(); |
| break; |
| case ResultWas::ExpressionFailed: |
| if (result.isOk()) |
| printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok")); |
| else |
| printResultType(Colour::Error, failedString()); |
| printOriginalExpression(); |
| printReconstructedExpression(); |
| printRemainingMessages(); |
| break; |
| case ResultWas::ThrewException: |
| printResultType(Colour::Error, failedString()); |
| printIssue("unexpected exception with message:"); |
| printMessage(); |
| printExpressionWas(); |
| printRemainingMessages(); |
| break; |
| case ResultWas::FatalErrorCondition: |
| printResultType(Colour::Error, failedString()); |
| printIssue("fatal error condition with message:"); |
| printMessage(); |
| printExpressionWas(); |
| printRemainingMessages(); |
| break; |
| case ResultWas::DidntThrowException: |
| printResultType(Colour::Error, failedString()); |
| printIssue("expected exception, got none"); |
| printExpressionWas(); |
| printRemainingMessages(); |
| break; |
| case ResultWas::Info: |
| printResultType(Colour::None, "info"); |
| printMessage(); |
| printRemainingMessages(); |
| break; |
| case ResultWas::Warning: |
| printResultType(Colour::None, "warning"); |
| printMessage(); |
| printRemainingMessages(); |
| break; |
| case ResultWas::ExplicitFailure: |
| printResultType(Colour::Error, failedString()); |
| printIssue("explicitly"); |
| printRemainingMessages(Colour::None); |
| break; |
| // These cases are here to prevent compiler warnings |
| case ResultWas::Unknown: |
| case ResultWas::FailureBit: |
| case ResultWas::Exception: |
| printResultType(Colour::Error, "** internal error **"); |
| break; |
| } |
| } |
| |
| private: |
| void printSourceInfo() const { |
| Colour colourGuard(Colour::FileName); |
| stream << result.getSourceInfo() << ':'; |
| } |
| |
| void printResultType(Colour::Code colour, std::string const& passOrFail) const { |
| if (!passOrFail.empty()) { |
| { |
| Colour colourGuard(colour); |
| stream << ' ' << passOrFail; |
| } |
| stream << ':'; |
| } |
| } |
| |
| void printIssue(std::string const& issue) const { |
| stream << ' ' << issue; |
| } |
| |
| void printExpressionWas() { |
| if (result.hasExpression()) { |
| stream << ';'; |
| { |
| Colour colour(dimColour()); |
| stream << " expression was:"; |
| } |
| printOriginalExpression(); |
| } |
| } |
| |
| void printOriginalExpression() const { |
| if (result.hasExpression()) { |
| stream << ' ' << result.getExpression(); |
| } |
| } |
| |
| void printReconstructedExpression() const { |
| if (result.hasExpandedExpression()) { |
| { |
| Colour colour(dimColour()); |
| stream << " for: "; |
| } |
| stream << result.getExpandedExpression(); |
| } |
| } |
| |
| void printMessage() { |
| if (itMessage != messages.end()) { |
| stream << " '" << itMessage->message << '\''; |
| ++itMessage; |
| } |
| } |
| |
| void printRemainingMessages(Colour::Code colour = dimColour()) { |
| if (itMessage == messages.end()) |
| return; |
| |
| const auto itEnd = messages.cend(); |
| const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd)); |
| |
| { |
| Colour colourGuard(colour); |
| stream << " with " << pluralise(N, "message") << ':'; |
| } |
| |
| while (itMessage != itEnd) { |
| // If this assertion is a warning ignore any INFO messages |
| if (printInfoMessages || itMessage->type != ResultWas::Info) { |
| printMessage(); |
| if (itMessage != itEnd) { |
| Colour colourGuard(dimColour()); |
| stream << " and"; |
| } |
| continue; |
| } |
| ++itMessage; |
| } |
| } |
| |
| private: |
| std::ostream& stream; |
| AssertionResult const& result; |
| std::vector<MessageInfo> messages; |
| std::vector<MessageInfo>::const_iterator itMessage; |
| bool printInfoMessages; |
| }; |
| |
| } // anon namespace |
| |
| std::string CompactReporter::getDescription() { |
| return "Reports test results on a single line, suitable for IDEs"; |
| } |
| |
| ReporterPreferences CompactReporter::getPreferences() const { |
| return m_reporterPrefs; |
| } |
| |
| void CompactReporter::noMatchingTestCases( std::string const& spec ) { |
| stream << "No test cases matched '" << spec << '\'' << std::endl; |
| } |
| |
| void CompactReporter::assertionStarting( AssertionInfo const& ) {} |
| |
| bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { |
| AssertionResult const& result = _assertionStats.assertionResult; |
| |
| bool printInfoMessages = true; |
| |
| // Drop out if result was successful and we're not printing those |
| if( !m_config->includeSuccessfulResults() && result.isOk() ) { |
| if( result.getResultType() != ResultWas::Warning ) |
| return false; |
| printInfoMessages = false; |
| } |
| |
| AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); |
| printer.print(); |
| |
| stream << std::endl; |
| return true; |
| } |
| |
| void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { |
| if (m_config->showDurations() == ShowDurations::Always) { |
| stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; |
| } |
| } |
| |
| void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { |
| printTotals( stream, _testRunStats.totals ); |
| stream << '\n' << std::endl; |
| StreamingReporterBase::testRunEnded( _testRunStats ); |
| } |
| |
| CompactReporter::~CompactReporter() {} |
| |
| CATCH_REGISTER_REPORTER( "compact", CompactReporter ) |
| |
| } // end namespace Catch |