mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-11-04 14:09:33 +01:00 
			
		
		
		
	Call listeners before calling reporters
Catch2's documentation promises that listeners are called _before_ reporters, but because of the previous implementation, they were called _after_ reporters. This commit fixes that. Closes #1234
This commit is contained in:
		@@ -265,7 +265,7 @@ set(REPORTER_HEADERS
 | 
			
		||||
        ${HEADER_DIR}/reporters/catch_reporter_compact.h
 | 
			
		||||
        ${HEADER_DIR}/reporters/catch_reporter_console.h
 | 
			
		||||
        ${HEADER_DIR}/reporters/catch_reporter_junit.h
 | 
			
		||||
        ${HEADER_DIR}/reporters/catch_reporter_multi.h
 | 
			
		||||
        ${HEADER_DIR}/reporters/catch_reporter_listening.h
 | 
			
		||||
        ${HEADER_DIR}/reporters/catch_reporter_tap.hpp
 | 
			
		||||
        ${HEADER_DIR}/reporters/catch_reporter_teamcity.hpp
 | 
			
		||||
        ${HEADER_DIR}/reporters/catch_reporter_xml.h
 | 
			
		||||
@@ -275,7 +275,7 @@ set(REPORTER_SOURCES
 | 
			
		||||
        ${HEADER_DIR}/reporters/catch_reporter_compact.cpp
 | 
			
		||||
        ${HEADER_DIR}/reporters/catch_reporter_console.cpp
 | 
			
		||||
        ${HEADER_DIR}/reporters/catch_reporter_junit.cpp
 | 
			
		||||
        ${HEADER_DIR}/reporters/catch_reporter_multi.cpp
 | 
			
		||||
        ${HEADER_DIR}/reporters/catch_reporter_listening.cpp
 | 
			
		||||
        ${HEADER_DIR}/reporters/catch_reporter_xml.cpp
 | 
			
		||||
        )
 | 
			
		||||
set(REPORTER_FILES ${REPORTER_HEADERS} ${REPORTER_SOURCES})
 | 
			
		||||
 
 | 
			
		||||
@@ -54,14 +54,12 @@ namespace Catch {
 | 
			
		||||
        std::string outputFilename;
 | 
			
		||||
        std::string name;
 | 
			
		||||
        std::string processName;
 | 
			
		||||
 | 
			
		||||
#ifndef CATCH_CONFIG_DEFAULT_REPORTER
 | 
			
		||||
#define CATCH_CONFIG_DEFAULT_REPORTER "console"
 | 
			
		||||
#endif
 | 
			
		||||
        std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER;
 | 
			
		||||
#undef CATCH_CONFIG_DEFAULT_REPORTER
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        std::vector<std::string> testsOrTags;
 | 
			
		||||
        std::vector<std::string> sectionsToRun;
 | 
			
		||||
    };
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "catch_interfaces_reporter.h"
 | 
			
		||||
#include "../reporters/catch_reporter_multi.h"
 | 
			
		||||
#include "../reporters/catch_reporter_listening.h"
 | 
			
		||||
 | 
			
		||||
namespace Catch {
 | 
			
		||||
 | 
			
		||||
@@ -111,25 +111,4 @@ namespace Catch {
 | 
			
		||||
    IReporterFactory::~IReporterFactory() = default;
 | 
			
		||||
    IReporterRegistry::~IReporterRegistry() = default;
 | 
			
		||||
 | 
			
		||||
    void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ) {
 | 
			
		||||
 | 
			
		||||
        if( !existingReporter ) {
 | 
			
		||||
            existingReporter = std::move( additionalReporter );
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        MultipleReporters* multi = nullptr;
 | 
			
		||||
 | 
			
		||||
        if( existingReporter->isMulti() ) {
 | 
			
		||||
            multi = static_cast<MultipleReporters*>( existingReporter.get() );
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            auto newMulti = std::unique_ptr<MultipleReporters>( new MultipleReporters );
 | 
			
		||||
            newMulti->add( std::move( existingReporter ) );
 | 
			
		||||
            multi = newMulti.get();
 | 
			
		||||
            existingReporter = std::move( newMulti );
 | 
			
		||||
        }
 | 
			
		||||
        multi->add( std::move( additionalReporter ) );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
} // end namespace Catch
 | 
			
		||||
 
 | 
			
		||||
@@ -226,8 +226,6 @@ namespace Catch {
 | 
			
		||||
        virtual Listeners const& getListeners() const = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter );
 | 
			
		||||
 | 
			
		||||
} // end namespace Catch
 | 
			
		||||
 | 
			
		||||
#endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@
 | 
			
		||||
#include "catch_text.h"
 | 
			
		||||
#include "catch_stream.h"
 | 
			
		||||
#include "catch_windows_h_proxy.h"
 | 
			
		||||
#include "../reporters/catch_reporter_listening.h"
 | 
			
		||||
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
@@ -36,22 +37,26 @@ namespace Catch {
 | 
			
		||||
            return reporter;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) {
 | 
			
		||||
            return createReporter(config->getReporterName(), config);
 | 
			
		||||
        }
 | 
			
		||||
            if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) {
 | 
			
		||||
                return createReporter(config->getReporterName(), config);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            auto multi = std::unique_ptr<ListeningReporter>(new ListeningReporter);
 | 
			
		||||
 | 
			
		||||
        void addListeners(IStreamingReporterPtr& reporters, IConfigPtr const& config) {
 | 
			
		||||
            auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
 | 
			
		||||
            for (auto const& listener : listeners)
 | 
			
		||||
                addReporter(reporters, listener->create(Catch::ReporterConfig(config)));
 | 
			
		||||
            for (auto const& listener : listeners) {
 | 
			
		||||
                multi->addListener(listener->create(Catch::ReporterConfig(config)));
 | 
			
		||||
            }
 | 
			
		||||
            multi->addReporter(createReporter(config->getReporterName(), config));
 | 
			
		||||
            return std::move(multi);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        Catch::Totals runTests(std::shared_ptr<Config> const& config) {
 | 
			
		||||
            IStreamingReporterPtr reporter = makeReporter(config);
 | 
			
		||||
            addListeners(reporter, config);
 | 
			
		||||
            // FixMe: Add listeners in order first, then add reporters.
 | 
			
		||||
 | 
			
		||||
            auto reporter = makeReporter(config);
 | 
			
		||||
 | 
			
		||||
            RunContext context(config, std::move(reporter));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										136
									
								
								include/reporters/catch_reporter_listening.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								include/reporters/catch_reporter_listening.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,136 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Created by Phil on 5/08/2015.
 | 
			
		||||
 *  Copyright 2015 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)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 #include "catch_reporter_listening.h"
 | 
			
		||||
#include <cassert>
 | 
			
		||||
 | 
			
		||||
namespace Catch {
 | 
			
		||||
 | 
			
		||||
    void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) {
 | 
			
		||||
        m_listeners.push_back( std::move( listener ) );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) {
 | 
			
		||||
        assert(!m_reporter && "Listening reporter can wrap only 1 real reporter");
 | 
			
		||||
        m_reporter = std::move( reporter );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ReporterPreferences ListeningReporter::getPreferences() const {
 | 
			
		||||
        return m_reporter->getPreferences();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::set<Verbosity> ListeningReporter::getSupportedVerbosities() {
 | 
			
		||||
        return std::set<Verbosity>{ };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void ListeningReporter::noMatchingTestCases( std::string const& spec ) {
 | 
			
		||||
        for ( auto const& listener : m_listeners ) {
 | 
			
		||||
            listener->noMatchingTestCases( spec );
 | 
			
		||||
        }
 | 
			
		||||
        m_reporter->noMatchingTestCases( spec );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
 | 
			
		||||
        for ( auto const& listener : m_listeners ) {
 | 
			
		||||
            listener->benchmarkStarting( benchmarkInfo );
 | 
			
		||||
        }
 | 
			
		||||
        m_reporter->benchmarkStarting( benchmarkInfo );
 | 
			
		||||
    }
 | 
			
		||||
    void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) {
 | 
			
		||||
        for ( auto const& listener : m_listeners ) {
 | 
			
		||||
            listener->benchmarkEnded( benchmarkStats );
 | 
			
		||||
        }
 | 
			
		||||
        m_reporter->benchmarkEnded( benchmarkStats );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) {
 | 
			
		||||
        for ( auto const& listener : m_listeners ) {
 | 
			
		||||
            listener->testRunStarting( testRunInfo );
 | 
			
		||||
        }
 | 
			
		||||
        m_reporter->testRunStarting( testRunInfo );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) {
 | 
			
		||||
        for ( auto const& listener : m_listeners ) {
 | 
			
		||||
            listener->testGroupStarting( groupInfo );
 | 
			
		||||
        }
 | 
			
		||||
        m_reporter->testGroupStarting( groupInfo );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
 | 
			
		||||
        for ( auto const& listener : m_listeners ) {
 | 
			
		||||
            listener->testCaseStarting( testInfo );
 | 
			
		||||
        }
 | 
			
		||||
        m_reporter->testCaseStarting( testInfo );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) {
 | 
			
		||||
        for ( auto const& listener : m_listeners ) {
 | 
			
		||||
            listener->sectionStarting( sectionInfo );
 | 
			
		||||
        }
 | 
			
		||||
        m_reporter->sectionStarting( sectionInfo );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) {
 | 
			
		||||
        for ( auto const& listener : m_listeners ) {
 | 
			
		||||
            listener->assertionStarting( assertionInfo );
 | 
			
		||||
        }
 | 
			
		||||
        m_reporter->assertionStarting( assertionInfo );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The return value indicates if the messages buffer should be cleared:
 | 
			
		||||
    bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) {
 | 
			
		||||
        for( auto const& listener : m_listeners ) {
 | 
			
		||||
            static_cast<void>( listener->assertionEnded( assertionStats ) );
 | 
			
		||||
        }
 | 
			
		||||
        return m_reporter->assertionEnded( assertionStats );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) {
 | 
			
		||||
        for ( auto const& listener : m_listeners ) {
 | 
			
		||||
            listener->sectionEnded( sectionStats );
 | 
			
		||||
        }
 | 
			
		||||
        m_reporter->sectionEnded( sectionStats );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
 | 
			
		||||
        for ( auto const& listener : m_listeners ) {
 | 
			
		||||
            listener->testCaseEnded( testCaseStats );
 | 
			
		||||
        }
 | 
			
		||||
        m_reporter->testCaseEnded( testCaseStats );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {
 | 
			
		||||
        for ( auto const& listener : m_listeners ) {
 | 
			
		||||
            listener->testGroupEnded( testGroupStats );
 | 
			
		||||
        }
 | 
			
		||||
        m_reporter->testGroupEnded( testGroupStats );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) {
 | 
			
		||||
        for ( auto const& listener : m_listeners ) {
 | 
			
		||||
            listener->testRunEnded( testRunStats );
 | 
			
		||||
        }
 | 
			
		||||
        m_reporter->testRunEnded( testRunStats );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) {
 | 
			
		||||
        for ( auto const& listener : m_listeners ) {
 | 
			
		||||
            listener->skipTest( testInfo );
 | 
			
		||||
        }
 | 
			
		||||
        m_reporter->skipTest( testInfo );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool ListeningReporter::isMulti() const {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
} // end namespace Catch
 | 
			
		||||
@@ -11,12 +11,14 @@
 | 
			
		||||
 | 
			
		||||
namespace Catch {
 | 
			
		||||
 | 
			
		||||
    class MultipleReporters : public IStreamingReporter {
 | 
			
		||||
    class ListeningReporter : public IStreamingReporter {
 | 
			
		||||
        using Reporters = std::vector<IStreamingReporterPtr>;
 | 
			
		||||
        Reporters m_reporters;
 | 
			
		||||
        Reporters m_listeners;
 | 
			
		||||
        IStreamingReporterPtr m_reporter = nullptr;
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        void add( IStreamingReporterPtr&& reporter );
 | 
			
		||||
        void addListener( IStreamingReporterPtr&& listener );
 | 
			
		||||
        void addReporter( IStreamingReporterPtr&& reporter );
 | 
			
		||||
 | 
			
		||||
    public: // IStreamingReporter
 | 
			
		||||
 | 
			
		||||
@@ -1,104 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Created by Phil on 5/08/2015.
 | 
			
		||||
 *  Copyright 2015 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)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 #include "catch_reporter_multi.h"
 | 
			
		||||
 | 
			
		||||
namespace Catch {
 | 
			
		||||
 | 
			
		||||
    void MultipleReporters::add( IStreamingReporterPtr&& reporter ) {
 | 
			
		||||
        m_reporters.push_back( std::move( reporter ) );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ReporterPreferences MultipleReporters::getPreferences() const {
 | 
			
		||||
        return m_reporters[0]->getPreferences();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::set<Verbosity> MultipleReporters::getSupportedVerbosities() {
 | 
			
		||||
        return std::set<Verbosity>{ };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void MultipleReporters::noMatchingTestCases( std::string const& spec ) {
 | 
			
		||||
        for( auto const& reporter : m_reporters )
 | 
			
		||||
            reporter->noMatchingTestCases( spec );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MultipleReporters::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
 | 
			
		||||
        for( auto const& reporter : m_reporters )
 | 
			
		||||
            reporter->benchmarkStarting( benchmarkInfo );
 | 
			
		||||
    }
 | 
			
		||||
    void MultipleReporters::benchmarkEnded( BenchmarkStats const& benchmarkStats ) {
 | 
			
		||||
        for( auto const& reporter : m_reporters )
 | 
			
		||||
            reporter->benchmarkEnded( benchmarkStats );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MultipleReporters::testRunStarting( TestRunInfo const& testRunInfo ) {
 | 
			
		||||
        for( auto const& reporter : m_reporters )
 | 
			
		||||
            reporter->testRunStarting( testRunInfo );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MultipleReporters::testGroupStarting( GroupInfo const& groupInfo ) {
 | 
			
		||||
        for( auto const& reporter : m_reporters )
 | 
			
		||||
            reporter->testGroupStarting( groupInfo );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void MultipleReporters::testCaseStarting( TestCaseInfo const& testInfo ) {
 | 
			
		||||
        for( auto const& reporter : m_reporters )
 | 
			
		||||
            reporter->testCaseStarting( testInfo );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MultipleReporters::sectionStarting( SectionInfo const& sectionInfo ) {
 | 
			
		||||
        for( auto const& reporter : m_reporters )
 | 
			
		||||
            reporter->sectionStarting( sectionInfo );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MultipleReporters::assertionStarting( AssertionInfo const& assertionInfo ) {
 | 
			
		||||
        for( auto const& reporter : m_reporters )
 | 
			
		||||
            reporter->assertionStarting( assertionInfo );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The return value indicates if the messages buffer should be cleared:
 | 
			
		||||
    bool MultipleReporters::assertionEnded( AssertionStats const& assertionStats ) {
 | 
			
		||||
        bool clearBuffer = false;
 | 
			
		||||
        for( auto const& reporter : m_reporters )
 | 
			
		||||
            clearBuffer |= reporter->assertionEnded( assertionStats );
 | 
			
		||||
        return clearBuffer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MultipleReporters::sectionEnded( SectionStats const& sectionStats ) {
 | 
			
		||||
        for( auto const& reporter : m_reporters )
 | 
			
		||||
            reporter->sectionEnded( sectionStats );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MultipleReporters::testCaseEnded( TestCaseStats const& testCaseStats ) {
 | 
			
		||||
        for( auto const& reporter : m_reporters )
 | 
			
		||||
            reporter->testCaseEnded( testCaseStats );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MultipleReporters::testGroupEnded( TestGroupStats const& testGroupStats ) {
 | 
			
		||||
        for( auto const& reporter : m_reporters )
 | 
			
		||||
            reporter->testGroupEnded( testGroupStats );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MultipleReporters::testRunEnded( TestRunStats const& testRunStats ) {
 | 
			
		||||
        for( auto const& reporter : m_reporters )
 | 
			
		||||
            reporter->testRunEnded( testRunStats );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void MultipleReporters::skipTest( TestCaseInfo const& testInfo ) {
 | 
			
		||||
        for( auto const& reporter : m_reporters )
 | 
			
		||||
            reporter->skipTest( testInfo );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool MultipleReporters::isMulti() const {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
} // end namespace Catch
 | 
			
		||||
		Reference in New Issue
	
	Block a user