diff options
| author | Martin Hořeňovský | 2023-01-17 11:04:49 +0100 |
|---|---|---|
| committer | Martin Hořeňovský | 2023-01-22 16:04:16 +0100 |
| commit | 8359a6b244a26cffabd4440b17fac8b1392815af (patch) | |
| tree | eb0a396ddc582cb7f1b5e5f7d0b3b369d18ebc40 /src | |
| parent | adf43494e19077d492343ea13d597af5133b7288 (diff) | |
| download | catch3-8359a6b244a26cffabd4440b17fac8b1392815af.tar.gz | |
Stop exceptions in generator constructors from aborting the binary
Fixes #2615
Diffstat (limited to 'src')
| -rw-r--r-- | src/catch2/generators/catch_generators.cpp | 9 | ||||
| -rw-r--r-- | src/catch2/generators/catch_generators.hpp | 20 | ||||
| -rw-r--r-- | src/catch2/interfaces/catch_interfaces_capture.hpp | 15 | ||||
| -rw-r--r-- | src/catch2/internal/catch_run_context.cpp | 42 | ||||
| -rw-r--r-- | src/catch2/internal/catch_run_context.hpp | 9 | ||||
| -rw-r--r-- | src/catch2/internal/catch_test_case_tracker.hpp | 4 |
6 files changed, 81 insertions, 18 deletions
diff --git a/src/catch2/generators/catch_generators.cpp b/src/catch2/generators/catch_generators.cpp index 7cc5aa8a..3514e9f6 100644 --- a/src/catch2/generators/catch_generators.cpp +++ b/src/catch2/generators/catch_generators.cpp @@ -27,9 +27,16 @@ namespace Detail { GeneratorUntypedBase::~GeneratorUntypedBase() = default; - auto acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + IGeneratorTracker* acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) { return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo ); } + IGeneratorTracker* createGeneratorTracker( StringRef generatorName, + SourceLineInfo lineInfo, + GeneratorBasePtr&& generator ) { + return getResultCapture().createGeneratorTracker( + generatorName, lineInfo, CATCH_MOVE( generator ) ); + } + } // namespace Generators } // namespace Catch diff --git a/src/catch2/generators/catch_generators.hpp b/src/catch2/generators/catch_generators.hpp index ec8f2795..79a23b12 100644 --- a/src/catch2/generators/catch_generators.hpp +++ b/src/catch2/generators/catch_generators.hpp @@ -204,18 +204,28 @@ namespace Detail { return makeGenerators( value( T( CATCH_FORWARD( val ) ) ), CATCH_FORWARD( moreGenerators )... ); } - auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; + IGeneratorTracker* acquireGeneratorTracker( StringRef generatorName, + SourceLineInfo const& lineInfo ); + IGeneratorTracker* createGeneratorTracker( StringRef generatorName, + SourceLineInfo lineInfo, + GeneratorBasePtr&& generator ); template<typename L> auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> typename decltype(generatorExpression())::type { using UnderlyingType = typename decltype(generatorExpression())::type; - IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo ); - if (!tracker.hasGenerator()) { - tracker.setGenerator(Catch::Detail::make_unique<Generators<UnderlyingType>>(generatorExpression())); + IGeneratorTracker* tracker = acquireGeneratorTracker( generatorName, lineInfo ); + // Creation of tracker is delayed after generator creation, so + // that constructing generator can fail without breaking everything. + if (!tracker) { + tracker = createGeneratorTracker( + generatorName, + lineInfo, + Catch::Detail::make_unique<Generators<UnderlyingType>>( + generatorExpression() ) ); } - auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() ); + auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker->getGenerator() ); return generator.get(); } diff --git a/src/catch2/interfaces/catch_interfaces_capture.hpp b/src/catch2/interfaces/catch_interfaces_capture.hpp index ac25a8c0..0fe27e53 100644 --- a/src/catch2/interfaces/catch_interfaces_capture.hpp +++ b/src/catch2/interfaces/catch_interfaces_capture.hpp @@ -13,6 +13,7 @@ #include <catch2/internal/catch_stringref.hpp> #include <catch2/internal/catch_result_type.hpp> +#include <catch2/internal/catch_unique_ptr.hpp> namespace Catch { @@ -33,6 +34,12 @@ namespace Catch { template <typename Duration = std::chrono::duration<double, std::nano>> struct BenchmarkStats; + namespace Generators { + class GeneratorUntypedBase; + using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>; + } + + class IResultCapture { public: virtual ~IResultCapture(); @@ -42,7 +49,13 @@ namespace Catch { virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; - virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; + virtual IGeneratorTracker* + acquireGeneratorTracker( StringRef generatorName, + SourceLineInfo const& lineInfo ) = 0; + virtual IGeneratorTracker* + createGeneratorTracker( StringRef generatorName, + SourceLineInfo lineInfo, + Generators::GeneratorBasePtr&& generator ) = 0; virtual void benchmarkPreparing( StringRef name ) = 0; virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; diff --git a/src/catch2/internal/catch_run_context.cpp b/src/catch2/internal/catch_run_context.cpp index e1b81d0b..eb8f1359 100644 --- a/src/catch2/internal/catch_run_context.cpp +++ b/src/catch2/internal/catch_run_context.cpp @@ -34,7 +34,7 @@ namespace Catch { {} ~GeneratorTracker() override; - static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) { + static GeneratorTracker* acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) { GeneratorTracker* tracker; ITracker& currentTracker = ctx.currentTracker(); @@ -61,18 +61,14 @@ namespace Catch { assert( childTracker->isGeneratorTracker() ); tracker = static_cast<GeneratorTracker*>( childTracker ); } else { - auto newTracker = - Catch::Detail::make_unique<GeneratorTracker>( - nameAndLocation, ctx, ¤tTracker ); - tracker = newTracker.get(); - currentTracker.addChild( CATCH_MOVE(newTracker) ); + return nullptr; } if( !tracker->isComplete() ) { tracker->open(); } - return *tracker; + return tracker; } // TrackerBase interface @@ -141,6 +137,7 @@ namespace Catch { // has a side-effect, where it consumes generator's current // value, but we do not want to invoke the side-effect if // this generator is still waiting for any child to start. + assert( m_generator && "Tracker without generator" ); if ( should_wait_for_child || ( m_runState == CompletedSuccessfully && m_generator->countedNext() ) ) { @@ -314,14 +311,39 @@ namespace Catch { return true; } - auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + IGeneratorTracker* + RunContext::acquireGeneratorTracker( StringRef generatorName, + SourceLineInfo const& lineInfo ) { using namespace Generators; - GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext, - TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) ); + GeneratorTracker* tracker = GeneratorTracker::acquire( + m_trackerContext, + TestCaseTracking::NameAndLocation( + static_cast<std::string>( generatorName ), lineInfo ) ); m_lastAssertionInfo.lineInfo = lineInfo; return tracker; } + IGeneratorTracker* RunContext::createGeneratorTracker( + StringRef generatorName, + SourceLineInfo lineInfo, + Generators::GeneratorBasePtr&& generator ) { + + auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast<std::string>( generatorName ), lineInfo ); + auto& currentTracker = m_trackerContext.currentTracker(); + assert( + currentTracker.nameAndLocation() != nameAndLoc && + "Trying to create tracker for a genreator that already has one" ); + + auto newTracker = Catch::Detail::make_unique<Generators::GeneratorTracker>( + nameAndLoc, m_trackerContext, ¤tTracker ); + auto ret = newTracker.get(); + currentTracker.addChild( CATCH_MOVE( newTracker ) ); + + ret->setGenerator( CATCH_MOVE( generator ) ); + ret->open(); + return ret; + } + bool RunContext::testForMissingAssertions(Counts& assertions) { if (assertions.total() != 0) return false; diff --git a/src/catch2/internal/catch_run_context.hpp b/src/catch2/internal/catch_run_context.hpp index ab20db57..71c74ee3 100644 --- a/src/catch2/internal/catch_run_context.hpp +++ b/src/catch2/internal/catch_run_context.hpp @@ -73,7 +73,14 @@ namespace Catch { void sectionEnded( SectionEndInfo const& endInfo ) override; void sectionEndedEarly( SectionEndInfo const& endInfo ) override; - auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; + IGeneratorTracker* + acquireGeneratorTracker( StringRef generatorName, + SourceLineInfo const& lineInfo ) override; + IGeneratorTracker* createGeneratorTracker( + StringRef generatorName, + SourceLineInfo lineInfo, + Generators::GeneratorBasePtr&& generator ) override; + void benchmarkPreparing( StringRef name ) override; void benchmarkStarting( BenchmarkInfo const& info ) override; diff --git a/src/catch2/internal/catch_test_case_tracker.hpp b/src/catch2/internal/catch_test_case_tracker.hpp index 005b1d8e..1e31e425 100644 --- a/src/catch2/internal/catch_test_case_tracker.hpp +++ b/src/catch2/internal/catch_test_case_tracker.hpp @@ -27,6 +27,10 @@ namespace TestCaseTracking { return lhs.name == rhs.name && lhs.location == rhs.location; } + friend bool operator!=(NameAndLocation const& lhs, + NameAndLocation const& rhs) { + return !( lhs == rhs ); + } }; class ITracker; |