• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Created by Phil on 27/11/2013.
3  *  Copyright 2013 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_REPORTER_BASES_HPP_INCLUDED
9 #define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
10 
11 #include "../internal/catch_enforce.h"
12 #include "../internal/catch_interfaces_reporter.h"
13 
14 #include <algorithm>
15 #include <cstring>
16 #include <cfloat>
17 #include <cstdio>
18 #include <cassert>
19 #include <memory>
20 #include <ostream>
21 
22 namespace Catch {
23     void prepareExpandedExpression(AssertionResult& result);
24 
25     // Returns double formatted as %.3f (format expected on output)
26     std::string getFormattedDuration( double duration );
27 
28     std::string serializeFilters( std::vector<std::string> const& container );
29 
30     template<typename DerivedT>
31     struct StreamingReporterBase : IStreamingReporter {
32 
StreamingReporterBaseCatch::StreamingReporterBase33         StreamingReporterBase( ReporterConfig const& _config )
34         :   m_config( _config.fullConfig() ),
35             stream( _config.stream() )
36         {
37             m_reporterPrefs.shouldRedirectStdOut = false;
38             if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
39                 CATCH_ERROR( "Verbosity level not supported by this reporter" );
40         }
41 
getPreferencesCatch::StreamingReporterBase42         ReporterPreferences getPreferences() const override {
43             return m_reporterPrefs;
44         }
45 
getSupportedVerbositiesCatch::StreamingReporterBase46         static std::set<Verbosity> getSupportedVerbosities() {
47             return { Verbosity::Normal };
48         }
49 
50         ~StreamingReporterBase() override = default;
51 
noMatchingTestCasesCatch::StreamingReporterBase52         void noMatchingTestCases(std::string const&) override {}
53 
testRunStartingCatch::StreamingReporterBase54         void testRunStarting(TestRunInfo const& _testRunInfo) override {
55             currentTestRunInfo = _testRunInfo;
56         }
57 
testGroupStartingCatch::StreamingReporterBase58         void testGroupStarting(GroupInfo const& _groupInfo) override {
59             currentGroupInfo = _groupInfo;
60         }
61 
testCaseStartingCatch::StreamingReporterBase62         void testCaseStarting(TestCaseInfo const& _testInfo) override  {
63             currentTestCaseInfo = _testInfo;
64         }
sectionStartingCatch::StreamingReporterBase65         void sectionStarting(SectionInfo const& _sectionInfo) override {
66             m_sectionStack.push_back(_sectionInfo);
67         }
68 
sectionEndedCatch::StreamingReporterBase69         void sectionEnded(SectionStats const& /* _sectionStats */) override {
70             m_sectionStack.pop_back();
71         }
testCaseEndedCatch::StreamingReporterBase72         void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override {
73             currentTestCaseInfo.reset();
74         }
testGroupEndedCatch::StreamingReporterBase75         void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override {
76             currentGroupInfo.reset();
77         }
testRunEndedCatch::StreamingReporterBase78         void testRunEnded(TestRunStats const& /* _testRunStats */) override {
79             currentTestCaseInfo.reset();
80             currentGroupInfo.reset();
81             currentTestRunInfo.reset();
82         }
83 
skipTestCatch::StreamingReporterBase84         void skipTest(TestCaseInfo const&) override {
85             // Don't do anything with this by default.
86             // It can optionally be overridden in the derived class.
87         }
88 
89         IConfigPtr m_config;
90         std::ostream& stream;
91 
92         LazyStat<TestRunInfo> currentTestRunInfo;
93         LazyStat<GroupInfo> currentGroupInfo;
94         LazyStat<TestCaseInfo> currentTestCaseInfo;
95 
96         std::vector<SectionInfo> m_sectionStack;
97         ReporterPreferences m_reporterPrefs;
98     };
99 
100     template<typename DerivedT>
101     struct CumulativeReporterBase : IStreamingReporter {
102         template<typename T, typename ChildNodeT>
103         struct Node {
NodeCatch::CumulativeReporterBase::Node104             explicit Node( T const& _value ) : value( _value ) {}
~NodeCatch::CumulativeReporterBase::Node105             virtual ~Node() {}
106 
107             using ChildNodes = std::vector<std::shared_ptr<ChildNodeT>>;
108             T value;
109             ChildNodes children;
110         };
111         struct SectionNode {
SectionNodeCatch::CumulativeReporterBase::SectionNode112             explicit SectionNode(SectionStats const& _stats) : stats(_stats) {}
113             virtual ~SectionNode() = default;
114 
operator ==Catch::CumulativeReporterBase::SectionNode115             bool operator == (SectionNode const& other) const {
116                 return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
117             }
operator ==Catch::CumulativeReporterBase::SectionNode118             bool operator == (std::shared_ptr<SectionNode> const& other) const {
119                 return operator==(*other);
120             }
121 
122             SectionStats stats;
123             using ChildSections = std::vector<std::shared_ptr<SectionNode>>;
124             using Assertions = std::vector<AssertionStats>;
125             ChildSections childSections;
126             Assertions assertions;
127             std::string stdOut;
128             std::string stdErr;
129         };
130 
131         struct BySectionInfo {
BySectionInfoCatch::CumulativeReporterBase::BySectionInfo132             BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
BySectionInfoCatch::CumulativeReporterBase::BySectionInfo133             BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
operator ()Catch::CumulativeReporterBase::BySectionInfo134             bool operator() (std::shared_ptr<SectionNode> const& node) const {
135                 return ((node->stats.sectionInfo.name == m_other.name) &&
136                         (node->stats.sectionInfo.lineInfo == m_other.lineInfo));
137             }
138             void operator=(BySectionInfo const&) = delete;
139 
140         private:
141             SectionInfo const& m_other;
142         };
143 
144 
145         using TestCaseNode = Node<TestCaseStats, SectionNode>;
146         using TestGroupNode = Node<TestGroupStats, TestCaseNode>;
147         using TestRunNode = Node<TestRunStats, TestGroupNode>;
148 
CumulativeReporterBaseCatch::CumulativeReporterBase149         CumulativeReporterBase( ReporterConfig const& _config )
150         :   m_config( _config.fullConfig() ),
151             stream( _config.stream() )
152         {
153             m_reporterPrefs.shouldRedirectStdOut = false;
154             if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
155                 CATCH_ERROR( "Verbosity level not supported by this reporter" );
156         }
157         ~CumulativeReporterBase() override = default;
158 
getPreferencesCatch::CumulativeReporterBase159         ReporterPreferences getPreferences() const override {
160             return m_reporterPrefs;
161         }
162 
getSupportedVerbositiesCatch::CumulativeReporterBase163         static std::set<Verbosity> getSupportedVerbosities() {
164             return { Verbosity::Normal };
165         }
166 
testRunStartingCatch::CumulativeReporterBase167         void testRunStarting( TestRunInfo const& ) override {}
testGroupStartingCatch::CumulativeReporterBase168         void testGroupStarting( GroupInfo const& ) override {}
169 
testCaseStartingCatch::CumulativeReporterBase170         void testCaseStarting( TestCaseInfo const& ) override {}
171 
sectionStartingCatch::CumulativeReporterBase172         void sectionStarting( SectionInfo const& sectionInfo ) override {
173             SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
174             std::shared_ptr<SectionNode> node;
175             if( m_sectionStack.empty() ) {
176                 if( !m_rootSection )
177                     m_rootSection = std::make_shared<SectionNode>( incompleteStats );
178                 node = m_rootSection;
179             }
180             else {
181                 SectionNode& parentNode = *m_sectionStack.back();
182                 auto it =
183                     std::find_if(   parentNode.childSections.begin(),
184                                     parentNode.childSections.end(),
185                                     BySectionInfo( sectionInfo ) );
186                 if( it == parentNode.childSections.end() ) {
187                     node = std::make_shared<SectionNode>( incompleteStats );
188                     parentNode.childSections.push_back( node );
189                 }
190                 else
191                     node = *it;
192             }
193             m_sectionStack.push_back( node );
194             m_deepestSection = std::move(node);
195         }
196 
assertionStartingCatch::CumulativeReporterBase197         void assertionStarting(AssertionInfo const&) override {}
198 
assertionEndedCatch::CumulativeReporterBase199         bool assertionEnded(AssertionStats const& assertionStats) override {
200             assert(!m_sectionStack.empty());
201             // AssertionResult holds a pointer to a temporary DecomposedExpression,
202             // which getExpandedExpression() calls to build the expression string.
203             // Our section stack copy of the assertionResult will likely outlive the
204             // temporary, so it must be expanded or discarded now to avoid calling
205             // a destroyed object later.
206             prepareExpandedExpression(const_cast<AssertionResult&>( assertionStats.assertionResult ) );
207             SectionNode& sectionNode = *m_sectionStack.back();
208             sectionNode.assertions.push_back(assertionStats);
209             return true;
210         }
sectionEndedCatch::CumulativeReporterBase211         void sectionEnded(SectionStats const& sectionStats) override {
212             assert(!m_sectionStack.empty());
213             SectionNode& node = *m_sectionStack.back();
214             node.stats = sectionStats;
215             m_sectionStack.pop_back();
216         }
testCaseEndedCatch::CumulativeReporterBase217         void testCaseEnded(TestCaseStats const& testCaseStats) override {
218             auto node = std::make_shared<TestCaseNode>(testCaseStats);
219             assert(m_sectionStack.size() == 0);
220             node->children.push_back(m_rootSection);
221             m_testCases.push_back(node);
222             m_rootSection.reset();
223 
224             assert(m_deepestSection);
225             m_deepestSection->stdOut = testCaseStats.stdOut;
226             m_deepestSection->stdErr = testCaseStats.stdErr;
227         }
testGroupEndedCatch::CumulativeReporterBase228         void testGroupEnded(TestGroupStats const& testGroupStats) override {
229             auto node = std::make_shared<TestGroupNode>(testGroupStats);
230             node->children.swap(m_testCases);
231             m_testGroups.push_back(node);
232         }
testRunEndedCatch::CumulativeReporterBase233         void testRunEnded(TestRunStats const& testRunStats) override {
234             auto node = std::make_shared<TestRunNode>(testRunStats);
235             node->children.swap(m_testGroups);
236             m_testRuns.push_back(node);
237             testRunEndedCumulative();
238         }
239         virtual void testRunEndedCumulative() = 0;
240 
skipTestCatch::CumulativeReporterBase241         void skipTest(TestCaseInfo const&) override {}
242 
243         IConfigPtr m_config;
244         std::ostream& stream;
245         std::vector<AssertionStats> m_assertions;
246         std::vector<std::vector<std::shared_ptr<SectionNode>>> m_sections;
247         std::vector<std::shared_ptr<TestCaseNode>> m_testCases;
248         std::vector<std::shared_ptr<TestGroupNode>> m_testGroups;
249 
250         std::vector<std::shared_ptr<TestRunNode>> m_testRuns;
251 
252         std::shared_ptr<SectionNode> m_rootSection;
253         std::shared_ptr<SectionNode> m_deepestSection;
254         std::vector<std::shared_ptr<SectionNode>> m_sectionStack;
255         ReporterPreferences m_reporterPrefs;
256     };
257 
258     template<char C>
getLineOfChars()259     char const* getLineOfChars() {
260         static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
261         if( !*line ) {
262             std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
263             line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
264         }
265         return line;
266     }
267 
268 
269     struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> {
270         TestEventListenerBase( ReporterConfig const& _config );
271 
272         static std::set<Verbosity> getSupportedVerbosities();
273 
274         void assertionStarting(AssertionInfo const&) override;
275         bool assertionEnded(AssertionStats const&) override;
276     };
277 
278 } // end namespace Catch
279 
280 #endif // TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
281