11package com .github .nylle .javafixture .annotations .testcases ;
22
3- import com .github .nylle .javafixture .Fixture ;
43import com .github .nylle .javafixture .SpecimenType ;
54import org .junit .jupiter .api .extension .ExtensionContext ;
65import org .junit .jupiter .params .provider .Arguments ;
76import org .junit .jupiter .params .provider .ArgumentsProvider ;
87import org .junit .jupiter .params .support .AnnotationConsumer ;
98
9+ import java .lang .annotation .Annotation ;
1010import java .lang .reflect .Parameter ;
1111import java .util .List ;
12+ import java .util .stream .Collectors ;
1213import java .util .stream .IntStream ;
1314import java .util .stream .Stream ;
1415
16+ import static com .github .nylle .javafixture .Fixture .fixture ;
1517import static java .util .Arrays .stream ;
1618import static java .util .stream .Collectors .toList ;
19+ import static java .util .stream .Collectors .toMap ;
1720
1821class TestCasesProvider implements ArgumentsProvider , AnnotationConsumer <TestWithCases > {
1922
@@ -23,36 +26,96 @@ public void accept(TestWithCases testWithCases) {
2326
2427 @ Override
2528 public Stream <Arguments > provideArguments (ExtensionContext context ) {
26- var fixtures = context .getTestMethod ().stream ()
27- .flatMap (method -> stream (method .getParameters ())
28- .filter (parameter -> hasFixtureAnnotation (parameter ))
29- .map (parameter -> parameter .getParameterizedType ())
30- .map (type -> new Fixture ().create (SpecimenType .fromClass (type ))))
29+ var testMethod = valid (context );
30+
31+ var fixtures = testMethod .parameters ()
32+ .filter (parameter -> parameter .getAnnotation (Fixture .class ) != null )
33+ .map (parameter -> parameter .getParameterizedType ())
34+ .map (type -> fixture ().create (SpecimenType .fromClass (type )))
35+ .collect (toList ());
36+
37+ var parameterTypes = testMethod .parameters ()
38+ .filter (parameter -> parameter .getAnnotation (Fixture .class ) == null )
39+ .map (parameter -> parameter .getType ())
3140 .collect (toList ());
3241
33- return context .getTestMethod ().stream ()
34- .flatMap (method -> stream (method .getDeclaredAnnotations ())
35- .filter (annotation -> annotation .annotationType ().equals (TestCases .class ))
36- .map (cases -> (TestCases ) cases )
42+ return testMethod .declaredAnnotations (TestCases .class )
3743 .flatMap (testCases -> stream (testCases .value ()))
38- .map (testCase -> mapToArguments (testCase , getParameterTypes (context ), fixtures )));
44+ .map (testCase -> new ReflectedTestCase (testCase ))
45+ .map (testCase -> IntStream .range (0 , parameterTypes .size ()).boxed ().map (i -> testCase .getTestCaseValueFor (parameterTypes .get (i ), i )))
46+ .map (caseValues -> Stream .concat (caseValues , fixtures .stream ()))
47+ .map (values -> Arguments .of (values .toArray ()));
3948 }
4049
41- private static Arguments mapToArguments (TestCase testCase , List <Class <?>> parameters , List <Object > fixtures ) {
42- ReflectedTestCase reflectedTestCase = new ReflectedTestCase (testCase );
43- return Arguments .of (Stream .concat (IntStream .range (0 , parameters .size ()).boxed ()
44- .map (i -> reflectedTestCase .getTestCaseValueFor (parameters .get (i ), i )), fixtures .stream ()).toArray ());
45- }
50+ private static TestMethod valid (ExtensionContext context ) {
51+ var testMethod = new TestMethod (context );
52+
53+ var parameters = testMethod .parameters ().collect (toList ());
54+
55+ var strictParamIndices = IntStream .range (0 , parameters .size ()).boxed ().filter (p -> parameters .get (p ).getAnnotation (Strict .class ) != null ).collect (toList ());
56+ if (strictParamIndices .isEmpty ()) {
57+ return testMethod ;
58+ }
59+
60+ var strictAndFixture = strictParamIndices .stream ().filter (p -> parameters .get (p ).getAnnotation (Fixture .class ) != null ).collect (toList ());
61+ if (!strictAndFixture .isEmpty ()) {
62+ throw new TestCaseException ("Arguments annotated with @Fixture cannot be @Strict: " +
63+ strictAndFixture .stream ()
64+ .map (i -> parameters .get (i ).getName ())
65+ .collect (Collectors .joining (", " )));
66+ }
67+
68+ var strictAndNotEnum = strictParamIndices .stream ().filter (p -> !parameters .get (p ).getType ().isEnum ()).collect (toList ());
69+ if (!strictAndNotEnum .isEmpty ()) {
70+ throw new TestCaseException ("Arguments annotated with @Strict must be of type Enum. The following arguments are not: " +
71+ strictAndNotEnum .stream ()
72+ .map (i -> parameters .get (i ).getName ())
73+ .collect (Collectors .joining (", " )));
74+ }
4675
47- private static List <Class <?>> getParameterTypes (ExtensionContext context ) {
48- return context .getTestMethod ().stream ()
49- .flatMap (method -> stream (method .getParameters ())
50- .filter (parameter -> !hasFixtureAnnotation (parameter ))
51- .map (parameter -> parameter .getType ()))
76+ var testCases = testMethod .declaredAnnotations (TestCases .class )
77+ .flatMap (cs -> stream (cs .value ()))
78+ .map (c -> new ReflectedTestCase (c ))
5279 .collect (toList ());
80+
81+ var parameterTypes = IntStream .range (0 , parameters .size ()).boxed ().collect (toMap (k -> k , v -> parameters .get (v ).getType ()));
82+
83+ strictParamIndices .forEach (i -> {
84+ var values = testCases .stream ().map (x -> x .getTestCaseValueFor (parameterTypes .get (i ), i )).collect (toList ());
85+ var uncovered = stream (((Class <? extends Enum >) parameterTypes .get (i )).getEnumConstants ())
86+ .filter (x -> !values .contains (x ))
87+ .map (x -> parameterTypes .get (i ).getSimpleName () + "." + x )
88+ .collect (Collectors .joining ("\n " ));
89+ if (!uncovered .isEmpty ()) {
90+ throw new AssertionError ("@Strict requires all Enum values to be covered by test-cases. Missing values for " + parameters .get (i ).getName () + ":\n " + uncovered );
91+ }
92+ });
93+
94+ return testMethod ;
5395 }
5496
55- private static boolean hasFixtureAnnotation (Parameter parameter ) {
56- return parameter .getAnnotation (com .github .nylle .javafixture .annotations .testcases .Fixture .class ) != null ;
97+ private static class TestMethod {
98+
99+ private final List <Parameter > parameters ;
100+ private final List <Annotation > declaredAnnotations ;
101+
102+ public TestMethod (ExtensionContext context ) {
103+ this .parameters = context .getTestMethod ().stream ()
104+ .flatMap (method -> Stream .ofNullable (method .getParameters ()).flatMap (params -> stream (params )))
105+ .collect (toList ());
106+ this .declaredAnnotations = context .getTestMethod ().stream ()
107+ .flatMap (method -> Stream .ofNullable (method .getDeclaredAnnotations ()).flatMap (annotations -> stream (annotations )))
108+ .collect (toList ());
109+ }
110+
111+ public Stream <Parameter > parameters () {
112+ return parameters .stream ();
113+ }
114+
115+ public <T extends Annotation > Stream <T > declaredAnnotations (Class <T > type ) {
116+ return declaredAnnotations .stream ()
117+ .filter (x -> x .annotationType ().equals (type ))
118+ .map (x -> (T ) x );
119+ }
57120 }
58121}
0 commit comments