Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorMartin Hořeňovský2023-01-17 11:04:49 +0100
committerMartin Hořeňovský2023-01-22 16:04:16 +0100
commit8359a6b244a26cffabd4440b17fac8b1392815af (patch)
treeeb0a396ddc582cb7f1b5e5f7d0b3b369d18ebc40 /src
parentadf43494e19077d492343ea13d597af5133b7288 (diff)
downloadcatch3-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.cpp9
-rw-r--r--src/catch2/generators/catch_generators.hpp20
-rw-r--r--src/catch2/interfaces/catch_interfaces_capture.hpp15
-rw-r--r--src/catch2/internal/catch_run_context.cpp42
-rw-r--r--src/catch2/internal/catch_run_context.hpp9
-rw-r--r--src/catch2/internal/catch_test_case_tracker.hpp4
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, &currentTracker );
- 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, &currentTracker );
+ 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;