mirror of
https://github.com/catchorg/Catch2.git
synced 2026-07-21 13:53:35 +00:00
Fix --warn InfiniteGenerators firing even if the generator was filtered
This commit is contained in:
@@ -179,8 +179,7 @@ namespace Generators {
|
|||||||
|
|
||||||
bool isFinite() const override {
|
bool isFinite() const override {
|
||||||
for (auto const& gen : m_generators) {
|
for (auto const& gen : m_generators) {
|
||||||
if (!gen.isFinite()) { return false;
|
if (!gen.isFinite()) { return false; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -196,6 +196,8 @@ namespace Catch {
|
|||||||
auto getGenerator() const -> GeneratorBasePtr const& override {
|
auto getGenerator() const -> GeneratorBasePtr const& override {
|
||||||
return m_generator;
|
return m_generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isFilteredImpl() const override { return m_isFiltered; }
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
}
|
}
|
||||||
@@ -540,17 +542,6 @@ namespace Catch {
|
|||||||
SourceLineInfo lineInfo,
|
SourceLineInfo lineInfo,
|
||||||
Generators::GeneratorBasePtr&& generator ) {
|
Generators::GeneratorBasePtr&& generator ) {
|
||||||
|
|
||||||
// TBD: Do we want to avoid the warning if the generator is filtered?
|
|
||||||
if ( m_config->warnAboutInfiniteGenerators() &&
|
|
||||||
!generator->isFinite() ) {
|
|
||||||
// We want the semantics of `FAIL()`, but we inline it
|
|
||||||
// to avoid issues with conditionally prefixed macros
|
|
||||||
INTERNAL_CATCH_MSG( "FAIL",
|
|
||||||
Catch::ResultWas::ExplicitFailure,
|
|
||||||
Catch::ResultDisposition::Normal,
|
|
||||||
"GENERATE() would run infinitely" );
|
|
||||||
}
|
|
||||||
|
|
||||||
auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast<std::string>( generatorName ), lineInfo );
|
auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast<std::string>( generatorName ), lineInfo );
|
||||||
auto& currentTracker = m_trackerContext.currentTracker();
|
auto& currentTracker = m_trackerContext.currentTracker();
|
||||||
assert(
|
assert(
|
||||||
@@ -563,11 +554,24 @@ namespace Catch {
|
|||||||
m_trackerContext,
|
m_trackerContext,
|
||||||
¤tTracker,
|
¤tTracker,
|
||||||
CATCH_MOVE( generator ) );
|
CATCH_MOVE( generator ) );
|
||||||
auto ret = newTracker.get();
|
|
||||||
|
// The warning shouldn't fire if the generator is infinite, **but** filtered down.
|
||||||
|
if ( m_config->warnAboutInfiniteGenerators() &&
|
||||||
|
!newTracker->m_generator->isFinite() &&
|
||||||
|
!newTracker->isFiltered() ) {
|
||||||
|
// We want the semantics of `FAIL()`, but we inline it
|
||||||
|
// to avoid issues with conditionally prefixed macros
|
||||||
|
INTERNAL_CATCH_MSG( "FAIL",
|
||||||
|
Catch::ResultWas::ExplicitFailure,
|
||||||
|
Catch::ResultDisposition::Normal,
|
||||||
|
"GENERATE() would run infinitely" );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto returnPtr = newTracker.get();
|
||||||
currentTracker.addChild( CATCH_MOVE( newTracker ) );
|
currentTracker.addChild( CATCH_MOVE( newTracker ) );
|
||||||
|
|
||||||
ret->open();
|
returnPtr->open();
|
||||||
return ret;
|
return returnPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RunContext::testForMissingAssertions(Counts& assertions) {
|
bool RunContext::testForMissingAssertions(Counts& assertions) {
|
||||||
|
|||||||
@@ -167,6 +167,28 @@ namespace TestCaseTracking {
|
|||||||
m_ctx.setCurrentTracker( this );
|
m_ctx.setCurrentTracker( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SectionTracker::isFilteredImpl() const {
|
||||||
|
// TBD: This is currently _very_ similar to the block in `isComplete`.
|
||||||
|
// Is this neccessarily that way, or just accident of current semantics?
|
||||||
|
const size_t filterIndex =
|
||||||
|
m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth;
|
||||||
|
|
||||||
|
if ( filterIndex < m_filterRef->size() ) {
|
||||||
|
// 1) New style filter must explicitly target section
|
||||||
|
if ( m_newStyleFilters && ( *m_filterRef )[filterIndex].type !=
|
||||||
|
PathFilter::For::Section ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 2) Both style filters must match the trimmed name exactly
|
||||||
|
if ( m_trimmed_name !=
|
||||||
|
StringRef( ( *m_filterRef )[filterIndex].filter ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
|
||||||
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
|
: TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
|
||||||
m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
|
m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <catch2/internal/catch_source_line_info.hpp>
|
#include <catch2/internal/catch_source_line_info.hpp>
|
||||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||||
#include <catch2/internal/catch_stringref.hpp>
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
#include <catch2/internal/catch_path_filter.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -81,6 +82,8 @@ namespace TestCaseTracking {
|
|||||||
|
|
||||||
using Children = std::vector<ITrackerPtr>;
|
using Children = std::vector<ITrackerPtr>;
|
||||||
|
|
||||||
|
virtual bool isFilteredImpl() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum CycleState {
|
enum CycleState {
|
||||||
NotStarted,
|
NotStarted,
|
||||||
@@ -178,6 +181,20 @@ namespace TestCaseTracking {
|
|||||||
* for internal debug checks.
|
* for internal debug checks.
|
||||||
*/
|
*/
|
||||||
virtual bool isGeneratorTracker() const;
|
virtual bool isGeneratorTracker() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the concrete tracker instance has a filter that applies to it.
|
||||||
|
*/
|
||||||
|
bool isFiltered() const {
|
||||||
|
// Fast path: are there even filters for tracker in this position?
|
||||||
|
const size_t filter_depth =
|
||||||
|
m_newStyleFilters ? m_allTrackerDepth : m_sectionOnlyDepth;
|
||||||
|
if ( m_filterRef->size() <= filter_depth ) { return false; }
|
||||||
|
|
||||||
|
// Slow path: If there are filters, ask the concrete tracker.
|
||||||
|
// This handles things like match-all filters for that tracker.
|
||||||
|
return isFilteredImpl();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class TrackerContext {
|
class TrackerContext {
|
||||||
@@ -233,6 +250,8 @@ namespace TestCaseTracking {
|
|||||||
// to not own the name, the name still has to outlive the `ITracker` parent, so
|
// to not own the name, the name still has to outlive the `ITracker` parent, so
|
||||||
// this should still be safe.
|
// this should still be safe.
|
||||||
StringRef m_trimmed_name;
|
StringRef m_trimmed_name;
|
||||||
|
|
||||||
|
bool isFilteredImpl() const override;
|
||||||
public:
|
public:
|
||||||
SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
|
SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
|
||||||
|
|
||||||
|
|||||||
@@ -583,16 +583,56 @@ add_executable(InfiniteGenerators ${TESTS_DIR}/X95-InfiniteGenerators.cpp)
|
|||||||
target_link_libraries(InfiniteGenerators PRIVATE Catch2::Catch2WithMain)
|
target_link_libraries(InfiniteGenerators PRIVATE Catch2::Catch2WithMain)
|
||||||
|
|
||||||
add_test(
|
add_test(
|
||||||
NAME Warnings::InfiniteGenerators
|
NAME Warnings::InfiniteGenerators::NoFilterWarns
|
||||||
COMMAND $<TARGET_FILE:InfiniteGenerators> --warn InfiniteGenerators
|
COMMAND $<TARGET_FILE:InfiniteGenerators> --warn InfiniteGenerators
|
||||||
)
|
)
|
||||||
set_tests_properties(Warnings::InfiniteGenerators
|
set_tests_properties(Warnings::InfiniteGenerators::NoFilterWarns
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
# One test case fails with infinite generator, but the other one runs
|
# One test case fails with infinite generator, but the other one runs
|
||||||
PASS_REGULAR_EXPRESSION "test cases: 2 \\| 1 passed \\| 1 failed"
|
PASS_REGULAR_EXPRESSION "test cases: 2 \\| 1 passed \\| 1 failed"
|
||||||
TIMEOUT 5
|
TIMEOUT 5
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_test(
|
||||||
|
NAME Warnings::InfiniteGenerators::MatchAllFilterWarns
|
||||||
|
COMMAND $<TARGET_FILE:InfiniteGenerators>
|
||||||
|
--warn InfiniteGenerators
|
||||||
|
--path-filter g:*
|
||||||
|
)
|
||||||
|
set_tests_properties(Warnings::InfiniteGenerators::MatchAllFilterWarns
|
||||||
|
PROPERTIES
|
||||||
|
# One test case fails with infinite generator, but the other one runs
|
||||||
|
PASS_REGULAR_EXPRESSION "test cases: 2 \\| 1 passed \\| 1 failed"
|
||||||
|
TIMEOUT 5
|
||||||
|
)
|
||||||
|
|
||||||
|
add_test(
|
||||||
|
NAME Warnings::InfiniteGenerators::MatchOneFilterDoesntWarn
|
||||||
|
COMMAND $<TARGET_FILE:InfiniteGenerators>
|
||||||
|
--warn InfiniteGenerators
|
||||||
|
--path-filter g:1
|
||||||
|
)
|
||||||
|
set_tests_properties(Warnings::InfiniteGenerators::MatchOneFilterDoesntWarn
|
||||||
|
PROPERTIES
|
||||||
|
# One test case fails with infinite generator, but the other one runs
|
||||||
|
PASS_REGULAR_EXPRESSION "All tests passed \\(1 assertion in 2 test cases\\)"
|
||||||
|
TIMEOUT 5
|
||||||
|
)
|
||||||
|
|
||||||
|
add_test(
|
||||||
|
NAME Warnings::InfiniteGenerators::SectionFilterWarns
|
||||||
|
COMMAND $<TARGET_FILE:InfiniteGenerators>
|
||||||
|
--warn InfiniteGenerators
|
||||||
|
--section FooBarBaz
|
||||||
|
)
|
||||||
|
set_tests_properties(Warnings::InfiniteGenerators::SectionFilterWarns
|
||||||
|
PROPERTIES
|
||||||
|
# One test case fails with infinite generator, but the other one runs
|
||||||
|
PASS_REGULAR_EXPRESSION "test cases: 2 \\| 1 passed \\| 1 failed"
|
||||||
|
TIMEOUT 5
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
set(EXTRA_TEST_BINARIES
|
set(EXTRA_TEST_BINARIES
|
||||||
AllSkipped
|
AllSkipped
|
||||||
PrefixedMacros
|
PrefixedMacros
|
||||||
|
|||||||
Reference in New Issue
Block a user