18
18
*/
19
19
20
20
/*
21
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
21
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
22
22
*/
23
23
package org .opensolaris .opengrok .condition ;
24
24
25
+ import java .lang .reflect .Method ;
26
+ import java .lang .reflect .Modifier ;
27
+ import java .util .ArrayList ;
28
+ import java .util .LinkedList ;
29
+ import java .util .List ;
25
30
import org .junit .Assume ;
26
31
import org .junit .rules .TestRule ;
27
32
import org .junit .runner .Description ;
28
33
import org .junit .runners .model .Statement ;
29
34
30
- import java .lang .reflect .Modifier ;
31
-
32
35
/**
33
36
*
34
37
* This rule can be added to a Junit test and will look for the annotation
41
44
* https://gist.github.com/yinzara/9980184
42
45
* http://cwd.dhemery.com/2010/12/junit-rules/
43
46
* http://stackoverflow.com/questions/28145735/androidjunit4-class-org-junit-assume-assumetrue-assumptionviolatedexception/
47
+ * https://docs.oracle.com/javase/tutorial/java/annotations/repeating.html
44
48
*/
45
49
public class ConditionalRunRule implements TestRule {
46
50
@@ -64,34 +68,70 @@ public Statement apply(Statement aStatement, Description aDescription) {
64
68
}
65
69
66
70
private static boolean hasConditionalIgnoreAnnotationOnClass (Description aDescription ) {
67
- return aDescription .getTestClass ().getAnnotation (ConditionalRun .class ) != null ;
71
+ return aDescription .getTestClass ().getAnnotationsByType (ConditionalRun .class ). length > 0 ;
68
72
}
69
73
70
74
private static RunCondition getIgnoreConditionOnClass (Description aDescription ) {
71
- ConditionalRun annotation = aDescription .getTestClass ().getAnnotation (ConditionalRun .class );
72
- return new IgnoreConditionCreator (aDescription .getTestClass (), annotation ).create ();
75
+ ConditionalRun [] annotations = aDescription .getTestClass ().getAnnotationsByType (ConditionalRun .class );
76
+ return new IgnoreConditionCreator (aDescription .getTestClass (), annotations ).create ();
73
77
}
74
78
75
79
private static boolean hasConditionalIgnoreAnnotationOnMethod (Description aDescription ) {
76
- return aDescription .getAnnotation (ConditionalRun .class ) != null ;
80
+ try {
81
+ // this is possible because test methods must not have any argument
82
+ Method testMethod = aDescription .getTestClass ().getMethod (aDescription .getMethodName ());
83
+ return testMethod .getAnnotationsByType (ConditionalRun .class ).length > 0 ;
84
+ } catch (NoSuchMethodException | SecurityException ex ) {
85
+ throw new RuntimeException (ex );
86
+ }
77
87
}
78
88
79
89
private static RunCondition getIgnoreConditionOnMethod (Description aDescription ) {
80
- ConditionalRun annotation = aDescription .getAnnotation (ConditionalRun .class );
81
- return new IgnoreConditionCreator (aDescription .getTestClass (), annotation ).create ();
90
+ try {
91
+ // this is possible because test methods must not have any argument
92
+ ConditionalRun [] annotations = aDescription .getTestClass ().getMethod (aDescription .getMethodName ()).getAnnotationsByType (ConditionalRun .class );
93
+ return new IgnoreConditionCreator (aDescription .getTestClass (), annotations ).create ();
94
+ } catch (NoSuchMethodException | SecurityException ex ) {
95
+ throw new RuntimeException (ex );
96
+ }
82
97
}
83
98
84
- private static class IgnoreConditionCreator {
99
+ /**
100
+ * Container for several conditions joined by an AND operator.
101
+ */
102
+ protected static class CompositeCondition implements RunCondition {
103
+
104
+ List <RunCondition > conditions = new LinkedList <>();
105
+
106
+ public boolean add (RunCondition e ) {
107
+ return conditions .add (e );
108
+ }
109
+
110
+ @ Override
111
+ public boolean isSatisfied () {
112
+ for (RunCondition condition : conditions ) {
113
+ if (!condition .isSatisfied ()) {
114
+ return false ;
115
+ }
116
+ }
117
+ return true ;
118
+ }
119
+ }
120
+
121
+ protected static class IgnoreConditionCreator {
85
122
86
123
private final Class <?> mTestClass ;
87
- private final Class <? extends RunCondition > conditionType ;
124
+ private final List < Class <? extends RunCondition >> conditionTypes ;
88
125
89
- IgnoreConditionCreator (Class <?> aTestClass , ConditionalRun annotation ) {
126
+ public IgnoreConditionCreator (Class <?> aTestClass , ConditionalRun [] annotation ) {
90
127
this .mTestClass = aTestClass ;
91
- this .conditionType = annotation .condition ();
128
+ this .conditionTypes = new ArrayList <>(annotation .length );
129
+ for (int i = 0 ; i < annotation .length ; i ++) {
130
+ this .conditionTypes .add (i , annotation [i ].condition ());
131
+ }
92
132
}
93
133
94
- RunCondition create () {
134
+ public RunCondition create () {
95
135
checkConditionType ();
96
136
try {
97
137
return createCondition ();
@@ -103,38 +143,49 @@ RunCondition create() {
103
143
}
104
144
105
145
private RunCondition createCondition () throws Exception {
106
- RunCondition result ;
107
- if (isConditionTypeStandalone ()) {
108
- result = conditionType .newInstance ();
109
- } else {
110
- result = conditionType .getDeclaredConstructor (mTestClass ).newInstance (mTestClass );
146
+ CompositeCondition result = null ;
147
+ /**
148
+ * Run through the list of classes implementing RunCondition and
149
+ * create a new class from it.
150
+ */
151
+ for (Class <? extends RunCondition > clazz : conditionTypes ) {
152
+ if (result == null ) {
153
+ result = new CompositeCondition ();
154
+ }
155
+ if (isConditionTypeStandalone (clazz )) {
156
+ result .add (clazz .newInstance ());
157
+ } else {
158
+ result .add (clazz .getDeclaredConstructor (mTestClass ).newInstance (mTestClass ));
159
+ }
111
160
}
112
161
return result ;
113
162
}
114
163
115
164
private void checkConditionType () {
116
- if (!isConditionTypeStandalone () && !isConditionTypeDeclaredInTarget ()) {
117
- String msg
118
- = "Conditional class '%s' is a member class "
119
- + "but was not declared inside the test case using it.\n "
120
- + "Either make this class a static class, "
121
- + "standalone class (by declaring it in it's own file) "
122
- + "or move it inside the test case using it" ;
123
- throw new IllegalArgumentException (String .format (msg , conditionType .getName ()));
165
+ for (Class <? extends RunCondition > clazz : conditionTypes ) {
166
+ if (!isConditionTypeStandalone (clazz ) && !isConditionTypeDeclaredInTarget (clazz )) {
167
+ String msg
168
+ = "Conditional class '%s' is a member class "
169
+ + "but was not declared inside the test case using it.\n "
170
+ + "Either make this class a static class, "
171
+ + "standalone class (by declaring it in it's own file) "
172
+ + "or move it inside the test case using it" ;
173
+ throw new IllegalArgumentException (String .format (msg , clazz .getName ()));
174
+ }
124
175
}
125
176
}
126
177
127
- private boolean isConditionTypeStandalone () {
128
- return !conditionType .isMemberClass ()
129
- || Modifier .isStatic (conditionType .getModifiers ());
178
+ private boolean isConditionTypeStandalone (Class <? extends RunCondition > clazz ) {
179
+ return !clazz .isMemberClass ()
180
+ || Modifier .isStatic (clazz .getModifiers ());
130
181
}
131
182
132
- private boolean isConditionTypeDeclaredInTarget () {
133
- return mTestClass .getClass ().isAssignableFrom (conditionType .getDeclaringClass ());
183
+ private boolean isConditionTypeDeclaredInTarget (Class <? extends RunCondition > clazz ) {
184
+ return mTestClass .getClass ().isAssignableFrom (clazz .getDeclaringClass ());
134
185
}
135
186
}
136
187
137
- private static class IgnoreStatement extends Statement {
188
+ protected static class IgnoreStatement extends Statement {
138
189
139
190
private final RunCondition condition ;
140
191
0 commit comments