Skip to content

Commit

Permalink
Make --list-* exit code be 0
Browse files Browse the repository at this point in the history
Previously it returned the sum of listed things because ???. This
was completely useless and in many ways actively counterproductive
because of the success/failure conventions around exit codes.

Closes #1410
  • Loading branch information
horenmar committed Jun 16, 2019
1 parent 807f1d3 commit fcc4db1
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 129 deletions.
231 changes: 124 additions & 107 deletions include/internal/catch_list.cpp
Expand Up @@ -24,59 +24,125 @@
#include <limits>
#include <algorithm>
#include <iomanip>
#include <set>

namespace Catch {
namespace {

std::size_t listTests( Config const& config ) {
TestSpec testSpec = config.testSpec();
if( config.hasTestFilters() )
Catch::cout() << "Matching test cases:\n";
else {
Catch::cout() << "All available test cases:\n";
struct TagInfo {
void add(std::string const& spelling);
std::string all() const;

std::set<std::string> spellings;
std::size_t count = 0;
};


void listTests(Config const& config) {
TestSpec testSpec = config.testSpec();
if (config.hasTestFilters())
Catch::cout() << "Matching test cases:\n";
else {
Catch::cout() << "All available test cases:\n";
}

auto matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
for (auto const& testCaseInfo : matchedTestCases) {
Colour::Code colour = testCaseInfo.isHidden()
? Colour::SecondaryText
: Colour::None;
Colour colourGuard(colour);

Catch::cout() << Column(testCaseInfo.name).initialIndent(2).indent(4) << "\n";
if (config.verbosity() >= Verbosity::High) {
Catch::cout() << Column(Catch::Detail::stringify(testCaseInfo.lineInfo)).indent(4) << std::endl;
std::string description = testCaseInfo.description;
if (description.empty())
description = "(NO DESCRIPTION)";
Catch::cout() << Column(description).indent(4) << std::endl;
}
if (!testCaseInfo.tags.empty())
Catch::cout() << Column(testCaseInfo.tagsAsString()).indent(6) << "\n";
}

if (!config.hasTestFilters())
Catch::cout() << pluralise(matchedTestCases.size(), "test case") << '\n' << std::endl;
else
Catch::cout() << pluralise(matchedTestCases.size(), "matching test case") << '\n' << std::endl;
}

auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( auto const& testCaseInfo : matchedTestCases ) {
Colour::Code colour = testCaseInfo.isHidden()
? Colour::SecondaryText
: Colour::None;
Colour colourGuard( colour );

Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n";
if( config.verbosity() >= Verbosity::High ) {
Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl;
std::string description = testCaseInfo.description;
if( description.empty() )
description = "(NO DESCRIPTION)";
Catch::cout() << Column( description ).indent(4) << std::endl;
void listTestsNamesOnly(Config const& config) {
TestSpec testSpec = config.testSpec();
std::size_t matchedTests = 0;
std::vector<TestCase> matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
for (auto const& testCaseInfo : matchedTestCases) {
matchedTests++;
if (startsWith(testCaseInfo.name, '#'))
Catch::cout() << '"' << testCaseInfo.name << '"';
else
Catch::cout() << testCaseInfo.name;
if (config.verbosity() >= Verbosity::High)
Catch::cout() << "\t@" << testCaseInfo.lineInfo;
Catch::cout() << std::endl;
}
if( !testCaseInfo.tags.empty() )
Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n";
}

if( !config.hasTestFilters() )
Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl;
else
Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl;
return matchedTestCases.size();
}
void listTags(Config const& config) {
TestSpec testSpec = config.testSpec();
if (config.hasTestFilters())
Catch::cout() << "Tags for matching test cases:\n";
else {
Catch::cout() << "All available tags:\n";
}

std::size_t listTestsNamesOnly( Config const& config ) {
TestSpec testSpec = config.testSpec();
std::size_t matchedTests = 0;
std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( auto const& testCaseInfo : matchedTestCases ) {
matchedTests++;
if( startsWith( testCaseInfo.name, '#' ) )
Catch::cout() << '"' << testCaseInfo.name << '"';
else
Catch::cout() << testCaseInfo.name;
if ( config.verbosity() >= Verbosity::High )
Catch::cout() << "\t@" << testCaseInfo.lineInfo;
std::map<std::string, TagInfo> tagCounts;

std::vector<TestCase> matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
for (auto const& testCase : matchedTestCases) {
for (auto const& tagName : testCase.getTestCaseInfo().tags) {
std::string lcaseTagName = toLower(tagName);
auto countIt = tagCounts.find(lcaseTagName);
if (countIt == tagCounts.end())
countIt = tagCounts.insert(std::make_pair(lcaseTagName, TagInfo())).first;
countIt->second.add(tagName);
}
}

for (auto const& tagCount : tagCounts) {
ReusableStringStream rss;
rss << " " << std::setw(2) << tagCount.second.count << " ";
auto str = rss.str();
auto wrapper = Column(tagCount.second.all())
.initialIndent(0)
.indent(str.size())
.width(CATCH_CONFIG_CONSOLE_WIDTH - 10);
Catch::cout() << str << wrapper << '\n';
}
Catch::cout() << pluralise(tagCounts.size(), "tag") << '\n' << std::endl;
}

void listReporters() {
Catch::cout() << "Available reporters:\n";
IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
std::size_t maxNameLen = 0;
for (auto const& factoryKvp : factories)
maxNameLen = (std::max)(maxNameLen, factoryKvp.first.size());

for (auto const& factoryKvp : factories) {
Catch::cout()
<< Column(factoryKvp.first + ":")
.indent(2)
.width(5 + maxNameLen)
+ Column(factoryKvp.second->getDescription())
.initialIndent(0)
.indent(2)
.width(CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8)
<< "\n";
}
Catch::cout() << std::endl;
}
return matchedTests;
}

} // end anonymous namespace

void TagInfo::add( std::string const& spelling ) {
++count;
Expand All @@ -90,75 +156,26 @@ namespace Catch {
return out;
}

std::size_t listTags( Config const& config ) {
TestSpec testSpec = config.testSpec();
if( config.hasTestFilters() )
Catch::cout() << "Tags for matching test cases:\n";
else {
Catch::cout() << "All available tags:\n";
bool list( std::shared_ptr<Config> const& config ) {
bool listed = false;
getCurrentMutableContext().setConfig( config );
if (config->listTests()) {
listed = true;
listTests(*config);
}

std::map<std::string, TagInfo> tagCounts;

std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
for( auto const& testCase : matchedTestCases ) {
for( auto const& tagName : testCase.getTestCaseInfo().tags ) {
std::string lcaseTagName = toLower( tagName );
auto countIt = tagCounts.find( lcaseTagName );
if( countIt == tagCounts.end() )
countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
countIt->second.add( tagName );
}
if (config->listTestNamesOnly()) {
listed = true;
listTestsNamesOnly(*config);
}

for( auto const& tagCount : tagCounts ) {
ReusableStringStream rss;
rss << " " << std::setw(2) << tagCount.second.count << " ";
auto str = rss.str();
auto wrapper = Column( tagCount.second.all() )
.initialIndent( 0 )
.indent( str.size() )
.width( CATCH_CONFIG_CONSOLE_WIDTH-10 );
Catch::cout() << str << wrapper << '\n';
if (config->listTags()) {
listed = true;
listTags(*config);
}
Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
return tagCounts.size();
}

std::size_t listReporters() {
Catch::cout() << "Available reporters:\n";
IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
std::size_t maxNameLen = 0;
for( auto const& factoryKvp : factories )
maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() );

for( auto const& factoryKvp : factories ) {
Catch::cout()
<< Column( factoryKvp.first + ":" )
.indent(2)
.width( 5+maxNameLen )
+ Column( factoryKvp.second->getDescription() )
.initialIndent(0)
.indent(2)
.width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 )
<< "\n";
if (config->listReporters()) {
listed = true;
listReporters();
}
Catch::cout() << std::endl;
return factories.size();
}

Option<std::size_t> list( std::shared_ptr<Config> const& config ) {
Option<std::size_t> listedCount;
getCurrentMutableContext().setConfig( config );
if( config->listTests() )
listedCount = listedCount.valueOr(0) + listTests( *config );
if( config->listTestNamesOnly() )
listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config );
if( config->listTags() )
listedCount = listedCount.valueOr(0) + listTags( *config );
if( config->listReporters() )
listedCount = listedCount.valueOr(0) + listReporters();
return listedCount;
return listed;
}

} // end namespace Catch
21 changes: 1 addition & 20 deletions include/internal/catch_list.h
Expand Up @@ -8,30 +8,11 @@
#ifndef TWOBLUECUBES_CATCH_LIST_H_INCLUDED
#define TWOBLUECUBES_CATCH_LIST_H_INCLUDED

#include "catch_option.hpp"
#include "catch_config.hpp"

#include <set>

namespace Catch {

std::size_t listTests( Config const& config );

std::size_t listTestsNamesOnly( Config const& config );

struct TagInfo {
void add( std::string const& spelling );
std::string all() const;

std::set<std::string> spellings;
std::size_t count = 0;
};

std::size_t listTags( Config const& config );

std::size_t listReporters();

Option<std::size_t> list( std::shared_ptr<Config> const& config );
bool list( std::shared_ptr<Config> const& config );

} // end namespace Catch

Expand Down
5 changes: 3 additions & 2 deletions include/internal/catch_session.cpp
Expand Up @@ -271,8 +271,9 @@ namespace Catch {
applyFilenamesAsTags( *m_config );

// Handle list request
if( Option<std::size_t> listed = list( m_config ) )
return static_cast<int>( *listed );
if (list(m_config)) {
return 0;
}

auto totals = runTests( m_config );
// Note that on unices only the lower 8 bits are usually used, clamping
Expand Down

0 comments on commit fcc4db1

Please sign in to comment.