diff --git a/include/internal/catch_generators.cpp b/include/internal/catch_generators.cpp index 5fbe2d23..c6d60a70 100644 --- a/include/internal/catch_generators.cpp +++ b/include/internal/catch_generators.cpp @@ -24,8 +24,8 @@ namespace Generators { GeneratorUntypedBase::~GeneratorUntypedBase() {} - 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 diff --git a/include/internal/catch_generators.hpp b/include/internal/catch_generators.hpp index d0fbe8bf..e253ea09 100644 --- a/include/internal/catch_generators.hpp +++ b/include/internal/catch_generators.hpp @@ -10,6 +10,7 @@ #include "catch_interfaces_generatortracker.h" #include "catch_common.h" #include "catch_enforce.h" +#include "catch_stringref.h" #include #include @@ -181,16 +182,16 @@ namespace Generators { return makeGenerators( value( T( std::forward( val ) ) ), std::forward( moreGenerators )... ); } - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; template // 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().get()) { + auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval().get()) { using UnderlyingType = typename decltype(generatorExpression())::type; - IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); + IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo ); if (!tracker.hasGenerator()) { tracker.setGenerator(pf::make_unique>(generatorExpression())); } @@ -203,10 +204,16 @@ namespace Generators { } // 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 diff --git a/include/internal/catch_interfaces_capture.h b/include/internal/catch_interfaces_capture.h index 8c25c8cf..ccca73de 100644 --- a/include/internal/catch_interfaces_capture.h +++ b/include/internal/catch_interfaces_capture.h @@ -44,7 +44,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; #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) virtual void benchmarkPreparing( std::string const& name ) = 0; diff --git a/include/internal/catch_run_context.cpp b/include/internal/catch_run_context.cpp index 2eb84fb9..e4d6c9d4 100644 --- a/include/internal/catch_run_context.cpp +++ b/include/internal/catch_run_context.cpp @@ -25,12 +25,27 @@ namespace Catch { std::shared_ptr 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(thisTracker); + } else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { assert( childTracker ); assert( childTracker->isGeneratorTracker() ); tracker = std::static_pointer_cast( childTracker ); - } - else { + } else { tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker ); currentTracker.addChild( tracker ); } @@ -187,9 +202,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(generatorName), lineInfo ) ); assert( tracker.isOpen() ); m_lastAssertionInfo.lineInfo = lineInfo; return tracker; diff --git a/include/internal/catch_run_context.h b/include/internal/catch_run_context.h index 2a8e72dc..044bdd81 100644 --- a/include/internal/catch_run_context.h +++ b/include/internal/catch_run_context.h @@ -80,7 +80,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; #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) void benchmarkPreparing( std::string const& name ) override; diff --git a/include/internal/catch_test_case_tracker.h b/include/internal/catch_test_case_tracker.h index 563dbef2..a60c0ae4 100644 --- a/include/internal/catch_test_case_tracker.h +++ b/include/internal/catch_test_case_tracker.h @@ -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; diff --git a/projects/SelfTest/Baselines/compact.sw.approved.txt b/projects/SelfTest/Baselines/compact.sw.approved.txt index 3ac244ee..ef077b7b 100644 --- a/projects/SelfTest/Baselines/compact.sw.approved.txt +++ b/projects/SelfTest/Baselines/compact.sw.approved.txt @@ -30,6 +30,12 @@ CmdLine.tests.cpp:: passed: spec.matches(fakeTestCase(R"(spec {a} c CmdLine.tests.cpp:: passed: spec.matches(fakeTestCase(R"(spec [a] char)")) for: true CmdLine.tests.cpp:: passed: !(spec.matches(fakeTestCase("differs but has similar tag", "[a]"))) for: !false CmdLine.tests.cpp:: passed: spec.matches(fakeTestCase(R"(spec \ char)")) for: true +Generators.tests.cpp:: passed: counter < 7 for: 3 < 7 +Generators.tests.cpp:: passed: counter < 7 for: 6 < 7 +Generators.tests.cpp:: passed: i != j for: 1 != 3 +Generators.tests.cpp:: passed: i != j for: 1 != 4 +Generators.tests.cpp:: passed: i != j for: 2 != 3 +Generators.tests.cpp:: passed: i != j for: 2 != 4 Exception.tests.cpp:: failed: unexpected exception with message: 'answer := 42' with 1 message: 'expected exception' Exception.tests.cpp:: failed: unexpected exception with message: 'answer := 42'; expression was: thisThrows() with 1 message: 'expected exception' Exception.tests.cpp:: passed: thisThrows() with 1 message: 'answer := 42' diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index 1cb3970e..0ab74f6a 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -1380,6 +1380,6 @@ due to unexpected exception with message: Why would you throw a std::string? =============================================================================== -test cases: 310 | 236 passed | 70 failed | 4 failed as expected -assertions: 1701 | 1549 passed | 131 failed | 21 failed as expected +test cases: 312 | 238 passed | 70 failed | 4 failed as expected +assertions: 1707 | 1555 passed | 131 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index 9ac146f9..c69ab0d0 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -243,6 +243,72 @@ CmdLine.tests.cpp:: PASSED: with expansion: true +------------------------------------------------------------------------------- +#1913 - GENERATE inside a for loop should not keep recreating the generator +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( counter < 7 ) +with expansion: + 3 < 7 + +------------------------------------------------------------------------------- +#1913 - GENERATE inside a for loop should not keep recreating the generator +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( counter < 7 ) +with expansion: + 6 < 7 + +------------------------------------------------------------------------------- +#1913 - GENERATEs can share a line +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i != j ) +with expansion: + 1 != 3 + +------------------------------------------------------------------------------- +#1913 - GENERATEs can share a line +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i != j ) +with expansion: + 1 != 4 + +------------------------------------------------------------------------------- +#1913 - GENERATEs can share a line +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i != j ) +with expansion: + 2 != 3 + +------------------------------------------------------------------------------- +#1913 - GENERATEs can share a line +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i != j ) +with expansion: + 2 != 4 + ------------------------------------------------------------------------------- #748 - captures with unexpected exceptions outside assertions @@ -13573,6 +13639,6 @@ Misc.tests.cpp: Misc.tests.cpp:: PASSED: =============================================================================== -test cases: 310 | 220 passed | 86 failed | 4 failed as expected -assertions: 1718 | 1549 passed | 148 failed | 21 failed as expected +test cases: 312 | 222 passed | 86 failed | 4 failed as expected +assertions: 1724 | 1555 passed | 148 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/console.swa4.approved.txt b/projects/SelfTest/Baselines/console.swa4.approved.txt index 4a5b4864..430c7705 100644 --- a/projects/SelfTest/Baselines/console.swa4.approved.txt +++ b/projects/SelfTest/Baselines/console.swa4.approved.txt @@ -243,6 +243,72 @@ CmdLine.tests.cpp:: PASSED: with expansion: true +------------------------------------------------------------------------------- +#1913 - GENERATE inside a for loop should not keep recreating the generator +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( counter < 7 ) +with expansion: + 3 < 7 + +------------------------------------------------------------------------------- +#1913 - GENERATE inside a for loop should not keep recreating the generator +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( counter < 7 ) +with expansion: + 6 < 7 + +------------------------------------------------------------------------------- +#1913 - GENERATEs can share a line +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i != j ) +with expansion: + 1 != 3 + +------------------------------------------------------------------------------- +#1913 - GENERATEs can share a line +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i != j ) +with expansion: + 1 != 4 + +------------------------------------------------------------------------------- +#1913 - GENERATEs can share a line +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i != j ) +with expansion: + 2 != 3 + +------------------------------------------------------------------------------- +#1913 - GENERATEs can share a line +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( i != j ) +with expansion: + 2 != 4 + ------------------------------------------------------------------------------- #748 - captures with unexpected exceptions outside assertions @@ -423,6 +489,6 @@ Condition.tests.cpp:: FAILED: CHECK( true != true ) =============================================================================== -test cases: 21 | 16 passed | 3 failed | 2 failed as expected -assertions: 49 | 42 passed | 4 failed | 3 failed as expected +test cases: 23 | 18 passed | 3 failed | 2 failed as expected +assertions: 55 | 48 passed | 4 failed | 3 failed as expected diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index 57237c15..47fd7546 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,7 +1,7 @@ - + @@ -33,6 +33,8 @@ Nor would this + + FAILED: diff --git a/projects/SelfTest/Baselines/sonarqube.sw.approved.txt b/projects/SelfTest/Baselines/sonarqube.sw.approved.txt index 663f6fb9..24fc52d8 100644 --- a/projects/SelfTest/Baselines/sonarqube.sw.approved.txt +++ b/projects/SelfTest/Baselines/sonarqube.sw.approved.txt @@ -875,6 +875,8 @@ Exception.tests.cpp: + + diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index ddbdb595..e6ad3c11 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -264,6 +264,60 @@ Nor would this + + + + counter < 7 + + + 3 < 7 + + + + + counter < 7 + + + 6 < 7 + + + + + + + + i != j + + + 1 != 3 + + + + + i != j + + + 1 != 4 + + + + + i != j + + + 2 != 3 + + + + + i != j + + + 2 != 4 + + + +
@@ -16255,7 +16309,7 @@ loose text artifact
- + - + diff --git a/projects/SelfTest/UsageTests/Generators.tests.cpp b/projects/SelfTest/UsageTests/Generators.tests.cpp index 0e39bd5c..7ed3e5b3 100644 --- a/projects/SelfTest/UsageTests/Generators.tests.cpp +++ b/projects/SelfTest/UsageTests/Generators.tests.cpp @@ -251,6 +251,22 @@ TEST_CASE("Copy and then generate a range", "[generators]") { } } +TEST_CASE("#1913 - GENERATE inside a for loop should not keep recreating the generator", "[regression][generators]") { + static int counter = 0; + for (int i = 0; i < 3; ++i) { + int _ = GENERATE(1, 2); + (void)_; + ++counter; + } + // There should be at most 6 (3 * 2) counter increments + REQUIRE(counter < 7); +} + +TEST_CASE("#1913 - GENERATEs can share a line", "[regression][generators]") { + int i = GENERATE(1, 2); int j = GENERATE(3, 4); + REQUIRE(i != j); +} + #if defined(__clang__) #pragma clang diagnostic pop #endif