diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ba4ca435..705b31d0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -120,7 +120,6 @@ set(INTERNAL_HEADERS ${SOURCES_DIR}/internal/catch_preprocessor_remove_parens.hpp ${SOURCES_DIR}/internal/catch_random_number_generator.hpp ${SOURCES_DIR}/internal/catch_random_seed_generation.hpp - ${SOURCES_DIR}/reporters/catch_reporter_registrars.hpp ${SOURCES_DIR}/internal/catch_reporter_registry.hpp ${SOURCES_DIR}/internal/catch_reporter_spec_parser.hpp ${SOURCES_DIR}/internal/catch_result_type.hpp @@ -237,6 +236,7 @@ set(REPORTER_HEADERS ${SOURCES_DIR}/reporters/catch_reporter_helpers.hpp ${SOURCES_DIR}/reporters/catch_reporter_junit.hpp ${SOURCES_DIR}/reporters/catch_reporter_multi.hpp + ${SOURCES_DIR}/reporters/catch_reporter_registrars.hpp ${SOURCES_DIR}/reporters/catch_reporter_sonarqube.hpp ${SOURCES_DIR}/reporters/catch_reporter_streaming_base.hpp ${SOURCES_DIR}/reporters/catch_reporter_tap.hpp @@ -252,6 +252,7 @@ set(REPORTER_SOURCES ${SOURCES_DIR}/reporters/catch_reporter_cumulative_base.cpp ${SOURCES_DIR}/reporters/catch_reporter_junit.cpp ${SOURCES_DIR}/reporters/catch_reporter_multi.cpp + ${SOURCES_DIR}/reporters/catch_reporter_registrars.cpp ${SOURCES_DIR}/reporters/catch_reporter_sonarqube.cpp ${SOURCES_DIR}/reporters/catch_reporter_streaming_base.cpp ${SOURCES_DIR}/reporters/catch_reporter_tap.cpp diff --git a/src/catch2/reporters/catch_reporter_registrars.cpp b/src/catch2/reporters/catch_reporter_registrars.cpp new file mode 100644 index 00000000..fd1bc76c --- /dev/null +++ b/src/catch2/reporters/catch_reporter_registrars.cpp @@ -0,0 +1,30 @@ + +// Copyright Catch2 Authors +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +// SPDX-License-Identifier: BSL-1.0 + +#include + +#include + +namespace Catch { + namespace Detail { + + void registerReporterImpl( std::string const& name, + IReporterFactoryPtr reporterPtr ) { + CATCH_TRY { + getMutableRegistryHub().registerReporter( + name, CATCH_MOVE( reporterPtr ) ); + } + CATCH_CATCH_ALL { + // Do not throw when constructing global objects, instead + // register the exception to be processed later + getMutableRegistryHub().registerStartupException(); + } + } + + } // namespace Detail +} // namespace Catch diff --git a/src/catch2/reporters/catch_reporter_registrars.hpp b/src/catch2/reporters/catch_reporter_registrars.hpp index e0922524..e33ecf8b 100644 --- a/src/catch2/reporters/catch_reporter_registrars.hpp +++ b/src/catch2/reporters/catch_reporter_registrars.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ namespace Catch { namespace Detail { + template struct has_description : std::false_type {}; @@ -29,7 +31,13 @@ namespace Catch { T, void_t> : std::true_type {}; - } + + //! Indirection for reporter registration, so that the error handling is + //! independent on the reporter's concrete type + void registerReporterImpl( std::string const& name, + IReporterFactoryPtr reporterPtr ); + + } // namespace Detail class IEventListener; using IEventListenerPtr = Detail::unique_ptr; @@ -51,7 +59,8 @@ namespace Catch { class ReporterRegistrar { public: explicit ReporterRegistrar( std::string const& name ) { - getMutableRegistryHub().registerReporter( name, Detail::make_unique>() ); + registerReporterImpl( name, + Detail::make_unique>() ); } }; @@ -95,17 +104,24 @@ namespace Catch { #if !defined(CATCH_CONFIG_DISABLE) -#define CATCH_REGISTER_REPORTER( name, reporterType ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +# define CATCH_REGISTER_REPORTER( name, reporterType ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace { \ + Catch::ReporterRegistrar INTERNAL_CATCH_UNIQUE_NAME( \ + catch_internal_RegistrarFor )( name ); \ + } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +# define CATCH_REGISTER_LISTENER( listenerType ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace { \ + Catch::ListenerRegistrar INTERNAL_CATCH_UNIQUE_NAME( \ + catch_internal_RegistrarFor )( #listenerType ); \ + } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION -#define CATCH_REGISTER_LISTENER( listenerType ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace { Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType(#listenerType); } \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #else // CATCH_CONFIG_DISABLE #define CATCH_REGISTER_REPORTER(name, reporterType) diff --git a/tests/ExtraTests/CMakeLists.txt b/tests/ExtraTests/CMakeLists.txt index 0b72bbfb..e533ad4a 100644 --- a/tests/ExtraTests/CMakeLists.txt +++ b/tests/ExtraTests/CMakeLists.txt @@ -421,6 +421,20 @@ set_tests_properties( FAIL_REGULAR_EXPRESSION "error: .* already defined\\." ) + +add_executable(DuplicatedReporters ${TESTS_DIR}/X35-DuplicatedReporterNames.cpp) +target_link_libraries(DuplicatedReporters PRIVATE Catch2::Catch2WithMain) +add_test( + NAME Reporters::RegistrationErrorsAreCaught + COMMAND $ +) +set_tests_properties( + Reporters::RegistrationErrorsAreCaught + PROPERTIES + PASS_REGULAR_EXPRESSION "Errors occurred during startup!" +) + + #add_executable(DebugBreakMacros ${TESTS_DIR}/X12-CustomDebugBreakMacro.cpp) #target_link_libraries(DebugBreakMacros Catch2) #add_test(NAME DebugBreakMacros COMMAND DebugBreakMacros --break) diff --git a/tests/ExtraTests/X35-DuplicatedReporterNames.cpp b/tests/ExtraTests/X35-DuplicatedReporterNames.cpp new file mode 100644 index 00000000..cc0dd0b9 --- /dev/null +++ b/tests/ExtraTests/X35-DuplicatedReporterNames.cpp @@ -0,0 +1,31 @@ + +// Copyright Catch2 Authors +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +// SPDX-License-Identifier: BSL-1.0 + +/**\file + * Checks that reporter registration errors are caught and handled as + * startup errors, by causing a registration error by registering multiple + * reporters with the same name. + */ + +#include + +#include +#include + +namespace { + //! Trivial custom reporter for registration + class TestReporter : public Catch::StreamingReporterBase { + public: + using StreamingReporterBase::StreamingReporterBase; + + static std::string getDescription() { return "X35 test reporter"; } + }; +} + +CATCH_REGISTER_REPORTER( "test-reporter", TestReporter ) +CATCH_REGISTER_REPORTER( "test-reporter", TestReporter )