Skip to content

Commit 9bd6d4e

Browse files
committed
Added LifecycleContext.findRepeatableAnnotations()
1 parent 163d7d6 commit 9bd6d4e

File tree

5 files changed

+96
-1
lines changed

5 files changed

+96
-1
lines changed

api/src/main/java/net/jqwik/api/lifecycle/LifecycleContext.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@ public interface LifecycleContext {
7979
*/
8080
<T extends Annotation> List<T> findAnnotationsInContainer(Class<T> annotationClass);
8181

82+
/**
83+
* Retrieve a list of repeatable annotations if present at the current test element.
84+
*
85+
* @param annotationClass The annotation type
86+
* @param <T> The annotation type
87+
* @return list of annotation objects
88+
*/
89+
@API(status = MAINTAINED, since = "1.7.4")
90+
<T extends Annotation> List<T> findRepeatableAnnotations(Class<T> annotationClass);
91+
8292
/**
8393
* Create a new instance of a {@code clazz} in the context of the property in which it
8494
* is running. Use this method, for example, when trying to instantiate a class

engine/src/main/java/net/jqwik/engine/execution/AbstractLifecycleContext.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ public <A extends Annotation> List<A> findAnnotationsInContainer(Class<A> annota
5656
.orElse(Collections.emptyList());
5757
}
5858

59+
@Override
60+
public <T extends Annotation> List<T> findRepeatableAnnotations(Class<T> annotationClass) {
61+
return AnnotationSupport.findRepeatableAnnotations(optionalElement(), annotationClass);
62+
}
63+
5964
private Optional<ContainerClassDescriptor> parentContainer() {
6065
return parentContainer(descriptor);
6166
}

engine/src/main/java/net/jqwik/engine/execution/DefaultTryLifecycleContext.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ public <T extends Annotation> List<T> findAnnotationsInContainer(Class<T> annota
7777
return propertyContext.findAnnotationsInContainer(annotationClass);
7878
}
7979

80+
@Override
81+
public <T extends Annotation> List<T> findRepeatableAnnotations(Class<T> annotationClass) {
82+
return propertyContext.findRepeatableAnnotations(annotationClass);
83+
}
84+
8085
@Override
8186
public String toString() {
8287
return String.format("TryLifecycleContext:%s", propertyContext);

engine/src/test/java/net/jqwik/engine/TestHelper.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,11 @@ public <T extends Annotation> List<T> findAnnotationsInContainer(Class<T> annota
218218
return Collections.emptyList();
219219
}
220220

221+
@Override
222+
public <T extends Annotation> List<T> findRepeatableAnnotations(Class<T> annotationClass) {
223+
return Collections.emptyList();
224+
}
225+
221226
@Override
222227
public <T> T newInstance(Class<T> clazz) {
223228
return null;

engine/src/test/java/net/jqwik/engine/execution/lifecycle/LifecycleContextAnnotationsTests.java

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package net.jqwik.engine.execution.lifecycle;
22

33
import java.lang.annotation.*;
4+
import java.util.*;
45

6+
import org.junit.platform.engine.*;
57
import org.mockito.*;
68

79
import net.jqwik.api.*;
@@ -13,11 +15,27 @@
1315
import static org.assertj.core.api.Assertions.*;
1416

1517
@MyAnnotation
18+
@MyRepeatableAnnotation("one")
19+
@MyRepeatableAnnotation("two")
1620
class LifecycleContextAnnotationsTests {
1721

1822
private final Reporter reporter = Mockito.mock(Reporter.class);
1923
private final ResolveParameterHook resolveParameter = Mockito.mock(ResolveParameterHook.class);
2024

25+
@Example
26+
void engineLifecycleContext() {
27+
28+
TestDescriptor engineDescriptor = TestDescriptorBuilder.forEngine(new JqwikTestEngine()).build();
29+
EngineLifecycleContext lifecycleContext = new EngineLifecycleContext(
30+
engineDescriptor,
31+
reporter,
32+
resolveParameter
33+
);
34+
assertThat(lifecycleContext.findAnnotation(MyAnnotation.class)).isEmpty();
35+
assertThat(lifecycleContext.findAnnotationsInContainer(MyAnnotation.class)).isEmpty();
36+
assertThat(lifecycleContext.findRepeatableAnnotations(MyRepeatableAnnotation.class)).isEmpty();
37+
}
38+
2139
@Example
2240
void containerLifecycleDescriptor() {
2341

@@ -31,7 +49,11 @@ void containerLifecycleDescriptor() {
3149

3250
assertThat(lifecycleContext.findAnnotation(MyAnnotation.class)).isPresent();
3351
assertThat(lifecycleContext.findAnnotationsInContainer(MyAnnotation.class)).isEmpty();
34-
assertThat(lifecycleContext.findAnnotation(Property.class)).isNotPresent();
52+
53+
List<MyRepeatableAnnotation> repeatableAnnotations = lifecycleContext.findRepeatableAnnotations(MyRepeatableAnnotation.class);
54+
assertThat(repeatableAnnotations).isNotEmpty();
55+
assertThat(repeatableAnnotations.stream().map(MyRepeatableAnnotation::value))
56+
.contains("one", "two");
3557
}
3658

3759
@Example
@@ -52,6 +74,8 @@ void nestedContainerLifecycleDescriptor() {
5274
.hasSize(1);
5375
}
5476

77+
@MyRepeatableAnnotation("three")
78+
@MyRepeatableAnnotation("four")
5579
@Example
5680
void propertyLifecycleDescriptor() {
5781

@@ -69,6 +93,39 @@ void propertyLifecycleDescriptor() {
6993
assertThat(lifecycleContext.findAnnotationsInContainer(MyAnnotation.class))
7094
.hasSize(1);
7195

96+
List<MyRepeatableAnnotation> repeatableAnnotations = lifecycleContext.findRepeatableAnnotations(MyRepeatableAnnotation.class);
97+
assertThat(repeatableAnnotations).isNotEmpty();
98+
assertThat(repeatableAnnotations.stream().map(MyRepeatableAnnotation::value))
99+
.contains("three", "four");
100+
101+
}
102+
103+
@MyRepeatableAnnotation("five")
104+
@MyRepeatableAnnotation("six")
105+
@Example
106+
void tryLifecycleDescriptor() {
107+
108+
PropertyMethodDescriptor methodDescriptor = (PropertyMethodDescriptor) TestDescriptorBuilder.forMethod(
109+
LifecycleContextAnnotationsTests.class, "tryLifecycleDescriptor"
110+
).build();
111+
DefaultPropertyLifecycleContext propertyLifecycleContext = new DefaultPropertyLifecycleContext(
112+
methodDescriptor,
113+
new LifecycleContextAnnotationsTests(),
114+
reporter,
115+
resolveParameter
116+
);
117+
118+
TryLifecycleContext lifecycleContext = new DefaultTryLifecycleContext(propertyLifecycleContext);
119+
120+
assertThat(lifecycleContext.findAnnotation(Example.class)).isPresent();
121+
assertThat(lifecycleContext.findAnnotationsInContainer(MyAnnotation.class))
122+
.hasSize(1);
123+
124+
List<MyRepeatableAnnotation> repeatableAnnotations = lifecycleContext.findRepeatableAnnotations(MyRepeatableAnnotation.class);
125+
assertThat(repeatableAnnotations).isNotEmpty();
126+
assertThat(repeatableAnnotations.stream().map(MyRepeatableAnnotation::value))
127+
.contains("five", "six");
128+
72129
}
73130

74131
@Group
@@ -83,3 +140,16 @@ void aProperty(@ForAll String aString) {}
83140
@Retention(RetentionPolicy.RUNTIME)
84141
@interface MyAnnotation {
85142
}
143+
144+
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE})
145+
@Retention(RetentionPolicy.RUNTIME)
146+
@Repeatable(MyRepeatableAnnotations.class)
147+
@interface MyRepeatableAnnotation {
148+
String value();
149+
}
150+
151+
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE})
152+
@Retention(RetentionPolicy.RUNTIME)
153+
@interface MyRepeatableAnnotations {
154+
MyRepeatableAnnotation[] value();
155+
}

0 commit comments

Comments
 (0)