Description
Steps to reproduce
- Create a subclass of
AnnotationBasedArgumentsProvider
that implementsprovideArguments(ExtensionContext context, CsvSource annotation)
- Use that provider as an argument to
@ArgumentsSource
on a@ParameterizedTest
method.
An example follows:
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(TestDefinition.List.class)
public @interface TestDefinition {
String foo() default "";
String bar() default "";
@Retention(RetentionPolicy.RUNTIME)
@interface List { TestDefinition[] value() default {}; }
class Provider extends AnnotationBasedArgumentsProvider<TestDefinition.List> {
@Override
protected Stream<? extends Arguments> provideArguments(ExtensionContext ctx, TestDefinition.List ann) {
return Arrays.stream(ann.value()).map(Arguments::arguments);
}
}
}
@ParameterizedTest
@ArgumentsSource(TestDefinition.Provider.class)
@TestDefinition(foo = "a", bar = "b")
@TestDefinition(foo = "c", bar = "d")
@TestDefinition(foo = "e", bar = "f")
void testImplementation(TestDefinition definition) {
...
}
The following is an easier means of reproducing; simply update the test harness in AnnotationConsumerInitializerTests
to implement the deprecated method, instead of the new one:
diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/params/support/AnnotationConsumerInitializerTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/params/support/AnnotationConsumerInitializerTests.java
index 4d4ea67ecf..99aa940ec7 100644
--- a/jupiter-tests/src/test/java/org/junit/jupiter/params/support/AnnotationConsumerInitializerTests.java
+++ b/jupiter-tests/src/test/java/org/junit/jupiter/params/support/AnnotationConsumerInitializerTests.java
@@ -117,8 +117,8 @@ class AnnotationConsumerInitializerTests {
List<CsvSource> annotations = new ArrayList<>();
@Override
- protected Stream<? extends Arguments> provideArguments(ParameterDeclarations parameters,
- ExtensionContext context, CsvSource annotation) {
+ @SuppressWarnings("deprecation")
+ protected Stream<? extends Arguments> provideArguments(ExtensionContext context, CsvSource annotation) {
annotations.add(annotation);
return Stream.empty();
}
Upon running the tests in that suite, you will receive the following error:
Index 0 out of bounds for length 0
java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
at java.base@21.0.4/java.util.ImmutableCollections$ListN.get(ImmutableCollections.java:687)
at app//org.junit.jupiter.params.support.AnnotationConsumerInitializer.findConsumedAnnotationType(AnnotationConsumerInitializer.java:78)
at app//org.junit.jupiter.params.support.AnnotationConsumerInitializer.initialize(AnnotationConsumerInitializer.java:53)
at app//org.junit.jupiter.params.support.AnnotationConsumerInitializerTests.shouldInitializeForEachAnnotations(AnnotationConsumerInitializerTests.java:110)
at java.base@21.0.4/java.lang.reflect.Method.invoke(Method.java:580)
at java.base@21.0.4/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base@21.0.4/java.util.ArrayList.forEach(ArrayList.java:1596)
Context
- Used versions (Jupiter/Vintage/Platform):
- junit-bom 5.13.0
- junit-jupiter-api
- junit-vintage-engine
- junit-platform-launcher
- Build Tool/IDE:
- Gradle 8.14.1
Proposed Solution
I believe that the issue stems from AnnotationConsumerInitializer#annotationConsumingMethodSignatures
having been updated to only look for the new, non-deprecated method. Since the deprecated method is still present in production code, I think its signature should be present in that list:
diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/AnnotationConsumerInitializer.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/AnnotationConsumerInitializer.java
index b6bdfd90f2..d80bbc0de7 100644
--- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/AnnotationConsumerInitializer.java
+++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/support/AnnotationConsumerInitializer.java
@@ -40,6 +40,7 @@ public final class AnnotationConsumerInitializer {
private static final List<AnnotationConsumingMethodSignature> annotationConsumingMethodSignatures = asList( //
new AnnotationConsumingMethodSignature("accept", 1, 0), //
+ new AnnotationConsumingMethodSignature("provideArguments", 2, 1), //
new AnnotationConsumingMethodSignature("provideArguments", 3, 2), //
new AnnotationConsumingMethodSignature("convert", 3, 2));
In my limited testing, this resolved the issue I am seeing and kept compatibility with the behaviour in 5.13.0, but I'm not aware of the full scope of this change.