mirror of
https://github.com/catchorg/Catch2.git
synced 2025-08-03 05:45:39 +02:00
Improved generator tracking
* Successive executions of the same `GENERATE` macro (e.g. because of a for loop) no longer lead to multiple nested generators. * The same line can now contain multiple `GENERATE` macros without issues. Fixes #1913
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <catch2/interfaces/catch_interfaces_generatortracker.hpp>
|
||||
#include <catch2/internal/catch_common.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
@@ -179,16 +180,16 @@ namespace Detail {
|
||||
return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
|
||||
}
|
||||
|
||||
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
|
||||
auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
|
||||
|
||||
template<typename L>
|
||||
// Note: The type after -> is weird, because VS2015 cannot parse
|
||||
// the expression used in the typedef inside, when it is in
|
||||
// return type. Yeah.
|
||||
auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
|
||||
auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
|
||||
using UnderlyingType = typename decltype(generatorExpression())::type;
|
||||
|
||||
IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
|
||||
IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo );
|
||||
if (!tracker.hasGenerator()) {
|
||||
tracker.setGenerator(Catch::Detail::make_unique<Generators<UnderlyingType>>(generatorExpression()));
|
||||
}
|
||||
@@ -201,10 +202,16 @@ namespace Detail {
|
||||
} // namespace Catch
|
||||
|
||||
#define GENERATE( ... ) \
|
||||
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||
Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||
CATCH_INTERNAL_LINEINFO, \
|
||||
[ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||
#define GENERATE_COPY( ... ) \
|
||||
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||
Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||
CATCH_INTERNAL_LINEINFO, \
|
||||
[=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||
#define GENERATE_REF( ... ) \
|
||||
Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||
Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
|
||||
CATCH_INTERNAL_LINEINFO, \
|
||||
[&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
|
||||
|
||||
#endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
|
||||
|
@@ -50,8 +50,8 @@ namespace Detail {
|
||||
|
||||
GeneratorUntypedBase::~GeneratorUntypedBase() = default;
|
||||
|
||||
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
|
||||
return getResultCapture().acquireGeneratorTracker( lineInfo );
|
||||
auto acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
|
||||
return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );
|
||||
}
|
||||
|
||||
} // namespace Generators
|
||||
|
@@ -42,7 +42,7 @@ namespace Catch {
|
||||
virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
|
||||
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
|
||||
|
||||
virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
|
||||
virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
|
||||
|
||||
virtual void benchmarkPreparing( std::string const& name ) = 0;
|
||||
virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
|
||||
|
@@ -27,12 +27,27 @@ namespace Catch {
|
||||
std::shared_ptr<GeneratorTracker> tracker;
|
||||
|
||||
ITracker& currentTracker = ctx.currentTracker();
|
||||
if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
||||
// Under specific circumstances, the generator we want
|
||||
// to acquire is also the current tracker. If this is
|
||||
// the case, we have to avoid looking through current
|
||||
// tracker's children, and instead return the current
|
||||
// tracker.
|
||||
// A case where this check is important is e.g.
|
||||
// for (int i = 0; i < 5; ++i) {
|
||||
// int n = GENERATE(1, 2);
|
||||
// }
|
||||
//
|
||||
// without it, the code above creates 5 nested generators.
|
||||
if (currentTracker.nameAndLocation() == nameAndLocation) {
|
||||
auto thisTracker = currentTracker.parent().findChild(nameAndLocation);
|
||||
assert(thisTracker);
|
||||
assert(thisTracker->isGeneratorTracker());
|
||||
tracker = std::static_pointer_cast<GeneratorTracker>(thisTracker);
|
||||
} else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
|
||||
assert( childTracker );
|
||||
assert( childTracker->isGeneratorTracker() );
|
||||
tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, ¤tTracker );
|
||||
currentTracker.addChild( tracker );
|
||||
}
|
||||
@@ -181,9 +196,10 @@ namespace Catch {
|
||||
|
||||
return true;
|
||||
}
|
||||
auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
|
||||
auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
|
||||
using namespace Generators;
|
||||
GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) );
|
||||
GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext,
|
||||
TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) );
|
||||
assert( tracker.isOpen() );
|
||||
m_lastAssertionInfo.lineInfo = lineInfo;
|
||||
return tracker;
|
||||
|
@@ -76,7 +76,7 @@ namespace Catch {
|
||||
void sectionEnded( SectionEndInfo const& endInfo ) override;
|
||||
void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
|
||||
|
||||
auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
|
||||
auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
|
||||
|
||||
void benchmarkPreparing( std::string const& name ) override;
|
||||
void benchmarkStarting( BenchmarkInfo const& info ) override;
|
||||
|
@@ -23,6 +23,10 @@ namespace TestCaseTracking {
|
||||
SourceLineInfo location;
|
||||
|
||||
NameAndLocation( std::string const& _name, SourceLineInfo const& _location );
|
||||
friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {
|
||||
return lhs.name == rhs.name
|
||||
&& lhs.location == rhs.location;
|
||||
}
|
||||
};
|
||||
|
||||
struct ITracker;
|
||||
|
Reference in New Issue
Block a user