Skip to content

Commit

Permalink
Extract the default listing implementation out of reporter interface
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
horenmar committed Jan 26, 2021
1 parent 7111b2a commit 6798c13
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 98 deletions.
105 changes: 8 additions & 97 deletions src/catch2/interfaces/catch_interfaces_reporter.cpp
Expand Up @@ -11,34 +11,15 @@
#include <catch2/internal/catch_console_width.hpp>
#include <catch2/catch_message.hpp>
#include <catch2/internal/catch_list.hpp>
#include <catch2/internal/catch_textflow.hpp>
#include <catch2/internal/catch_string_manip.hpp>
#include <catch2/catch_test_case_info.hpp>
#include <catch2/internal/catch_textflow.hpp>
#include <catch2/reporters/catch_reporter_helpers.hpp>

#include <algorithm>
#include <iomanip>

namespace Catch {

namespace {
void listTestNamesOnly( std::vector<TestCaseHandle> 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 ) {}

Expand Down Expand Up @@ -128,89 +109,19 @@ namespace Catch {
void IStreamingReporter::fatalErrorEncountered( StringRef ) {}

void IStreamingReporter::listReporters(std::vector<ReporterDescription> 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<TestCaseHandle> 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<TagInfo> 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
124 changes: 123 additions & 1 deletion src/catch2/reporters/catch_reporter_combined_tu.cpp
Expand Up @@ -21,13 +21,40 @@
#include <catch2/interfaces/catch_interfaces_config.hpp>
#include <catch2/internal/catch_console_width.hpp>
#include <catch2/internal/catch_errno_guard.hpp>

#include <catch2/internal/catch_textflow.hpp>
#include <catch2/internal/catch_stream.hpp>
#include <catch2/internal/catch_string_manip.hpp>
#include <catch2/internal/catch_console_colour.hpp>
#include <catch2/catch_tostring.hpp>
#include <catch2/catch_test_case_info.hpp>

#include <algorithm>
#include <cfloat>
#include <cstdio>
#include <ostream>
#include <iomanip>

namespace Catch {

namespace {
void listTestNamesOnly(std::ostream& out,
std::vector<TestCaseHandle> 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.
Expand Down Expand Up @@ -89,6 +116,101 @@ namespace Catch {
return out;
}

void
defaultListReporters( std::ostream& out,
std::vector<ReporterDescription> 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<TagInfo> 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<TestCaseHandle> 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


Expand Down
40 changes: 40 additions & 0 deletions src/catch2/reporters/catch_reporter_helpers.hpp
Expand Up @@ -12,9 +12,13 @@
#include <string>
#include <vector>

#include <catch2/internal/catch_list.hpp>
#include <catch2/interfaces/catch_interfaces_config.hpp>

namespace Catch {

struct IConfig;
class TestCaseHandle;

// Returns double formatted as %.3f (format expected on output)
std::string getFormattedDuration( double duration );
Expand All @@ -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<ReporterDescription> 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<TagInfo> 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<TestCaseHandle> const& tests,
bool isFiltered,
Verbosity verbosity );

} // end namespace Catch

#endif // CATCH_REPORTER_HELPERS_HPP_INCLUDED

0 comments on commit 6798c13

Please sign in to comment.