From 6798c139a65f97ce5ed0105a2a8adb28262ef7f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Mon, 25 Jan 2021 12:22:54 +0100 Subject: [PATCH] Extract the default listing implementation out of reporter interface Also generalized the implementations to write to the provided output stream, which will be required for the follow up changes, where the listings should happen to the location user asked for by specifying the `-o` flag. --- .../interfaces/catch_interfaces_reporter.cpp | 105 ++------------- .../reporters/catch_reporter_combined_tu.cpp | 124 +++++++++++++++++- .../reporters/catch_reporter_helpers.hpp | 40 ++++++ 3 files changed, 171 insertions(+), 98 deletions(-) diff --git a/src/catch2/interfaces/catch_interfaces_reporter.cpp b/src/catch2/interfaces/catch_interfaces_reporter.cpp index a2a8bebfe5..29fafecfd3 100644 --- a/src/catch2/interfaces/catch_interfaces_reporter.cpp +++ b/src/catch2/interfaces/catch_interfaces_reporter.cpp @@ -11,34 +11,15 @@ #include #include #include -#include #include #include -#include +#include #include #include namespace Catch { - namespace { - void listTestNamesOnly( std::vector const& tests ) { - for ( auto const& test : tests ) { - auto const& testCaseInfo = test.getTestCaseInfo(); - - if ( startsWith( testCaseInfo.name, '#' ) ) { - Catch::cout() << '"' << testCaseInfo.name << '"'; - } else { - Catch::cout() << testCaseInfo.name; - } - - Catch::cout() << '\n'; - } - Catch::cout() << std::flush; - } - } // end unnamed namespace - - ReporterConfig::ReporterConfig( IConfig const* _fullConfig ) : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} @@ -128,89 +109,19 @@ namespace Catch { void IStreamingReporter::fatalErrorEncountered( StringRef ) {} void IStreamingReporter::listReporters(std::vector const& descriptions) { - Catch::cout() << "Available reporters:\n"; - const auto maxNameLen = std::max_element(descriptions.begin(), descriptions.end(), - [](ReporterDescription const& lhs, ReporterDescription const& rhs) { return lhs.name.size() < rhs.name.size(); }) - ->name.size(); - - for (auto const& desc : descriptions) { - if (m_config->verbosity() == Verbosity::Quiet) { - Catch::cout() - << TextFlow::Column(desc.name) - .indent(2) - .width(5 + maxNameLen) << '\n'; - } else { - Catch::cout() - << TextFlow::Column(desc.name + ":") - .indent(2) - .width(5 + maxNameLen) - + TextFlow::Column(desc.description) - .initialIndent(0) - .indent(2) - .width(CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8) - << '\n'; - } - } - Catch::cout() << std::endl; + defaultListReporters( + Catch::cout(), descriptions, m_config->verbosity() ); } void IStreamingReporter::listTests(std::vector const& tests) { - // We special case this to provide the equivalent of old - // `--list-test-names-only`, which could then be used by the - // `--input-file` option. - if (m_config->verbosity() == Verbosity::Quiet) { - listTestNamesOnly(tests); - return; - } - - if (m_config->hasTestFilters()) { - Catch::cout() << "Matching test cases:\n"; - } else { - Catch::cout() << "All available test cases:\n"; - } - - for (auto const& test : tests) { - auto const& testCaseInfo = test.getTestCaseInfo(); - Colour::Code colour = testCaseInfo.isHidden() - ? Colour::SecondaryText - : Colour::None; - Colour colourGuard(colour); - - Catch::cout() << TextFlow::Column(testCaseInfo.name).initialIndent(2).indent(4) << '\n'; - if (m_config->verbosity() >= Verbosity::High) { - Catch::cout() << TextFlow::Column(Catch::Detail::stringify(testCaseInfo.lineInfo)).indent(4) << std::endl; - } - if ( !testCaseInfo.tags.empty() && - m_config->verbosity() > Verbosity::Quiet ) { - Catch::cout() << TextFlow::Column(testCaseInfo.tagsAsString()).indent(6) << '\n'; - } - } - - if (m_config->hasTestFilters()) { - Catch::cout() << pluralise(tests.size(), "matching test case") << '\n' << std::endl; - } else { - Catch::cout() << pluralise(tests.size(), "test case") << '\n' << std::endl; - } + defaultListTests( Catch::cout(), + tests, + m_config->hasTestFilters(), + m_config->verbosity() ); } void IStreamingReporter::listTags(std::vector const& tags) { - if (m_config->hasTestFilters()) { - Catch::cout() << "Tags for matching test cases:\n"; - } else { - Catch::cout() << "All available tags:\n"; - } - - for (auto const& tagCount : tags) { - ReusableStringStream rss; - rss << " " << std::setw(2) << tagCount.count << " "; - auto str = rss.str(); - auto wrapper = TextFlow::Column(tagCount.all()) - .initialIndent(0) - .indent(str.size()) - .width(CATCH_CONFIG_CONSOLE_WIDTH - 10); - Catch::cout() << str << wrapper << '\n'; - } - Catch::cout() << pluralise(tags.size(), "tag") << '\n' << std::endl; + defaultListTags( Catch::cout(), tags, m_config->hasTestFilters() ); } } // end namespace Catch diff --git a/src/catch2/reporters/catch_reporter_combined_tu.cpp b/src/catch2/reporters/catch_reporter_combined_tu.cpp index 0a15c09836..25a52e9dac 100644 --- a/src/catch2/reporters/catch_reporter_combined_tu.cpp +++ b/src/catch2/reporters/catch_reporter_combined_tu.cpp @@ -21,13 +21,40 @@ #include #include #include - +#include +#include +#include +#include +#include +#include + +#include #include #include #include +#include namespace Catch { + namespace { + void listTestNamesOnly(std::ostream& out, + std::vector const& tests) { + for (auto const& test : tests) { + auto const& testCaseInfo = test.getTestCaseInfo(); + + if (startsWith(testCaseInfo.name, '#')) { + out << '"' << testCaseInfo.name << '"'; + } else { + out << testCaseInfo.name; + } + + out << '\n'; + } + out << std::flush; + } + } // end unnamed namespace + + // Because formatting using c++ streams is stateful, drop down to C is // required Alternatively we could use stringstream, but its performance // is... not good. @@ -89,6 +116,101 @@ namespace Catch { return out; } + void + defaultListReporters( std::ostream& out, + std::vector const& descriptions, + Verbosity verbosity ) { + out << "Available reporters:\n"; + const auto maxNameLen = + std::max_element( descriptions.begin(), + descriptions.end(), + []( ReporterDescription const& lhs, + ReporterDescription const& rhs ) { + return lhs.name.size() < rhs.name.size(); + } ) + ->name.size(); + + for ( auto const& desc : descriptions ) { + if ( verbosity == Verbosity::Quiet ) { + out << TextFlow::Column( desc.name ) + .indent( 2 ) + .width( 5 + maxNameLen ) + << '\n'; + } else { + out << TextFlow::Column( desc.name + ":" ) + .indent( 2 ) + .width( 5 + maxNameLen ) + + TextFlow::Column( desc.description ) + .initialIndent( 0 ) + .indent( 2 ) + .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8 ) + << '\n'; + } + } + out << '\n' << std::flush; + } + + void defaultListTags( std::ostream& out, + std::vector const& tags, + bool isFiltered ) { + if ( isFiltered ) { + out << "Tags for matching test cases:\n"; + } else { + out << "All available tags:\n"; + } + + for ( auto const& tagCount : tags ) { + ReusableStringStream rss; + rss << " " << std::setw( 2 ) << tagCount.count << " "; + auto str = rss.str(); + auto wrapper = TextFlow::Column( tagCount.all() ) + .initialIndent( 0 ) + .indent( str.size() ) + .width( CATCH_CONFIG_CONSOLE_WIDTH - 10 ); + out << str << wrapper << '\n'; + } + out << pluralise( tags.size(), "tag" ) << '\n' << std::endl; + } + + void defaultListTests(std::ostream& out, std::vector const& tests, bool isFiltered, Verbosity verbosity) { + // We special case this to provide the equivalent of old + // `--list-test-names-only`, which could then be used by the + // `--input-file` option. + if (verbosity == Verbosity::Quiet) { + listTestNamesOnly(out, tests); + return; + } + + if (isFiltered) { + out << "Matching test cases:\n"; + } else { + out << "All available test cases:\n"; + } + + for (auto const& test : tests) { + auto const& testCaseInfo = test.getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard(colour); + + out << TextFlow::Column(testCaseInfo.name).initialIndent(2).indent(4) << '\n'; + if (verbosity >= Verbosity::High) { + out << TextFlow::Column(Catch::Detail::stringify(testCaseInfo.lineInfo)).indent(4) << std::endl; + } + if (!testCaseInfo.tags.empty() && + verbosity > Verbosity::Quiet) { + out << TextFlow::Column(testCaseInfo.tagsAsString()).indent(6) << '\n'; + } + } + + if (isFiltered) { + out << pluralise(tests.size(), "matching test case") << '\n' << std::endl; + } else { + out << pluralise(tests.size(), "test case") << '\n' << std::endl; + } + } + } // namespace Catch diff --git a/src/catch2/reporters/catch_reporter_helpers.hpp b/src/catch2/reporters/catch_reporter_helpers.hpp index c86863baa1..d16d92f207 100644 --- a/src/catch2/reporters/catch_reporter_helpers.hpp +++ b/src/catch2/reporters/catch_reporter_helpers.hpp @@ -12,9 +12,13 @@ #include #include +#include +#include + namespace Catch { struct IConfig; + class TestCaseHandle; // Returns double formatted as %.3f (format expected on output) std::string getFormattedDuration( double duration ); @@ -31,6 +35,42 @@ namespace Catch { friend std::ostream& operator<<( std::ostream& out, lineOfChars value ); }; + /** + * Lists reporter descriptions to the provided stream in user-friendly + * format + * + * Used as the default listing implementation by the first party reporter + * bases. The output should be backwards compatible with the output of + * Catch2 v2 binaries. + */ + void + defaultListReporters( std::ostream& out, + std::vector const& descriptions, + Verbosity verbosity ); + + /** + * Lists tag information to the provided stream in user-friendly format + * + * Used as the default listing implementation by the first party reporter + * bases. The output should be backwards compatible with the output of + * Catch2 v2 binaries. + */ + void defaultListTags( std::ostream& out, std::vector const& tags, bool isFiltered ); + + /** + * Lists test case information to the provided stream in user-friendly + * format + * + * Used as the default listing implementation by the first party reporter + * bases. The output is backwards compatible with the output of Catch2 + * v2 binaries, and also supports the format specific to the old + * `--list-test-names-only` option, for people who used it in integrations. + */ + void defaultListTests( std::ostream& out, + std::vector const& tests, + bool isFiltered, + Verbosity verbosity ); + } // end namespace Catch #endif // CATCH_REPORTER_HELPERS_HPP_INCLUDED