diff --git a/docs/release_notes.adoc b/docs/release_notes.adoc index 2b046d7192..fee00b3f1d 100644 --- a/docs/release_notes.adoc +++ b/docs/release_notes.adoc @@ -24,6 +24,7 @@ include::include.adoc[] * Fix mocking issue with the ByteBuddy MockMaker when using multiple classloaders in Java 21 spockIssue:2017[] * Fix mocking of final classes via `@SpringBean` and `@SpringSpy` spockIssue:1960[] * Size of data providers is no longer calculated multiple times but only once +* Fix exception when using `@RepeatUntilFailure` with a data provider with unknown iteration amount. spockPull:2031[] == 2.4-M4 (2024-03-21) diff --git a/spock-core/src/main/java/org/spockframework/runtime/extension/builtin/RepeatUntilFailureExtension.java b/spock-core/src/main/java/org/spockframework/runtime/extension/builtin/RepeatUntilFailureExtension.java index 52af45d0fc..27e6171e72 100644 --- a/spock-core/src/main/java/org/spockframework/runtime/extension/builtin/RepeatUntilFailureExtension.java +++ b/spock-core/src/main/java/org/spockframework/runtime/extension/builtin/RepeatUntilFailureExtension.java @@ -1,5 +1,6 @@ package org.spockframework.runtime.extension.builtin; +import org.spockframework.runtime.DataIteratorFactory; import org.spockframework.runtime.IDataIterator; import org.spockframework.runtime.extension.*; import org.spockframework.runtime.model.*; @@ -8,6 +9,8 @@ import java.util.*; import java.util.concurrent.ExecutionException; +import static org.spockframework.runtime.DataIteratorFactory.UNKNOWN_ITERATIONS; + public class RepeatUntilFailureExtension implements IAnnotationDrivenExtension { @Override public void visitFeatureAnnotation(RepeatUntilFailure annotation, FeatureInfo feature) { @@ -32,8 +35,8 @@ public RepeatUntilFailureDataDriver(int maxAttempts) { @Override public void runIterations(IDataIterator dataIterator, IIterationRunner iterationRunner, List parameters) { int estimatedNumIterations = dataIterator.getEstimatedNumIterations(); - int maxIterations = estimatedNumIterations * maxAttempts; - List arguments = new ArrayList<>(estimatedNumIterations); + int maxIterations = estimatedNumIterations == UNKNOWN_ITERATIONS ? UNKNOWN_ITERATIONS : (estimatedNumIterations * maxAttempts); + List arguments = estimatedNumIterations == UNKNOWN_ITERATIONS ? new ArrayList<>() : new ArrayList<>(estimatedNumIterations); dataIterator.forEachRemaining(arguments::add); for (int attempt = 0; attempt < maxAttempts; attempt++) { for (Object[] args : arguments) { diff --git a/spock-specs/src/test/groovy/org/spockframework/smoke/extension/RepeatUntilFailureExtensionSpec.groovy b/spock-specs/src/test/groovy/org/spockframework/smoke/extension/RepeatUntilFailureExtensionSpec.groovy index 9b4fa7c045..ff1508aaa1 100644 --- a/spock-specs/src/test/groovy/org/spockframework/smoke/extension/RepeatUntilFailureExtensionSpec.groovy +++ b/spock-specs/src/test/groovy/org/spockframework/smoke/extension/RepeatUntilFailureExtensionSpec.groovy @@ -74,6 +74,30 @@ class RepeatUntilFailureExtensionSpec extends EmbeddedSpecification { result.testsSkippedCount == 2 } + def "repeats with unknown iteration count"() { + given: + runner.throwFailure = false + + when: + def result = runner.runSpecBody """ + @Shared + int count = 0 + + @RepeatUntilFailure + def "test"() { + expect: + ++count < 3 + + where: + x << [1].iterator() + } + """ + + then: + result.testsStartedCount == 1 + 3 + result.testsSucceededCount == 1 + 2 + result.testsFailedCount == 1 + } def "ignores aborted tests"() { when: