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 #ifndef TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
9 #define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
10 
11 #include "catch_commandline.hpp"
12 #include "catch_text.h"
13 #include "catch_console_colour.hpp"
14 #include "catch_interfaces_reporter.h"
15 #include "catch_test_spec_parser.hpp"
16 
17 #include <limits>
18 #include <algorithm>
19 
20 namespace Catch {
21 
listTests(Config const & config)22     inline std::size_t listTests( Config const& config ) {
23 
24         TestSpec testSpec = config.testSpec();
25         if( config.testSpec().hasFilters() )
26             Catch::cout() << "Matching test cases:\n";
27         else {
28             Catch::cout() << "All available test cases:\n";
29             testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
30         }
31 
32         std::size_t matchedTests = 0;
33         TextAttributes nameAttr, descAttr, tagsAttr;
34         nameAttr.setInitialIndent( 2 ).setIndent( 4 );
35         descAttr.setIndent( 4 );
36         tagsAttr.setIndent( 6 );
37 
38         std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
39         for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
40                 it != itEnd;
41                 ++it ) {
42             matchedTests++;
43             TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
44             Colour::Code colour = testCaseInfo.isHidden()
45                 ? Colour::SecondaryText
46                 : Colour::None;
47             Colour colourGuard( colour );
48 
49             Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl;
50             if( config.listExtraInfo() ) {
51                 Catch::cout() << "    " << testCaseInfo.lineInfo << std::endl;
52                 std::string description = testCaseInfo.description;
53                 if( description.empty() )
54                     description = "(NO DESCRIPTION)";
55                 Catch::cout() << Text( description, descAttr ) << std::endl;
56             }
57             if( !testCaseInfo.tags.empty() )
58                 Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
59         }
60 
61         if( !config.testSpec().hasFilters() )
62             Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl;
63         else
64             Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl;
65         return matchedTests;
66     }
67 
listTestsNamesOnly(Config const & config)68     inline std::size_t listTestsNamesOnly( Config const& config ) {
69         TestSpec testSpec = config.testSpec();
70         if( !config.testSpec().hasFilters() )
71             testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
72         std::size_t matchedTests = 0;
73         std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
74         for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
75                 it != itEnd;
76                 ++it ) {
77             matchedTests++;
78             TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
79             if( startsWith( testCaseInfo.name, '#' ) )
80                Catch::cout() << '"' << testCaseInfo.name << '"';
81             else
82                Catch::cout() << testCaseInfo.name;
83             if ( config.listExtraInfo() )
84                 Catch::cout() << "\t@" << testCaseInfo.lineInfo;
85             Catch::cout() << std::endl;
86         }
87         return matchedTests;
88     }
89 
90     struct TagInfo {
TagInfoCatch::TagInfo91         TagInfo() : count ( 0 ) {}
addCatch::TagInfo92         void add( std::string const& spelling ) {
93             ++count;
94             spellings.insert( spelling );
95         }
allCatch::TagInfo96         std::string all() const {
97             std::string out;
98             for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end();
99                         it != itEnd;
100                         ++it )
101                 out += "[" + *it + "]";
102             return out;
103         }
104         std::set<std::string> spellings;
105         std::size_t count;
106     };
107 
listTags(Config const & config)108     inline std::size_t listTags( Config const& config ) {
109         TestSpec testSpec = config.testSpec();
110         if( config.testSpec().hasFilters() )
111             Catch::cout() << "Tags for matching test cases:\n";
112         else {
113             Catch::cout() << "All available tags:\n";
114             testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
115         }
116 
117         std::map<std::string, TagInfo> tagCounts;
118 
119         std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
120         for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
121                 it != itEnd;
122                 ++it ) {
123             for( std::set<std::string>::const_iterator  tagIt = it->getTestCaseInfo().tags.begin(),
124                                                         tagItEnd = it->getTestCaseInfo().tags.end();
125                     tagIt != tagItEnd;
126                     ++tagIt ) {
127                 std::string tagName = *tagIt;
128                 std::string lcaseTagName = toLower( tagName );
129                 std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName );
130                 if( countIt == tagCounts.end() )
131                     countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
132                 countIt->second.add( tagName );
133             }
134         }
135 
136         for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(),
137                                                             countItEnd = tagCounts.end();
138                 countIt != countItEnd;
139                 ++countIt ) {
140             std::ostringstream oss;
141             oss << "  " << std::setw(2) << countIt->second.count << "  ";
142             Text wrapper( countIt->second.all(), TextAttributes()
143                                                     .setInitialIndent( 0 )
144                                                     .setIndent( oss.str().size() )
145                                                     .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
146             Catch::cout() << oss.str() << wrapper << '\n';
147         }
148         Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
149         return tagCounts.size();
150     }
151 
listReporters(Config const &)152     inline std::size_t listReporters( Config const& /*config*/ ) {
153         Catch::cout() << "Available reporters:\n";
154         IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
155         IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
156         std::size_t maxNameLen = 0;
157         for(it = itBegin; it != itEnd; ++it )
158             maxNameLen = (std::max)( maxNameLen, it->first.size() );
159 
160         for(it = itBegin; it != itEnd; ++it ) {
161             Text wrapper( it->second->getDescription(), TextAttributes()
162                                                         .setInitialIndent( 0 )
163                                                         .setIndent( 7+maxNameLen )
164                                                         .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
165             Catch::cout() << "  "
166                     << it->first
167                     << ':'
168                     << std::string( maxNameLen - it->first.size() + 2, ' ' )
169                     << wrapper << '\n';
170         }
171         Catch::cout() << std::endl;
172         return factories.size();
173     }
174 
list(Config const & config)175     inline Option<std::size_t> list( Config const& config ) {
176         Option<std::size_t> listedCount;
177         if( config.listTests() || ( config.listExtraInfo() && !config.listTestNamesOnly() ) )
178             listedCount = listedCount.valueOr(0) + listTests( config );
179         if( config.listTestNamesOnly() )
180             listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
181         if( config.listTags() )
182             listedCount = listedCount.valueOr(0) + listTags( config );
183         if( config.listReporters() )
184             listedCount = listedCount.valueOr(0) + listReporters( config );
185         return listedCount;
186     }
187 
188 } // end namespace Catch
189 
190 #endif // TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
191