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 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 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 std::string out; 88 for( auto const& spelling : spellings ) 89 out += "[" + spelling + "]"; 90 return out; 91 } 92 listTags(Config const & config)93 std::size_t listTags( Config const& config ) { 94 TestSpec testSpec = config.testSpec(); 95 if( config.hasTestFilters() ) 96 Catch::cout() << "Tags for matching test cases:\n"; 97 else { 98 Catch::cout() << "All available tags:\n"; 99 } 100 101 std::map<std::string, TagInfo> tagCounts; 102 103 std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); 104 for( auto const& testCase : matchedTestCases ) { 105 for( auto const& tagName : testCase.getTestCaseInfo().tags ) { 106 std::string lcaseTagName = toLower( tagName ); 107 auto countIt = tagCounts.find( lcaseTagName ); 108 if( countIt == tagCounts.end() ) 109 countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; 110 countIt->second.add( tagName ); 111 } 112 } 113 114 for( auto const& tagCount : tagCounts ) { 115 ReusableStringStream rss; 116 rss << " " << std::setw(2) << tagCount.second.count << " "; 117 auto str = rss.str(); 118 auto wrapper = Column( tagCount.second.all() ) 119 .initialIndent( 0 ) 120 .indent( str.size() ) 121 .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); 122 Catch::cout() << str << wrapper << '\n'; 123 } 124 Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; 125 return tagCounts.size(); 126 } 127 listReporters()128 std::size_t listReporters() { 129 Catch::cout() << "Available reporters:\n"; 130 IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); 131 std::size_t maxNameLen = 0; 132 for( auto const& factoryKvp : factories ) 133 maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); 134 135 for( auto const& factoryKvp : factories ) { 136 Catch::cout() 137 << Column( factoryKvp.first + ":" ) 138 .indent(2) 139 .width( 5+maxNameLen ) 140 + Column( factoryKvp.second->getDescription() ) 141 .initialIndent(0) 142 .indent(2) 143 .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) 144 << "\n"; 145 } 146 Catch::cout() << std::endl; 147 return factories.size(); 148 } 149 list(std::shared_ptr<Config> const & config)150 Option<std::size_t> list( std::shared_ptr<Config> const& config ) { 151 Option<std::size_t> listedCount; 152 getCurrentMutableContext().setConfig( config ); 153 if( config->listTests() ) 154 listedCount = listedCount.valueOr(0) + listTests( *config ); 155 if( config->listTestNamesOnly() ) 156 listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config ); 157 if( config->listTags() ) 158 listedCount = listedCount.valueOr(0) + listTags( *config ); 159 if( config->listReporters() ) 160 listedCount = listedCount.valueOr(0) + listReporters(); 161 return listedCount; 162 } 163 164 } // end namespace Catch 165