From fe98123d0bcfac7c47f398b9ca6bd2dca5b41c6e Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Wed, 5 Dec 2012 08:40:53 +0000 Subject: [PATCH] Started new reporter, "console", which will replace "basic" when done. Introduced Option template as part of this. --- include/internal/catch_impl.hpp | 4 + include/internal/catch_interfaces_reporter.h | 71 ++++++++++++- include/internal/catch_option.hpp | 64 ++++++++++++ include/internal/catch_ptr.hpp | 6 ++ include/internal/catch_test_case_info.h | 2 +- include/internal/catch_test_case_info.hpp | 8 +- include/reporters/catch_reporter_console.hpp | 99 +++++++++++++++++++ .../SelfTest/SurrogateCpps/catch_option.cpp | 2 + .../CatchSelfTest.xcodeproj/project.pbxproj | 8 ++ 9 files changed, 258 insertions(+), 6 deletions(-) create mode 100644 include/internal/catch_option.hpp create mode 100644 include/reporters/catch_reporter_console.hpp create mode 100644 projects/SelfTest/SurrogateCpps/catch_option.cpp diff --git a/include/internal/catch_impl.hpp b/include/internal/catch_impl.hpp index 014a6345..8b4c226c 100644 --- a/include/internal/catch_impl.hpp +++ b/include/internal/catch_impl.hpp @@ -31,6 +31,7 @@ #include "../reporters/catch_reporter_basic.hpp" #include "../reporters/catch_reporter_xml.hpp" #include "../reporters/catch_reporter_junit.hpp" +#include "../reporters/catch_reporter_console.hpp" namespace Catch { NonCopyable::~NonCopyable() {} @@ -54,8 +55,11 @@ namespace Catch { TestCaseStats::~TestCaseStats() {} TestGroupStats::~TestGroupStats() {} TestRunStats::~TestRunStats() {} + ThreadedSectionInfo::~ThreadedSectionInfo() {} BasicReporter::~BasicReporter() {} + AccumulatingReporter::~AccumulatingReporter() {} + ConsoleReporter::~ConsoleReporter() {} IRunner::~IRunner() {} IMutableContext::~IMutableContext() {} IConfig::~IConfig() {} diff --git a/include/internal/catch_interfaces_reporter.h b/include/internal/catch_interfaces_reporter.h index fc272755..2743e969 100644 --- a/include/internal/catch_interfaces_reporter.h +++ b/include/internal/catch_interfaces_reporter.h @@ -14,6 +14,7 @@ #include "catch_config.hpp" #include "catch_test_case_info.h" #include "catch_assertionresult.h" +#include "catch_option.hpp" #include #include @@ -25,7 +26,7 @@ namespace Catch ReporterConfig( std::ostream& _stream, ConfigData const& _fullConfig ) : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} - std::ostream& stream() { return *m_stream; } + std::ostream& stream() const { return *m_stream; } std::string name() const { return m_fullConfig.name; } bool includeSuccessfulResults() const { return m_fullConfig.includeWhichResults == Include::SuccessfulResults; } bool warnAboutMissingAssertions() const { return m_fullConfig.warnings & ConfigData::WarnAbout::NoAssertions; } @@ -66,6 +67,17 @@ namespace Catch SourceLineInfo lineInfo; }; + struct ThreadedSectionInfo : SectionInfo, SharedImpl<> { + ThreadedSectionInfo( SectionInfo const& _sectionInfo, Ptr const& _parent = Ptr() ) + : SectionInfo( _sectionInfo ), + parent( _parent ) + {} + virtual ~ThreadedSectionInfo(); + + std::vector > children; + Ptr parent; + }; + struct AssertionStats : SharedImpl<> { AssertionStats( AssertionResult const& _assertionResult, Totals const& _totals ) @@ -150,6 +162,10 @@ namespace Catch // !Work In progress struct IStreamingReporter : IShared { virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static methid: + // static std::string getDescription(); + virtual ReporterPreferences getPreferences() const = 0; virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; @@ -171,6 +187,59 @@ namespace Catch // - this would be used by the JUnit reporter, for example. // - it may be used by the basic reporter, too, but that would clear down the stack // as it goes + struct AccumulatingReporter : SharedImpl { + + AccumulatingReporter( ReporterConfig const& _config ) + : stream( _config.stream() ) + {} + + virtual ~AccumulatingReporter(); + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { + testRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) { + unusedGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { + unusedTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + Ptr sectionInfo = new ThreadedSectionInfo( _sectionInfo ); + unusedSectionInfo = sectionInfo; + if( !currentSectionInfo ) { + currentSectionInfo = sectionInfo; + } + else { + currentSectionInfo->children.push_back( sectionInfo ); + sectionInfo->parent = currentSectionInfo; + currentSectionInfo = sectionInfo; + } + } + + virtual void sectionEnded( Ptr const& /* _sectionStats */ ) { + currentSectionInfo = currentSectionInfo->parent; + unusedSectionInfo = currentSectionInfo; + } + virtual void testCaseEnded( Ptr const& /* _testCaseStats */ ) { + unusedTestCaseInfo.reset(); + } + virtual void testGroupEnded( Ptr const& /* _testGroupStats */ ) { + unusedGroupInfo.reset(); + } + virtual void testRunEnded( Ptr const& /* _testRunStats */ ) { + } + + Option testRunInfo; + Option unusedGroupInfo; + Option unusedTestCaseInfo; + Ptr unusedSectionInfo; + Ptr currentSectionInfo; + bool currentSectionOpen; + std::ostream& stream; + }; + // Deprecated diff --git a/include/internal/catch_option.hpp b/include/internal/catch_option.hpp new file mode 100644 index 00000000..0b01a4dc --- /dev/null +++ b/include/internal/catch_option.hpp @@ -0,0 +1,64 @@ +/* + * Created by Phil on 02/12/2012. + * Copyright 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED + +#include "catch_common.h" + +namespace Catch { + + // An optional type + template + class Option { + public: + Option() : nullableValue( NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : NULL ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = NULL; + } + T& operator*() { return *nullableValue; } + const T& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + bool some() const { return nullableValue != NULL; } + bool none() const { return nullableValue == NULL; } + + bool operator !() const { return nullableValue == NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + + private: + T* nullableValue; + char storage[sizeof(T)]; + }; + + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED diff --git a/include/internal/catch_ptr.hpp b/include/internal/catch_ptr.hpp index 60000aaa..2817ddd1 100644 --- a/include/internal/catch_ptr.hpp +++ b/include/internal/catch_ptr.hpp @@ -31,6 +31,11 @@ namespace Catch { if( m_p ) m_p->release(); } + void reset() { + if( m_p ) + m_p->release(); + m_p = NULL; + } Ptr& operator = ( T* p ){ Ptr temp( p ); swap( temp ); @@ -47,6 +52,7 @@ namespace Catch { T& operator*() const { return *m_p; } T* operator->() const { return m_p; } bool operator !() const { return m_p == NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } private: T* m_p; diff --git a/include/internal/catch_test_case_info.h b/include/internal/catch_test_case_info.h index b3f133b4..fd4e44ad 100644 --- a/include/internal/catch_test_case_info.h +++ b/include/internal/catch_test_case_info.h @@ -31,8 +31,8 @@ namespace Catch { std::string className; std::string description; std::set tags; - bool isHidden; SourceLineInfo lineInfo; + bool isHidden; }; class TestCase : protected TestCaseInfo { diff --git a/include/internal/catch_test_case_info.hpp b/include/internal/catch_test_case_info.hpp index e7e12166..6795047d 100644 --- a/include/internal/catch_test_case_info.hpp +++ b/include/internal/catch_test_case_info.hpp @@ -41,8 +41,8 @@ namespace Catch { className( _className ), description( _description ), tags( _tags ), - isHidden( _isHidden ), - lineInfo( _lineInfo ) + lineInfo( _lineInfo ), + isHidden( _isHidden ) {} TestCaseInfo::TestCaseInfo( const TestCaseInfo& other ) @@ -50,8 +50,8 @@ namespace Catch { className( other.className ), description( other.description ), tags( other.tags ), - isHidden( other.isHidden ), - lineInfo( other.lineInfo ) + lineInfo( other.lineInfo ), + isHidden( other.isHidden ) {} TestCase::TestCase( ITestCase* testCase, const TestCaseInfo& info ) : TestCaseInfo( info ), test( testCase ) {} diff --git a/include/reporters/catch_reporter_console.hpp b/include/reporters/catch_reporter_console.hpp new file mode 100644 index 00000000..4eeb8c79 --- /dev/null +++ b/include/reporters/catch_reporter_console.hpp @@ -0,0 +1,99 @@ +/* + * Created by Phil on 5/12/2012. + * Copyright 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +#include "../internal/catch_interfaces_reporter.h" +#include "../internal/catch_reporter_registrars.hpp" +#include "../internal/catch_console_colour.hpp" + +namespace Catch { + + struct ConsoleReporter : AccumulatingReporter { + ConsoleReporter( ReporterConfig const& _config ) + : AccumulatingReporter( _config ) + {} + + virtual ~ConsoleReporter(); + static std::string getDescription() { + return "Reports test results as plain lines of text"; + } + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + + } + void lazyPrintRunInfo() { + stream << "[Started testing: " << testRunInfo->name << "]" << std::endl; + testRunInfo.reset(); + } + void lazyPrintGroupInfo() { + if( !unusedGroupInfo->name.empty() ) + stream << "[Group: " << unusedGroupInfo->name << "]" << std::endl; + unusedGroupInfo.reset(); + } + void lazyPrintTestCaseInfo() { + stream << "[TestCase: " << unusedTestCaseInfo->name << "]" << std::endl; + unusedTestCaseInfo.reset(); + } + void lazyPrintSectionInfo() { + ThreadedSectionInfo* section = unusedSectionInfo.get(); + bool firstSection = true; + stream << "[Section: "; + do { + if( firstSection ) + firstSection = false; + else + stream << ",\n "; + stream << section->name; + section = section->parent.get(); + } + while( section ); + + stream << "]" << std::endl; + unusedSectionInfo.reset(); + } + void lazyPrint() { + if( testRunInfo ) + lazyPrintRunInfo(); + if( unusedGroupInfo ) + lazyPrintGroupInfo(); + if( unusedTestCaseInfo ) + lazyPrintTestCaseInfo(); + if( unusedSectionInfo ) + lazyPrintSectionInfo(); + } + + virtual void assertionStarting( AssertionInfo const& _assertionInfo ) { + } + virtual void assertionEnded( Ptr const& _assertionStats ) { + if( !_assertionStats->assertionResult.isOk() ) + lazyPrint(); + } + + virtual void sectionEnded( Ptr const& _sectionStats ) { + if( !unusedSectionInfo ) { + stream << "[Section totals: ]" << std::endl; + } + AccumulatingReporter::sectionEnded( _sectionStats ); + } + virtual void testCaseEnded( Ptr const& _testCaseStats ) { + if( !unusedTestCaseInfo ) { + stream << "[TestCase totals: ]\n" << std::endl; + } + AccumulatingReporter::testCaseEnded( _testCaseStats ); + } + + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED diff --git a/projects/SelfTest/SurrogateCpps/catch_option.cpp b/projects/SelfTest/SurrogateCpps/catch_option.cpp new file mode 100644 index 00000000..9461fdef --- /dev/null +++ b/projects/SelfTest/SurrogateCpps/catch_option.cpp @@ -0,0 +1,2 @@ +// This file is only here to verify (to the extent possible) the self sufficiency of the header +#include "catch_option.hpp" diff --git a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj index 0376b843..7346eb15 100644 --- a/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj +++ b/projects/XCode4/CatchSelfTest/CatchSelfTest.xcodeproj/project.pbxproj @@ -30,6 +30,7 @@ 4AB3D99D1616216500C9A0F8 /* catch_interfaces_testcase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AB3D99C1616216500C9A0F8 /* catch_interfaces_testcase.cpp */; }; 4AB3D9A01616219100C9A0F8 /* catch_interfaces_config.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AB3D99F1616219100C9A0F8 /* catch_interfaces_config.cpp */; }; 4AB3D9A2161621B500C9A0F8 /* catch_interfaces_generators.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AB3D9A1161621B500C9A0F8 /* catch_interfaces_generators.cpp */; }; + 4ACE21CC166CA1B300FB5509 /* catch_option.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4ACE21CA166CA1B300FB5509 /* catch_option.cpp */; }; 4AE1840B14EE4F230066340D /* catch_self_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AE1840A14EE4F230066340D /* catch_self_test.cpp */; }; 4AEE032016142F910071E950 /* catch_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AEE031F16142F910071E950 /* catch_common.cpp */; }; 4AEE032316142FC70071E950 /* catch_debugger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AEE032216142FC70071E950 /* catch_debugger.cpp */; }; @@ -132,12 +133,15 @@ 4AB3D99C1616216500C9A0F8 /* catch_interfaces_testcase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_interfaces_testcase.cpp; path = ../../../SelfTest/SurrogateCpps/catch_interfaces_testcase.cpp; sourceTree = ""; }; 4AB3D99F1616219100C9A0F8 /* catch_interfaces_config.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_interfaces_config.cpp; path = ../../../SelfTest/SurrogateCpps/catch_interfaces_config.cpp; sourceTree = ""; }; 4AB3D9A1161621B500C9A0F8 /* catch_interfaces_generators.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_interfaces_generators.cpp; path = ../../../SelfTest/SurrogateCpps/catch_interfaces_generators.cpp; sourceTree = ""; }; + 4AB42F84166F3E1A0099F2C8 /* catch_reporter_console.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_reporter_console.hpp; sourceTree = ""; }; 4AB77CB51551AEA200857BF0 /* catch_ptr.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_ptr.hpp; sourceTree = ""; }; 4AB77CB71553B72B00857BF0 /* catch_section_info.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_section_info.hpp; sourceTree = ""; }; 4AB77CB81553BB3800857BF0 /* catch_running_test.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; path = catch_running_test.hpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 4ABEA80415C90D2B009F0424 /* catch_objc_arc.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_objc_arc.hpp; sourceTree = ""; }; 4AC91CCE155CF02800DC5117 /* catch_expression_lhs.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; path = catch_expression_lhs.hpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 4AC91CD0155D8DA600DC5117 /* catch_expression_decomposer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; lineEnding = 0; path = catch_expression_decomposer.hpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; + 4ACE21C8166CA19700FB5509 /* catch_option.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_option.hpp; sourceTree = ""; }; + 4ACE21CA166CA1B300FB5509 /* catch_option.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_option.cpp; path = ../../../SelfTest/SurrogateCpps/catch_option.cpp; sourceTree = ""; }; 4AE1840A14EE4F230066340D /* catch_self_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_self_test.cpp; path = ../../../SelfTest/catch_self_test.cpp; sourceTree = ""; }; 4AEE031F16142F910071E950 /* catch_common.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_common.cpp; path = ../../../SelfTest/SurrogateCpps/catch_common.cpp; sourceTree = ""; }; 4AEE032216142FC70071E950 /* catch_debugger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_debugger.cpp; path = ../../../SelfTest/SurrogateCpps/catch_debugger.cpp; sourceTree = ""; }; @@ -240,6 +244,7 @@ 4A6D0C66149B3E3D00DB3EAA /* catch_reporter_basic.hpp */, 4A6D0C67149B3E3D00DB3EAA /* catch_reporter_junit.hpp */, 4A6D0C68149B3E3D00DB3EAA /* catch_reporter_xml.hpp */, + 4AB42F84166F3E1A0099F2C8 /* catch_reporter_console.hpp */, ); name = reporters; path = ../../../../include/reporters; @@ -264,6 +269,7 @@ 4AB3D99C1616216500C9A0F8 /* catch_interfaces_testcase.cpp */, 4AB3D99F1616219100C9A0F8 /* catch_interfaces_config.cpp */, 4AB3D9A1161621B500C9A0F8 /* catch_interfaces_generators.cpp */, + 4ACE21CA166CA1B300FB5509 /* catch_option.cpp */, ); name = SurrogateCpps; sourceTree = ""; @@ -367,6 +373,7 @@ 4AB1C73714F97C1300F31DF7 /* catch_console_colour.hpp */, 4AB77CB51551AEA200857BF0 /* catch_ptr.hpp */, 4AEE0326161431070071E950 /* catch_streambuf.h */, + 4ACE21C8166CA19700FB5509 /* catch_option.hpp */, ); name = Infrastructure; sourceTree = ""; @@ -457,6 +464,7 @@ 4AB3D99D1616216500C9A0F8 /* catch_interfaces_testcase.cpp in Sources */, 4AB3D9A01616219100C9A0F8 /* catch_interfaces_config.cpp in Sources */, 4AB3D9A2161621B500C9A0F8 /* catch_interfaces_generators.cpp in Sources */, + 4ACE21CC166CA1B300FB5509 /* catch_option.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };