catch_reporter_bases.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  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. #include "../internal/catch_enforce.h"
  11. #include "../internal/catch_interfaces_reporter.h"
  12. #include <algorithm>
  13. #include <cstring>
  14. #include <cfloat>
  15. #include <cstdio>
  16. #include <cassert>
  17. #include <memory>
  18. #include <ostream>
  19. namespace Catch {
  20. void prepareExpandedExpression(AssertionResult& result);
  21. // Returns double formatted as %.3f (format expected on output)
  22. std::string getFormattedDuration( double duration );
  23. //! Should the reporter show
  24. bool shouldShowDuration( IConfig const& config, double duration );
  25. std::string serializeFilters( std::vector<std::string> const& container );
  26. template<typename DerivedT>
  27. struct StreamingReporterBase : IStreamingReporter {
  28. StreamingReporterBase( ReporterConfig const& _config )
  29. : m_config( _config.fullConfig() ),
  30. stream( _config.stream() )
  31. {
  32. m_reporterPrefs.shouldRedirectStdOut = false;
  33. if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
  34. CATCH_ERROR( "Verbosity level not supported by this reporter" );
  35. }
  36. ReporterPreferences getPreferences() const override {
  37. return m_reporterPrefs;
  38. }
  39. static std::set<Verbosity> getSupportedVerbosities() {
  40. return { Verbosity::Normal };
  41. }
  42. ~StreamingReporterBase() override = default;
  43. void noMatchingTestCases(std::string const&) override {}
  44. void reportInvalidArguments(std::string const&) override {}
  45. void testRunStarting(TestRunInfo const& _testRunInfo) override {
  46. currentTestRunInfo = _testRunInfo;
  47. }
  48. void testGroupStarting(GroupInfo const& _groupInfo) override {
  49. currentGroupInfo = _groupInfo;
  50. }
  51. void testCaseStarting(TestCaseInfo const& _testInfo) override {
  52. currentTestCaseInfo = _testInfo;
  53. }
  54. void sectionStarting(SectionInfo const& _sectionInfo) override {
  55. m_sectionStack.push_back(_sectionInfo);
  56. }
  57. void sectionEnded(SectionStats const& /* _sectionStats */) override {
  58. m_sectionStack.pop_back();
  59. }
  60. void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override {
  61. currentTestCaseInfo.reset();
  62. }
  63. void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override {
  64. currentGroupInfo.reset();
  65. }
  66. void testRunEnded(TestRunStats const& /* _testRunStats */) override {
  67. currentTestCaseInfo.reset();
  68. currentGroupInfo.reset();
  69. currentTestRunInfo.reset();
  70. }
  71. void skipTest(TestCaseInfo const&) override {
  72. // Don't do anything with this by default.
  73. // It can optionally be overridden in the derived class.
  74. }
  75. IConfigPtr m_config;
  76. std::ostream& stream;
  77. LazyStat<TestRunInfo> currentTestRunInfo;
  78. LazyStat<GroupInfo> currentGroupInfo;
  79. LazyStat<TestCaseInfo> currentTestCaseInfo;
  80. std::vector<SectionInfo> m_sectionStack;
  81. ReporterPreferences m_reporterPrefs;
  82. };
  83. template<typename DerivedT>
  84. struct CumulativeReporterBase : IStreamingReporter {
  85. template<typename T, typename ChildNodeT>
  86. struct Node {
  87. explicit Node( T const& _value ) : value( _value ) {}
  88. virtual ~Node() {}
  89. using ChildNodes = std::vector<std::shared_ptr<ChildNodeT>>;
  90. T value;
  91. ChildNodes children;
  92. };
  93. struct SectionNode {
  94. explicit SectionNode(SectionStats const& _stats) : stats(_stats) {}
  95. virtual ~SectionNode() = default;
  96. bool operator == (SectionNode const& other) const {
  97. return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
  98. }
  99. bool operator == (std::shared_ptr<SectionNode> const& other) const {
  100. return operator==(*other);
  101. }
  102. SectionStats stats;
  103. using ChildSections = std::vector<std::shared_ptr<SectionNode>>;
  104. using Assertions = std::vector<AssertionStats>;
  105. ChildSections childSections;
  106. Assertions assertions;
  107. std::string stdOut;
  108. std::string stdErr;
  109. };
  110. struct BySectionInfo {
  111. BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
  112. BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
  113. bool operator() (std::shared_ptr<SectionNode> const& node) const {
  114. return ((node->stats.sectionInfo.name == m_other.name) &&
  115. (node->stats.sectionInfo.lineInfo == m_other.lineInfo));
  116. }
  117. void operator=(BySectionInfo const&) = delete;
  118. private:
  119. SectionInfo const& m_other;
  120. };
  121. using TestCaseNode = Node<TestCaseStats, SectionNode>;
  122. using TestGroupNode = Node<TestGroupStats, TestCaseNode>;
  123. using TestRunNode = Node<TestRunStats, TestGroupNode>;
  124. CumulativeReporterBase( ReporterConfig const& _config )
  125. : m_config( _config.fullConfig() ),
  126. stream( _config.stream() )
  127. {
  128. m_reporterPrefs.shouldRedirectStdOut = false;
  129. if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
  130. CATCH_ERROR( "Verbosity level not supported by this reporter" );
  131. }
  132. ~CumulativeReporterBase() override = default;
  133. ReporterPreferences getPreferences() const override {
  134. return m_reporterPrefs;
  135. }
  136. static std::set<Verbosity> getSupportedVerbosities() {
  137. return { Verbosity::Normal };
  138. }
  139. void testRunStarting( TestRunInfo const& ) override {}
  140. void testGroupStarting( GroupInfo const& ) override {}
  141. void testCaseStarting( TestCaseInfo const& ) override {}
  142. void sectionStarting( SectionInfo const& sectionInfo ) override {
  143. SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
  144. std::shared_ptr<SectionNode> node;
  145. if( m_sectionStack.empty() ) {
  146. if( !m_rootSection )
  147. m_rootSection = std::make_shared<SectionNode>( incompleteStats );
  148. node = m_rootSection;
  149. }
  150. else {
  151. SectionNode& parentNode = *m_sectionStack.back();
  152. auto it =
  153. std::find_if( parentNode.childSections.begin(),
  154. parentNode.childSections.end(),
  155. BySectionInfo( sectionInfo ) );
  156. if( it == parentNode.childSections.end() ) {
  157. node = std::make_shared<SectionNode>( incompleteStats );
  158. parentNode.childSections.push_back( node );
  159. }
  160. else
  161. node = *it;
  162. }
  163. m_sectionStack.push_back( node );
  164. m_deepestSection = std::move(node);
  165. }
  166. void assertionStarting(AssertionInfo const&) override {}
  167. bool assertionEnded(AssertionStats const& assertionStats) override {
  168. assert(!m_sectionStack.empty());
  169. // AssertionResult holds a pointer to a temporary DecomposedExpression,
  170. // which getExpandedExpression() calls to build the expression string.
  171. // Our section stack copy of the assertionResult will likely outlive the
  172. // temporary, so it must be expanded or discarded now to avoid calling
  173. // a destroyed object later.
  174. prepareExpandedExpression(const_cast<AssertionResult&>( assertionStats.assertionResult ) );
  175. SectionNode& sectionNode = *m_sectionStack.back();
  176. sectionNode.assertions.push_back(assertionStats);
  177. return true;
  178. }
  179. void sectionEnded(SectionStats const& sectionStats) override {
  180. assert(!m_sectionStack.empty());
  181. SectionNode& node = *m_sectionStack.back();
  182. node.stats = sectionStats;
  183. m_sectionStack.pop_back();
  184. }
  185. void testCaseEnded(TestCaseStats const& testCaseStats) override {
  186. auto node = std::make_shared<TestCaseNode>(testCaseStats);
  187. assert(m_sectionStack.size() == 0);
  188. node->children.push_back(m_rootSection);
  189. m_testCases.push_back(node);
  190. m_rootSection.reset();
  191. assert(m_deepestSection);
  192. m_deepestSection->stdOut = testCaseStats.stdOut;
  193. m_deepestSection->stdErr = testCaseStats.stdErr;
  194. }
  195. void testGroupEnded(TestGroupStats const& testGroupStats) override {
  196. auto node = std::make_shared<TestGroupNode>(testGroupStats);
  197. node->children.swap(m_testCases);
  198. m_testGroups.push_back(node);
  199. }
  200. void testRunEnded(TestRunStats const& testRunStats) override {
  201. auto node = std::make_shared<TestRunNode>(testRunStats);
  202. node->children.swap(m_testGroups);
  203. m_testRuns.push_back(node);
  204. testRunEndedCumulative();
  205. }
  206. virtual void testRunEndedCumulative() = 0;
  207. void skipTest(TestCaseInfo const&) override {}
  208. IConfigPtr m_config;
  209. std::ostream& stream;
  210. std::vector<AssertionStats> m_assertions;
  211. std::vector<std::vector<std::shared_ptr<SectionNode>>> m_sections;
  212. std::vector<std::shared_ptr<TestCaseNode>> m_testCases;
  213. std::vector<std::shared_ptr<TestGroupNode>> m_testGroups;
  214. std::vector<std::shared_ptr<TestRunNode>> m_testRuns;
  215. std::shared_ptr<SectionNode> m_rootSection;
  216. std::shared_ptr<SectionNode> m_deepestSection;
  217. std::vector<std::shared_ptr<SectionNode>> m_sectionStack;
  218. ReporterPreferences m_reporterPrefs;
  219. };
  220. template<char C>
  221. char const* getLineOfChars() {
  222. static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
  223. if( !*line ) {
  224. std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
  225. line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
  226. }
  227. return line;
  228. }
  229. struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> {
  230. TestEventListenerBase( ReporterConfig const& _config );
  231. static std::set<Verbosity> getSupportedVerbosities();
  232. void assertionStarting(AssertionInfo const&) override;
  233. bool assertionEnded(AssertionStats const&) override;
  234. };
  235. } // end namespace Catch
  236. #endif // TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED