1 /* 2 * Created by Phil on 5/11/2010. 3 * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. 4 * 5 * Distributed under the Boost Software License, Version 1.0. (See accompanying 6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 */ 8 9 #include "catch_list.h" 10 11 #include "catch_interfaces_registry_hub.h" 12 #include "catch_interfaces_reporter.h" 13 #include "catch_interfaces_testcase.h" 14 15 #include "catch_context.h" 16 #include "catch_stream.h" 17 #include "catch_text.h" 18 19 #include "catch_console_colour.h" 20 #include "catch_test_spec_parser.h" 21 #include "catch_tostring.h" 22 #include "catch_string_manip.h" 23 24 #include <limits> 25 #include <algorithm> 26 #include <iomanip> 27 28 namespace Catch { 29 listTests(Config const & config)30 std::size_t listTests( Config const& config ) { 31 TestSpec const& testSpec = config.testSpec(); 32 if( config.hasTestFilters() ) 33 Catch::cout() << "Matching test cases:\n"; 34 else { 35 Catch::cout() << "All available test cases:\n"; 36 } 37 38 auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); 39 for( auto const& testCaseInfo : matchedTestCases ) { 40 Colour::Code colour = testCaseInfo.isHidden() 41 ? Colour::SecondaryText 42 : Colour::None; 43 Colour colourGuard( colour ); 44 45 Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n"; 46 if( config.verbosity() >= Verbosity::High ) { 47 Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; 48 std::string description = testCaseInfo.description; 49 if( description.empty() ) 50 description = "(NO DESCRIPTION)"; 51 Catch::cout() << Column( description ).indent(4) << std::endl; 52 } 53 if( !testCaseInfo.tags.empty() ) 54 Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; 55 } 56 57 if( !config.hasTestFilters() ) 58 Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; 59 else 60 Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; 61 return matchedTestCases.size(); 62 } 63 listTestsNamesOnly(Config const & config)64 std::size_t listTestsNamesOnly( Config const& config ) { 65 TestSpec const& testSpec = config.testSpec(); 66 std::size_t matchedTests = 0; 67 std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); 68 for( auto const& testCaseInfo : matchedTestCases ) { 69 matchedTests++; 70 if( startsWith( testCaseInfo.name, '#' ) ) 71 Catch::cout() << '"' << testCaseInfo.name << '"'; 72 else 73 Catch::cout() << testCaseInfo.name; 74 if ( config.verbosity() >= Verbosity::High ) 75 Catch::cout() << "\t@" << testCaseInfo.lineInfo; 76 Catch::cout() << std::endl; 77 } 78 return matchedTests; 79 } 80 add(std::string const & spelling)81 void TagInfo::add( std::string const& spelling ) { 82 ++count; 83 spellings.insert( spelling ); 84 } 85 all() const86 std::string TagInfo::all() const { 87 size_t size = 0; 88 for (auto const& spelling : spellings) { 89 // Add 2 for the brackes 90 size += spelling.size() + 2; 91 } 92 93 std::string out; out.reserve(size); 94 for (auto const& spelling : spellings) { 95 out += '['; 96 out += spelling; 97 out += ']'; 98 } 99 return out; 100 } 101 listTags(Config const & config)102 std::size_t listTags( Config const& config ) { 103 TestSpec const& testSpec = config.testSpec(); 104 if( config.hasTestFilters() ) 105 Catch::cout() << "Tags for matching test cases:\n"; 106 else { 107 Catch::cout() << "All available tags:\n"; 108 } 109 110 std::map<std::string, TagInfo> tagCounts; 111 112 std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); 113 for( auto const& testCase : matchedTestCases ) { 114 for( auto const& tagName : testCase.getTestCaseInfo().tags ) { 115 std::string lcaseTagName = toLower( tagName ); 116 auto countIt = tagCounts.find( lcaseTagName ); 117 if( countIt == tagCounts.end() ) 118 countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; 119 countIt->second.add( tagName ); 120 } 121 } 122 123 for( auto const& tagCount : tagCounts ) { 124 ReusableStringStream rss; 125 rss << " " << std::setw(2) << tagCount.second.count << " "; 126 auto str = rss.str(); 127 auto wrapper = Column( tagCount.second.all() ) 128 .initialIndent( 0 ) 129 .indent( str.size() ) 130 .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); 131 Catch::cout() << str << wrapper << '\n'; 132 } 133 Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; 134 return tagCounts.size(); 135 } 136 listReporters()137 std::size_t listReporters() { 138 Catch::cout() << "Available reporters:\n"; 139 IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); 140 std::size_t maxNameLen = 0; 141 for( auto const& factoryKvp : factories ) 142 maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); 143 144 for( auto const& factoryKvp : factories ) { 145 Catch::cout() 146 << Column( factoryKvp.first + ":" ) 147 .indent(2) 148 .width( 5+maxNameLen ) 149 + Column( factoryKvp.second->getDescription() ) 150 .initialIndent(0) 151 .indent(2) 152 .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) 153 << "\n"; 154 } 155 Catch::cout() << std::endl; 156 return factories.size(); 157 } 158 list(std::shared_ptr<Config> const & config)159 Option<std::size_t> list( std::shared_ptr<Config> const& config ) { 160 Option<std::size_t> listedCount; 161 getCurrentMutableContext().setConfig( config ); 162 if( config->listTests() ) 163 listedCount = listedCount.valueOr(0) + listTests( *config ); 164 if( config->listTestNamesOnly() ) 165 listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config ); 166 if( config->listTags() ) 167 listedCount = listedCount.valueOr(0) + listTags( *config ); 168 if( config->listReporters() ) 169 listedCount = listedCount.valueOr(0) + listReporters(); 170 return listedCount; 171 } 172 173 } // end namespace Catch 174