19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 * or visit www.oracle.com if you need additional information or have any |
20 * or visit www.oracle.com if you need additional information or have any |
21 * questions. |
21 * questions. |
22 */ |
22 */ |
23 |
23 |
24 /** |
24 /* |
25 * @test |
25 * @test |
26 * @bug 7195131 |
26 * @bug 7151010 8006547 8007766 |
27 * @author sogoel |
27 * @summary Default test cases for running combinations for Target values |
28 * @summary Combo test for all possible combinations for Target values |
|
29 * @ignore 8008339 Test TargetAnnoCombo.java is broken |
|
30 * @build Helper |
28 * @build Helper |
31 * @compile TargetAnnoCombo.java TestCaseGenerator.java |
|
32 * @run main TargetAnnoCombo |
29 * @run main TargetAnnoCombo |
33 */ |
30 */ |
34 |
31 |
|
32 import java.util.Set; |
|
33 import java.util.List; |
35 import java.io.IOException; |
34 import java.io.IOException; |
|
35 import java.lang.annotation.ElementType; |
36 import java.util.ArrayList; |
36 import java.util.ArrayList; |
37 import java.util.Arrays; |
37 import java.util.Arrays; |
38 import java.util.HashSet; |
38 import java.util.EnumSet; |
39 import java.util.Set; |
|
40 import javax.tools.Diagnostic; |
39 import javax.tools.Diagnostic; |
41 import javax.tools.DiagnosticCollector; |
40 import javax.tools.DiagnosticCollector; |
42 import javax.tools.JavaFileObject; |
41 import javax.tools.JavaFileObject; |
43 |
42 |
44 /* |
43 import static java.lang.annotation.ElementType.ANNOTATION_TYPE; |
45 * TargetAnnoCombo gets a list of test case numbers using TestCaseGenerator. |
44 import static java.lang.annotation.ElementType.CONSTRUCTOR; |
46 * For each of the test case number, @Target sets for base and container annotations |
45 import static java.lang.annotation.ElementType.FIELD; |
47 * are determined, source files are generated, compiled, and the result is verified |
46 import static java.lang.annotation.ElementType.METHOD; |
48 * based on if the @Target set for base and container is a positive or negative combination. |
47 import static java.lang.annotation.ElementType.PARAMETER; |
49 * |
48 import static java.lang.annotation.ElementType.TYPE; |
50 * @Target sets for base and container annotations are determined using a bit mapping of |
49 import static java.lang.annotation.ElementType.PACKAGE; |
51 * 10 ElementType enum constants defined in JDK8. |
50 import static java.lang.annotation.ElementType.LOCAL_VARIABLE; |
52 * |
51 import static java.lang.annotation.ElementType.TYPE_USE; |
53 * Bit Target value |
52 import static java.lang.annotation.ElementType.TYPE_PARAMETER; |
54 * 0 "ElementType.ANNOTATION_TYPE" |
|
55 * 1 "ElementType.CONSTRUCTOR" |
|
56 * 2 "ElementType.FIELD" |
|
57 * 3 "ElementType.LOCAL_VARIABLE" |
|
58 * 4 "ElementType.METHOD" |
|
59 * 5 "ElementType.TYPE" |
|
60 * 6 "ElementType.PARAMETER" |
|
61 * 7 "ElementType.PACKAGE" |
|
62 * 8 "ElementType.TYPE_USE" |
|
63 * 9 "ElementType.TYPE_PARAMETER" |
|
64 * |
|
65 * Group 1: |
|
66 * 20 bits mapping, representing a test case number, is used for all target set |
|
67 * combinations ( 0 to 1048575 ) including empty @Target sets => @Target({}). |
|
68 * From this 20 bits, 10 bits are for base followed by 10 bits for container |
|
69 * where each bit maps to an ElementType enum constant defined in JDK8. |
|
70 * |
|
71 * Examples: |
|
72 * Test case number: 4, binary: 100 => container=100, base=[], container=["ElementType.FIELD"] |
|
73 * Test case number: 1003575, binary: 11110101000000110111 => base=1111010100, container=0000110111; |
|
74 * base=["ElementType.PARAMETER", "ElementType.TYPE_USE", "ElementType.METHOD", "ElementType.FIELD", "ElementType.PACKAGE", "ElementType.TYPE_PARAMETER"], |
|
75 * container=["ElementType.TYPE", "ElementType.METHOD", "ElementType.ANNOTATION_TYPE", "ElementType.CONSTRUCTOR", "ElementType.FIELD"] |
|
76 * |
|
77 * In the following groups, no @Target set is represented by null. |
|
78 * Group 2: |
|
79 * @Target is not defined on base. |
|
80 * Target sets for container are determined using the 10-bit binary number |
|
81 * resulting in 1024 test cases, mapping them to test case numbers from |
|
82 * 1048576 to (1048576 + 1023) => 1048576 to 1049599. |
|
83 * |
|
84 * Example: |
|
85 * Test case number: 1048587 => 1048587 - 1048576 = test case 11 in Group 2, binary: 1011 => |
|
86 * base = null, |
|
87 * container = ["ElementType.ANNOTATION_TYPE","ElementType.CONSTRUCTOR","ElementType.LOCAL_VARIABLE"] |
|
88 * |
|
89 * Group 3: |
|
90 * @Target is not defined on container |
|
91 * Target sets for base are determined using the 10-bit binary number |
|
92 * resulting in 1024 test cases, mapping them to test case numbers from |
|
93 * 1049600 to (1049600 + 1023) => 1049600 to 1050623. |
|
94 * |
|
95 * Example: |
|
96 * Test case number: 1049708 => 1049708 - 1049600 = test case 108 in Group 3, binary: 1101100 => |
|
97 * base = ["ElementType.FIELD", "ElementType.LOCAL_VARIABLE", "ElementType.TYPE", "ElementType.PARAMETER"], |
|
98 * container = null |
|
99 * |
|
100 * For the above group, test case number: 1049855 gives compiler error, JDK-8006547 filed |
|
101 * |
|
102 * Group 4: |
|
103 * @Target not defined for both base and container annotations. |
|
104 * |
|
105 * This is the last test and corresponds to test case number 1050624. base=null, container=null |
|
106 * |
|
107 * Examples to run this test: |
|
108 * 1. Run a specific test case number: |
|
109 * ${JTREG} -DTestCaseNum=10782 -samevm -jdk:${JAVA_TEST} -reportDir ${REPORT} -workDir ${WORK} TargetAnnoCombo.java |
|
110 * 2. Run specific number of tests: |
|
111 * ${JTREG} -DNumberOfTests=4 -samevm -jdk:${JAVA_TEST} -reportDir ${REPORT} -workDir ${WORK} TargetAnnoCombo.java |
|
112 * 3. Run specific number of tests with a seed: |
|
113 * ${JTREG} -DNumberOfTests=4 -DTestSeed=-972894659 -samevm -jdk:${JAVA_TEST} -reportDir ${REPORT} -workDir ${WORK} TargetAnnoCombo.java |
|
114 * 4. Run tests in default mode (number of tests = 1000): |
|
115 * ${JTREG} -DTestMode=DEFAULT -samevm -jdk:${JAVA_TEST} -reportDir ${REPORT} -workDir ${WORK} TargetAnnoCombo.java |
|
116 * 5. Run all tests (FULL mode): |
|
117 * ${JTREG} -DTestMode=FULL -samevm -jdk:${JAVA_TEST} -reportDir ${REPORT} -workDir ${WORK} TargetAnnoCombo.java |
|
118 * |
|
119 */ |
|
120 |
53 |
121 public class TargetAnnoCombo { |
54 public class TargetAnnoCombo { |
|
55 |
|
56 static final String TESTPKG = "testpkg"; |
|
57 |
|
58 // Set it to true to get more debug information including base and container |
|
59 // target sets for a given test case. |
|
60 static final boolean DEBUG = false; |
|
61 |
|
62 // Define constant target sets to be used for the combination of the target values. |
|
63 final static Set<ElementType> noSet = null; |
|
64 final static Set<ElementType> empty = EnumSet.noneOf(ElementType.class); |
|
65 |
|
66 // [TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, |
|
67 // PACKAGE, TYPE_PARAMETER, TYPE_USE] |
|
68 final static Set<ElementType> allTargets = EnumSet.allOf(ElementType.class); |
|
69 |
|
70 // [TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, |
|
71 // PACKAGE] |
|
72 final static Set<ElementType> jdk7 = EnumSet.range(TYPE, PACKAGE); |
|
73 |
|
74 // [TYPE_USE, TYPE_PARAMETER] |
|
75 final static Set<ElementType> jdk8 = EnumSet.range(TYPE_PARAMETER, TYPE_USE); |
|
76 |
|
77 // List of test cases to run. This list is created in generate(). |
|
78 // To run a specific test cases add case number in @run main line. |
|
79 List<TestCase> testCases = new ArrayList<TestCase>(); |
|
80 |
122 int errors = 0; |
81 int errors = 0; |
123 static final String TESTPKG = "testpkg"; |
82 |
124 /* |
83 // Identify test cases that fail. |
125 * Set it to true to get more debug information including base and |
84 enum IgnoreKind { |
126 * container target sets for a given test case number |
85 RUN, |
127 */ |
86 IGNORE |
128 static final boolean DEBUG = false; |
87 }; |
129 |
88 |
130 // JDK 5/6/7/8 Targets |
89 private class TestCase { |
131 static final String[] targetVals = {"ElementType.ANNOTATION_TYPE", |
90 |
132 "ElementType.CONSTRUCTOR", "ElementType.FIELD", |
91 private Set<ElementType> baseAnnotations; |
133 "ElementType.LOCAL_VARIABLE", "ElementType.METHOD", |
92 private Set<ElementType> containerAnnotations; |
134 "ElementType.TYPE", "ElementType.PARAMETER", |
93 private IgnoreKind ignore; |
135 "ElementType.PACKAGE", "ElementType.TYPE_USE", |
94 |
136 "ElementType.TYPE_PARAMETER"}; |
95 public TestCase(Set<ElementType> baseAnnotations, Set<ElementType> containerAnnotations) { |
137 |
96 this(baseAnnotations, containerAnnotations, IgnoreKind.RUN); |
138 // TYPE_USE and TYPE_PARAMETER (added in JDK8) are not part of default Target set |
97 } |
139 static final int DEFAULT_TARGET_CNT = 8; |
98 |
|
99 public TestCase(Set<ElementType> baseAnnotations, Set<ElementType> containerAnnotations, |
|
100 IgnoreKind ignoreKind) { |
|
101 this.baseAnnotations = baseAnnotations; |
|
102 this.containerAnnotations = containerAnnotations; |
|
103 this.ignore = ignoreKind; |
|
104 } |
|
105 |
|
106 public Set getBaseAnnotations() { |
|
107 return baseAnnotations; |
|
108 } |
|
109 |
|
110 public Set getContainerAnnotations() { |
|
111 return containerAnnotations; |
|
112 } |
|
113 |
|
114 public boolean isIgnored() { |
|
115 return ignore == IgnoreKind.IGNORE; |
|
116 } |
|
117 |
|
118 // Determine if a testCase should compile or not. |
|
119 private boolean isValidSubSet() { |
|
120 /* |
|
121 * RULE 1: conAnnoTarget should be a subset of baseAnnoTarget |
|
122 * RULE 2: For empty @Target ({}) - annotation cannot be applied anywhere |
|
123 * - Empty sets for both is valid |
|
124 * - Empty baseTarget set is invalid with non-empty conTarget set |
|
125 * - Non-empty baseTarget set is valid with empty conTarget set |
|
126 * RULE 3: For no @Target specified - annotation can be applied to any JDK 7 targets |
|
127 * - No @Target for both is valid |
|
128 * - No @Target for baseTarget set with @Target conTarget set is valid |
|
129 * - @Target for baseTarget set with no @Target for conTarget is invalid |
|
130 */ |
|
131 |
|
132 |
|
133 /* If baseAnno has no @Target, Foo can be either applied to @Target specified |
|
134 * for container annotation else will be applicable for all default targets |
|
135 * if no @Target is present for container annotation. |
|
136 * In both cases, the set will be a valid set with no @Target for base annotation |
|
137 */ |
|
138 if (baseAnnotations == null) { |
|
139 if (containerAnnotations == null) { |
|
140 return true; |
|
141 } |
|
142 return !(containerAnnotations.contains(TYPE_USE) || |
|
143 containerAnnotations.contains(TYPE_PARAMETER)); |
|
144 } |
|
145 |
|
146 Set<ElementType> tempBaseSet = EnumSet.noneOf(ElementType.class); |
|
147 tempBaseSet.addAll(baseAnnotations); |
|
148 // If BaseAnno has TYPE, then ANNOTATION_TYPE is allowed by default. |
|
149 if (baseAnnotations.contains(TYPE)) { |
|
150 tempBaseSet.add(ANNOTATION_TYPE); |
|
151 } |
|
152 |
|
153 // If containerAnno has no @Target, only valid case if baseAnnoTarget has |
|
154 // all targets defined else invalid set. |
|
155 if (containerAnnotations == null) { |
|
156 return tempBaseSet.containsAll(jdk7); |
|
157 } |
|
158 |
|
159 // At this point, neither conAnnoTarget or baseAnnoTarget are null. |
|
160 if (containerAnnotations.isEmpty()) { |
|
161 return true; |
|
162 } |
|
163 |
|
164 // At this point, conAnnoTarget is non-empty. |
|
165 if (baseAnnotations.isEmpty()) { |
|
166 return false; |
|
167 } |
|
168 |
|
169 // At this point, neither conAnnoTarget or baseAnnoTarget are empty. |
|
170 return tempBaseSet.containsAll(containerAnnotations); |
|
171 } |
|
172 } |
140 |
173 |
141 public static void main(String args[]) throws Exception { |
174 public static void main(String args[]) throws Exception { |
142 |
|
143 /* maxTestNum = (base and container combinations of targetVals elems [0 - 1048575 combos]) |
|
144 * + (combinations where base or container has no Target [1024 combos]) |
|
145 * + (no -1 even though 1st test is number 0 as last test is where both |
|
146 * base and container have no target) |
|
147 */ |
|
148 |
|
149 int maxTestNum = (int)Math.pow(2, 2*targetVals.length) + 2*(int)Math.pow(2, targetVals.length); |
|
150 TestCaseGenerator tcg = new TestCaseGenerator(maxTestNum); |
|
151 TargetAnnoCombo tac = new TargetAnnoCombo(); |
175 TargetAnnoCombo tac = new TargetAnnoCombo(); |
152 |
176 // Generates all test cases to be run. |
|
177 tac.generate(); |
|
178 List<Integer> cases = new ArrayList<Integer>(); |
|
179 for (int i = 0; i < args.length; i++) { |
|
180 cases.add(Integer.parseInt(args[i])); |
|
181 } |
|
182 if (cases.isEmpty()) { |
|
183 tac.run(); |
|
184 } else { |
|
185 for (int index : cases) { |
|
186 tac.executeTestCase(tac.testCases.get(index), index); |
|
187 } |
|
188 } |
|
189 } |
|
190 |
|
191 private void generate() { |
|
192 // Adding test cases to run. |
|
193 testCases.addAll(Arrays.asList( |
|
194 // No base target against no container target. |
|
195 new TestCase(noSet, noSet), |
|
196 // No base target against empty container target. |
|
197 new TestCase(noSet, empty), |
|
198 // No base target against TYPE_USE only container target. |
|
199 new TestCase(noSet, less(jdk8, TYPE_PARAMETER)), |
|
200 // No base target against TYPE_PARAMETER only container target. |
|
201 new TestCase(noSet, less(jdk8, TYPE_USE)), |
|
202 // No base target against TYPE_USE + TYPE_PARAMETER only container target. |
|
203 new TestCase(noSet, jdk8), |
|
204 // No base target against TYPE_USE + some selection of jdk7 targets. |
|
205 new TestCase(noSet, |
|
206 plus(EnumSet.range(TYPE, LOCAL_VARIABLE), TYPE_USE)), |
|
207 // No base target against TYPE_PARAMETER + some selection of jdk7 targets. |
|
208 new TestCase(noSet, |
|
209 plus(EnumSet.range(TYPE, LOCAL_VARIABLE), TYPE_PARAMETER)), |
|
210 // No base target against each jdk7 target alone as container target. |
|
211 new TestCase(noSet, plus(empty, TYPE)), |
|
212 new TestCase(noSet, plus(empty, PARAMETER)), |
|
213 new TestCase(noSet, plus(empty, PACKAGE)), |
|
214 new TestCase(noSet, plus(empty, METHOD)), |
|
215 new TestCase(noSet, plus(empty, LOCAL_VARIABLE)), |
|
216 new TestCase(noSet, plus(empty, FIELD)), |
|
217 new TestCase(noSet, plus(empty, CONSTRUCTOR)), |
|
218 new TestCase(noSet, plus(empty, ANNOTATION_TYPE)), |
|
219 // Empty base target against no container target. |
|
220 new TestCase(empty, noSet), |
|
221 // Empty base target against empty container target. |
|
222 new TestCase(empty, empty), |
|
223 // Empty base target against any lone container target. |
|
224 new TestCase(empty, plus(empty, TYPE)), |
|
225 new TestCase(empty, plus(empty, PARAMETER)), |
|
226 new TestCase(empty, plus(empty, PACKAGE)), |
|
227 new TestCase(empty, plus(empty, METHOD)), |
|
228 new TestCase(empty, plus(empty, LOCAL_VARIABLE)), |
|
229 new TestCase(empty, plus(empty, FIELD)), |
|
230 new TestCase(empty, plus(empty, CONSTRUCTOR)), |
|
231 new TestCase(empty, plus(empty, ANNOTATION_TYPE)), |
|
232 new TestCase(empty, less(jdk8, TYPE_USE)), |
|
233 new TestCase(empty, less(jdk8, TYPE_PARAMETER)), |
|
234 // No container target against all all-but one jdk7 targets. |
|
235 new TestCase(less(jdk7, TYPE), noSet), |
|
236 new TestCase(less(jdk7, PARAMETER), noSet), |
|
237 new TestCase(less(jdk7, PACKAGE), noSet), |
|
238 new TestCase(less(jdk7, METHOD), noSet), |
|
239 new TestCase(less(jdk7, LOCAL_VARIABLE), noSet), |
|
240 new TestCase(less(jdk7, FIELD), noSet), |
|
241 new TestCase(less(jdk7, CONSTRUCTOR), noSet), |
|
242 new TestCase(less(jdk7, ANNOTATION_TYPE), noSet), |
|
243 // No container against all but TYPE and ANNOTATION_TYPE |
|
244 new TestCase(less(jdk7, TYPE, ANNOTATION_TYPE), noSet), |
|
245 // No container against jdk7 targets. |
|
246 new TestCase(jdk7, noSet), |
|
247 // No container against jdk7 targets plus one or both of TYPE_USE, TYPE_PARAMETER |
|
248 new TestCase(plus(jdk7, TYPE_USE), noSet), |
|
249 new TestCase(plus(jdk7, TYPE_PARAMETER), noSet), |
|
250 new TestCase(allTargets, noSet), |
|
251 // Empty container target against any lone target. |
|
252 new TestCase(plus(empty, TYPE), empty), |
|
253 new TestCase(plus(empty, PARAMETER), empty), |
|
254 new TestCase(plus(empty, PACKAGE), empty), |
|
255 new TestCase(plus(empty, METHOD), empty), |
|
256 new TestCase(plus(empty, LOCAL_VARIABLE), empty), |
|
257 new TestCase(plus(empty, FIELD), empty), |
|
258 new TestCase(plus(empty, CONSTRUCTOR), empty), |
|
259 new TestCase(plus(empty, ANNOTATION_TYPE), empty), |
|
260 new TestCase(plus(empty, TYPE_USE), empty), |
|
261 new TestCase(plus(empty, TYPE_PARAMETER), empty), |
|
262 // All base targets against all container targets. |
|
263 new TestCase(allTargets, allTargets), |
|
264 // All base targets against all but one container targets. |
|
265 new TestCase(allTargets, less(allTargets, TYPE)), |
|
266 new TestCase(allTargets, less(allTargets, PARAMETER)), |
|
267 new TestCase(allTargets, less(allTargets, PACKAGE)), |
|
268 new TestCase(allTargets, less(allTargets, METHOD)), |
|
269 new TestCase(allTargets, less(allTargets, LOCAL_VARIABLE)), |
|
270 new TestCase(allTargets, less(allTargets, FIELD)), |
|
271 new TestCase(allTargets, less(allTargets, CONSTRUCTOR)), |
|
272 new TestCase(allTargets, less(allTargets, ANNOTATION_TYPE)), |
|
273 new TestCase(allTargets, less(allTargets, TYPE_USE)), |
|
274 new TestCase(allTargets, less(allTargets, TYPE_PARAMETER)), |
|
275 // All container targets against all but one base targets. |
|
276 new TestCase(less(allTargets, TYPE), allTargets), |
|
277 new TestCase(less(allTargets, PARAMETER), allTargets), |
|
278 new TestCase(less(allTargets, PACKAGE), allTargets), |
|
279 new TestCase(less(allTargets, METHOD), allTargets), |
|
280 new TestCase(less(allTargets, LOCAL_VARIABLE), allTargets), |
|
281 new TestCase(less(allTargets, FIELD), allTargets), |
|
282 new TestCase(less(allTargets, CONSTRUCTOR), allTargets), |
|
283 new TestCase(less(allTargets, ANNOTATION_TYPE), allTargets), |
|
284 new TestCase(less(allTargets, TYPE_USE), allTargets), |
|
285 new TestCase(less(allTargets, TYPE_PARAMETER), allTargets))); |
|
286 // Generates 100 test cases for any lone base target contained in Set |
|
287 // allTargets against any lone container target. |
|
288 for (ElementType b : allTargets) { |
|
289 for (ElementType c : allTargets) { |
|
290 testCases.add(new TestCase(plus(empty, b), plus(empty, c))); |
|
291 } |
|
292 } |
|
293 } |
|
294 |
|
295 void run() throws Exception { |
153 int testCtr = 0; |
296 int testCtr = 0; |
154 int testCase = -1; |
297 for (TestCase tc : testCases) { |
155 while ( (testCase=tcg.getNextTestCase()) != -1 ) { |
298 if (!tc.isIgnored()) { |
156 tac.executeTestCase(testCase, maxTestNum); |
299 executeTestCase(tc, testCases.indexOf(tc)); |
157 testCtr++; |
300 testCtr++; |
158 } |
301 } |
159 |
302 } |
160 System.out.println("Total tests run: " + testCtr); |
303 System.out.println("Total tests run: " + testCtr); |
161 if (tac.errors > 0) |
304 if (errors > 0) { |
162 throw new Exception(tac.errors + " errors found"); |
305 throw new Exception(errors + " errors found"); |
163 } |
306 } |
164 |
307 } |
165 /* |
308 |
166 * For given testCase, determine the base and container annotation Target sets, |
309 private void executeTestCase(TestCase testCase, int index) { |
167 * get if testCase should compile, get test source file(s), get compilation result and verify. |
310 debugPrint("Test case number = " + index); |
168 * |
311 debugPrint(" => baseAnnoTarget = " + testCase.getBaseAnnotations()); |
169 */ |
312 debugPrint(" => containerAnnoTarget = " + testCase.getContainerAnnotations()); |
170 private void executeTestCase(int testCase, int maxTestNum) { |
313 |
171 |
314 String className = "TC" + index; |
172 // Determine base and container annotation Target sets for the testCase |
315 boolean shouldCompile = testCase.isValidSubSet(); |
173 Set<String> baseAnnoTarget = null; |
316 Iterable<? extends JavaFileObject> files = getFileList(className, testCase, shouldCompile); |
174 Set<String> conAnnoTarget = null; |
317 // Get result of compiling test src file(s). |
175 |
|
176 //Number of base and container combinations [0 - 1048575 combos] |
|
177 int baseContCombos = (int)Math.pow(2, 2*targetVals.length); |
|
178 //Number of either base or container combinations when one of them has no @Target [1024 combos] |
|
179 int targetValsCombos = (int)Math.pow(2, targetVals.length); |
|
180 |
|
181 if (testCase >= baseContCombos) { |
|
182 //Base annotation do not have @Target |
|
183 if (testCase < baseContCombos + targetValsCombos) { |
|
184 baseAnnoTarget = null; |
|
185 conAnnoTarget = getSetFromBitVec(Integer.toBinaryString(testCase - baseContCombos)); |
|
186 } else if (testCase < baseContCombos + 2*targetValsCombos) { |
|
187 //Container annotation do not have @Target |
|
188 baseAnnoTarget = getSetFromBitVec(Integer.toBinaryString(testCase - baseContCombos - targetValsCombos)); |
|
189 conAnnoTarget = null; |
|
190 } else { |
|
191 //Both Base and Container annotation do not have @Target |
|
192 baseAnnoTarget = null; |
|
193 conAnnoTarget = null; |
|
194 } |
|
195 } else { |
|
196 //TestCase number is represented as 10-bits for base followed by container bits |
|
197 String bin = Integer.toBinaryString(testCase); |
|
198 String base="", cont=bin; |
|
199 if (bin.length() > targetVals.length){ |
|
200 base = bin.substring(0, bin.length() - targetVals.length); |
|
201 cont = bin.substring(bin.length() - targetVals.length,bin.length()); |
|
202 } |
|
203 baseAnnoTarget = getSetFromBitVec(base); |
|
204 conAnnoTarget = getSetFromBitVec(cont); |
|
205 } |
|
206 |
|
207 debugPrint("Test case number = " + testCase + " => binary = " + Integer.toBinaryString(testCase)); |
|
208 debugPrint(" => baseAnnoTarget = " + baseAnnoTarget); |
|
209 debugPrint(" => containerAnnoTarget = " + conAnnoTarget); |
|
210 |
|
211 // Determine if a testCase should compile or not |
|
212 String className = "TC" + testCase; |
|
213 boolean shouldCompile = isValidSubSet(baseAnnoTarget, conAnnoTarget); |
|
214 |
|
215 // Get test source file(s) |
|
216 Iterable<? extends JavaFileObject> files = getFileList(className, baseAnnoTarget, |
|
217 conAnnoTarget, shouldCompile); |
|
218 |
|
219 // Get result of compiling test src file(s) |
|
220 boolean result = getCompileResult(className, shouldCompile, files); |
318 boolean result = getCompileResult(className, shouldCompile, files); |
221 |
319 // List test src code if test fails. |
222 // List test src code if test fails |
320 if (!result) { |
223 if(!result) { |
321 System.out.println("FAIL: Test " + index); |
224 System.out.println("FAIL: Test " + testCase); |
|
225 try { |
322 try { |
226 for (JavaFileObject f: files) { |
323 for (JavaFileObject f : files) { |
227 System.out.println("File: " + f.getName() + "\n" + f.getCharContent(true)); |
324 System.out.println("File: " + f.getName() + "\n" + f.getCharContent(true)); |
228 } |
325 } |
229 } catch (IOException ioe) { |
326 } catch (IOException ioe) { |
230 System.out.println("Exception: " + ioe); |
327 System.out.println("Exception: " + ioe); |
231 } |
328 } |
232 } else { |
329 } else { |
233 debugPrint("PASS: Test " + testCase); |
330 debugPrint("PASS: Test " + index); |
234 } |
331 } |
235 } |
332 |
236 |
333 } |
237 // Get a Set<String> based on bits that are set to 1 |
334 |
238 public Set<String> getSetFromBitVec(String bitVec) { |
335 // Create src code and corresponding JavaFileObjects. |
239 Set<String> ret = new HashSet<>(); |
336 private Iterable<? extends JavaFileObject> getFileList(String className, |
240 char[] bit = bitVec.toCharArray(); |
337 TestCase testCase, boolean shouldCompile) { |
241 for (int i=bit.length-1, j=0; i>=0; i--, j++){ |
338 Set<ElementType> baseAnnoTarget = testCase.getBaseAnnotations(); |
242 if (bit[i] == '1') { |
339 Set<ElementType> conAnnoTarget = testCase.getContainerAnnotations(); |
243 ret.add(targetVals[j]); |
340 String srcContent = ""; |
244 } |
341 String pkgInfoContent = ""; |
245 } |
342 String template = Helper.template; |
246 return ret; |
343 String baseTarget = "", conTarget = ""; |
247 } |
344 |
248 |
345 String target = Helper.ContentVars.TARGET.getVal(); |
249 // Compile the test source file(s) and return test result |
346 if (baseAnnoTarget != null) { |
|
347 String tmp = target.replace("#VAL", convertToString(baseAnnoTarget).toString()); |
|
348 baseTarget = tmp.replace("[", "{").replace("]", "}"); |
|
349 } |
|
350 if (conAnnoTarget != null) { |
|
351 String tmp = target.replace("#VAL", convertToString(conAnnoTarget).toString()); |
|
352 conTarget = tmp.replace("[", "{").replace("]", "}"); |
|
353 } |
|
354 |
|
355 String annoData = Helper.ContentVars.IMPORTSTMTS.getVal() |
|
356 + conTarget |
|
357 + Helper.ContentVars.CONTAINER.getVal() |
|
358 + baseTarget |
|
359 + Helper.ContentVars.REPEATABLE.getVal() |
|
360 + Helper.ContentVars.BASE.getVal(); |
|
361 |
|
362 JavaFileObject pkgInfoFile = null; |
|
363 |
|
364 // If shouldCompile = true and no @Target is specified for container annotation, |
|
365 // then all 8 ElementType enum constants are applicable as targets for |
|
366 // container annotation. |
|
367 if (shouldCompile && conAnnoTarget == null) { |
|
368 Set<ElementType> copySet = EnumSet.noneOf(ElementType.class); |
|
369 copySet.addAll(jdk7); |
|
370 conAnnoTarget = copySet; |
|
371 } |
|
372 |
|
373 if (shouldCompile) { |
|
374 boolean isPkgCasePresent = conAnnoTarget.contains(PACKAGE); |
|
375 String repeatableAnno = Helper.ContentVars.BASEANNO.getVal() |
|
376 + " " + Helper.ContentVars.BASEANNO.getVal(); |
|
377 for (ElementType s : conAnnoTarget) { |
|
378 String replaceStr = "/*" + s.name() + "*/"; |
|
379 if (s.name().equalsIgnoreCase("PACKAGE")) { |
|
380 //Create packageInfo file. |
|
381 String pkgInfoName = TESTPKG + "." + "package-info"; |
|
382 pkgInfoContent = repeatableAnno + "\npackage " + TESTPKG + ";" + annoData; |
|
383 pkgInfoFile = Helper.getFile(pkgInfoName, pkgInfoContent); |
|
384 } else { |
|
385 template = template.replace(replaceStr, repeatableAnno); |
|
386 if (!isPkgCasePresent) { |
|
387 srcContent = template.replace( |
|
388 "/*ANNODATA*/", annoData).replace("#ClassName", className); |
|
389 } else { |
|
390 replaceStr = "/*PACKAGE*/"; |
|
391 String tmp = template.replace(replaceStr, "package " + TESTPKG + ";"); |
|
392 srcContent = tmp.replace("#ClassName", className); |
|
393 } |
|
394 } |
|
395 } |
|
396 } else { |
|
397 // For invalid cases, compilation should fail at declaration site. |
|
398 template = "class #ClassName {}"; |
|
399 srcContent = annoData + template.replace("#ClassName", className); |
|
400 } |
|
401 JavaFileObject srcFile = Helper.getFile(className, srcContent); |
|
402 Iterable<? extends JavaFileObject> files = null; |
|
403 if (pkgInfoFile != null) { |
|
404 files = Arrays.asList(pkgInfoFile, srcFile); |
|
405 } else { |
|
406 files = Arrays.asList(srcFile); |
|
407 } |
|
408 return files; |
|
409 } |
|
410 |
|
411 // Compile the test source file(s) and return test result. |
250 private boolean getCompileResult(String className, boolean shouldCompile, |
412 private boolean getCompileResult(String className, boolean shouldCompile, |
251 Iterable<? extends JavaFileObject> files) { |
413 Iterable<? extends JavaFileObject> files) { |
252 |
414 |
253 DiagnosticCollector<JavaFileObject> diagnostics = |
415 DiagnosticCollector<JavaFileObject> diagnostics = |
254 new DiagnosticCollector<JavaFileObject>(); |
416 new DiagnosticCollector<JavaFileObject>(); |
255 Helper.compileCode(diagnostics, files); |
417 Helper.compileCode(diagnostics, files); |
256 |
418 // Test case pass or fail. |
257 // Test case pass or fail |
|
258 boolean ok = false; |
419 boolean ok = false; |
259 |
|
260 String errMesg = ""; |
420 String errMesg = ""; |
261 int numDiags = diagnostics.getDiagnostics().size(); |
421 int numDiags = diagnostics.getDiagnostics().size(); |
262 |
|
263 if (numDiags == 0) { |
422 if (numDiags == 0) { |
264 if (shouldCompile) { |
423 if (shouldCompile) { |
265 debugPrint("Test passed, compiled as expected."); |
424 debugPrint("Test passed, compiled as expected."); |
266 ok = true; |
425 ok = true; |
267 } else { |
426 } else { |
268 errMesg = "Test failed, compiled unexpectedly."; |
427 errMesg = "Test failed, compiled unexpectedly."; |
269 ok = false; |
428 ok = false; |
270 } |
429 } |
271 } else { |
430 } else { |
272 if (shouldCompile) { |
431 if (shouldCompile) { |
273 // did not compile |
432 // did not compile. |
274 errMesg = "Test failed, did not compile."; |
433 errMesg = "Test failed, did not compile."; |
275 ok = false; |
434 ok = false; |
276 } else { |
435 } else { |
277 // Error in compilation as expected |
436 // Error in compilation as expected. |
278 String expectedErrKey = "compiler.err.invalid.repeatable." + |
437 String expectedErrKey = "compiler.err.invalid.repeatable." |
279 "annotation.incompatible.target"; |
438 + "annotation.incompatible.target"; |
280 for (Diagnostic<?> d : diagnostics.getDiagnostics()) { |
439 for (Diagnostic<?> d : diagnostics.getDiagnostics()) { |
281 if((d.getKind() == Diagnostic.Kind.ERROR) && |
440 if ((d.getKind() == Diagnostic.Kind.ERROR) |
282 d.getCode().contains(expectedErrKey)) { |
441 && d.getCode().contains(expectedErrKey)) { |
283 // Error message as expected |
442 // Error message as expected. |
284 debugPrint("Error message as expected."); |
443 debugPrint("Error message as expected."); |
285 ok = true; |
444 ok = true; |
286 break; |
445 break; |
287 } else { |
446 } else { |
288 // error message is incorrect |
447 // error message is incorrect. |
289 ok = false; |
448 ok = false; |
290 } |
449 } |
291 } |
450 } |
292 if (!ok) { |
451 if (!ok) { |
293 errMesg = "Incorrect error received when compiling " + |
452 errMesg = "Incorrect error received when compiling " |
294 className + ", expected: " + expectedErrKey; |
453 + className + ", expected: " + expectedErrKey; |
295 } |
454 } |
296 } |
455 } |
297 } |
456 } |
298 |
457 |
299 if(!ok) { |
458 if (!ok) { |
300 error(errMesg); |
459 error(errMesg); |
301 for (Diagnostic<?> d : diagnostics.getDiagnostics()) |
460 for (Diagnostic<?> d : diagnostics.getDiagnostics()) { |
302 System.out.println(" Diags: " + d); |
461 System.out.println(" Diags: " + d); |
|
462 } |
303 } |
463 } |
304 return ok; |
464 return ok; |
305 } |
465 } |
306 |
466 |
|
467 private Set<ElementType> less(Set<ElementType> base, ElementType... sub) { |
|
468 Set<ElementType> res = EnumSet.noneOf(ElementType.class); |
|
469 res.addAll(base); |
|
470 for (ElementType t : sub) { |
|
471 res.remove(t); |
|
472 } |
|
473 return res; |
|
474 } |
|
475 |
|
476 private Set<ElementType> plus(Set<ElementType> base, ElementType... add) { |
|
477 Set<ElementType> res = EnumSet.noneOf(ElementType.class); |
|
478 res.addAll(base); |
|
479 for (ElementType t : add) { |
|
480 res.add(t); |
|
481 } |
|
482 return res; |
|
483 } |
|
484 |
|
485 // Iterate target set and add "ElementType." in front of every target type. |
|
486 private List<String> convertToString(Set<ElementType> annoTarget) { |
|
487 if (annoTarget == null) { |
|
488 return null; |
|
489 } |
|
490 List<String> annoTargets = new ArrayList<String>(); |
|
491 for (ElementType e : annoTarget) { |
|
492 annoTargets.add("ElementType." + e.name()); |
|
493 } |
|
494 return annoTargets; |
|
495 } |
|
496 |
307 private void debugPrint(String string) { |
497 private void debugPrint(String string) { |
308 if(DEBUG) |
498 if (DEBUG) { |
309 System.out.println(string); |
499 System.out.println(string); |
310 } |
500 } |
311 |
501 } |
312 // Create src code and corresponding JavaFileObjects |
502 |
313 private Iterable<? extends JavaFileObject> getFileList(String className, |
503 private void error(String msg) { |
314 Set<String> baseAnnoTarget, Set<String> conAnnoTarget, |
|
315 boolean shouldCompile) { |
|
316 |
|
317 String srcContent = ""; |
|
318 String pkgInfoContent = ""; |
|
319 String template = Helper.template; |
|
320 String baseTarget = "", conTarget = ""; |
|
321 |
|
322 String target = Helper.ContentVars.TARGET.getVal(); |
|
323 if(baseAnnoTarget != null) { |
|
324 baseTarget = target.replace("#VAL", baseAnnoTarget.toString()) |
|
325 .replace("[", "{").replace("]", "}"); |
|
326 } |
|
327 if(conAnnoTarget != null) { |
|
328 conTarget = target.replace("#VAL", conAnnoTarget.toString()) |
|
329 .replace("[", "{").replace("]", "}"); |
|
330 } |
|
331 |
|
332 String annoData = Helper.ContentVars.IMPORTSTMTS.getVal() + |
|
333 conTarget + |
|
334 Helper.ContentVars.CONTAINER.getVal() + |
|
335 baseTarget + |
|
336 Helper.ContentVars.REPEATABLE.getVal() + |
|
337 Helper.ContentVars.BASE.getVal(); |
|
338 |
|
339 JavaFileObject pkgInfoFile = null; |
|
340 |
|
341 /* |
|
342 * If shouldCompile = true and no @Target is specified for container annotation, |
|
343 * then all 8 ElementType enum constants are applicable as targets for |
|
344 * container annotation. |
|
345 */ |
|
346 if(shouldCompile && conAnnoTarget == null) { |
|
347 //conAnnoTarget = new HashSet<String>(Arrays.asList(targetVals)); |
|
348 conAnnoTarget = getDefaultTargetSet(); |
|
349 } |
|
350 |
|
351 if(shouldCompile) { |
|
352 boolean isPkgCasePresent = new ArrayList<String>(conAnnoTarget).contains("ElementType.PACKAGE"); |
|
353 String repeatableAnno = Helper.ContentVars.BASEANNO.getVal() + " " + Helper.ContentVars.BASEANNO.getVal(); |
|
354 for(String s: conAnnoTarget) { |
|
355 s = s.replace("ElementType.",""); |
|
356 String replaceStr = "/*"+s+"*/"; |
|
357 if(s.equalsIgnoreCase("PACKAGE")) { |
|
358 //Create packageInfo file |
|
359 String pkgInfoName = TESTPKG + "." + "package-info"; |
|
360 pkgInfoContent = repeatableAnno + "\npackage " + TESTPKG + ";" + annoData; |
|
361 pkgInfoFile = Helper.getFile(pkgInfoName, pkgInfoContent); |
|
362 } else { |
|
363 template = template.replace(replaceStr, repeatableAnno); |
|
364 //srcContent = template.replace("#ClassName",className); |
|
365 if(!isPkgCasePresent) { |
|
366 srcContent = template.replace("/*ANNODATA*/", annoData).replace("#ClassName",className); |
|
367 } else { |
|
368 replaceStr = "/*PACKAGE*/"; |
|
369 srcContent = template.replace(replaceStr, "package " + TESTPKG + ";") |
|
370 .replace("#ClassName", className); |
|
371 } |
|
372 } |
|
373 } |
|
374 } else { |
|
375 // For invalid cases, compilation should fail at declaration site |
|
376 template = "class #ClassName {}"; |
|
377 srcContent = annoData + template.replace("#ClassName",className); |
|
378 } |
|
379 JavaFileObject srcFile = Helper.getFile(className, srcContent); |
|
380 Iterable<? extends JavaFileObject> files = null; |
|
381 if(pkgInfoFile != null) |
|
382 files = Arrays.asList(pkgInfoFile,srcFile); |
|
383 else |
|
384 files = Arrays.asList(srcFile); |
|
385 return files; |
|
386 } |
|
387 |
|
388 private Set<String> getDefaultTargetSet() { |
|
389 Set<String> defaultSet = new HashSet<>(); |
|
390 int ctr = 0; |
|
391 for(String s : targetVals) { |
|
392 if(ctr++ < DEFAULT_TARGET_CNT) { |
|
393 defaultSet.add(s); |
|
394 } |
|
395 } |
|
396 return defaultSet; |
|
397 } |
|
398 |
|
399 private boolean isValidSubSet(Set<String> baseAnnoTarget, Set<String> conAnnoTarget) { |
|
400 /* |
|
401 * RULE 1: conAnnoTarget should be a subset of baseAnnoTarget |
|
402 * RULE 2: For empty @Target ({}) - annotation cannot be applied anywhere |
|
403 * - Empty sets for both is valid |
|
404 * - Empty baseTarget set is invalid with non-empty conTarget set |
|
405 * - Non-empty baseTarget set is valid with empty conTarget set |
|
406 * RULE 3: For no @Target specified - annotation can be applied to any JDK 7 targets |
|
407 * - No @Target for both is valid |
|
408 * - No @Target for baseTarget set with @Target conTarget set is valid |
|
409 * - @Target for baseTarget set with no @Target for conTarget is invalid |
|
410 */ |
|
411 |
|
412 |
|
413 /* If baseAnno has no @Target, Foo can be either applied to @Target specified for container annotation |
|
414 * else will be applicable for all default targets if no @Target is present for container annotation. |
|
415 * In both cases, the set will be a valid set with no @Target for base annotation |
|
416 */ |
|
417 if(baseAnnoTarget == null) { |
|
418 if(conAnnoTarget == null) return true; |
|
419 return !(conAnnoTarget.contains("ElementType.TYPE_USE") || conAnnoTarget.contains("ElementType.TYPE_PARAMETER")); |
|
420 } |
|
421 |
|
422 Set<String> tempBaseSet = new HashSet<>(baseAnnoTarget); |
|
423 // If BaseAnno has TYPE, then ANNOTATION_TYPE is allowed by default |
|
424 if(baseAnnoTarget.contains("ElementType.TYPE")) { |
|
425 tempBaseSet.add("ElementType.ANNOTATION_TYPE"); |
|
426 } |
|
427 |
|
428 /* |
|
429 * If containerAnno has no @Target, only valid case if baseAnnoTarget has all targets defined |
|
430 * else invalid set |
|
431 */ |
|
432 if(conAnnoTarget == null) { |
|
433 return (tempBaseSet.containsAll(getDefaultTargetSet())); |
|
434 } |
|
435 |
|
436 // At this point, neither conAnnoTarget or baseAnnoTarget are null |
|
437 if(conAnnoTarget.size() == 0) return true; |
|
438 |
|
439 // At this point, conAnnoTarget is non-empty |
|
440 if (baseAnnoTarget.size() == 0) return false; |
|
441 |
|
442 // At this point, neither conAnnoTarget or baseAnnoTarget are empty |
|
443 return tempBaseSet.containsAll(conAnnoTarget); |
|
444 } |
|
445 |
|
446 void error(String msg) { |
|
447 System.out.println("ERROR: " + msg); |
504 System.out.println("ERROR: " + msg); |
448 errors++; |
505 errors++; |
449 } |
506 } |
450 |
|
451 // Lists the start and end range for the given set of target vals |
|
452 void showGroups() { |
|
453 //Group 1: All target set combinations ( 0 to 1048575 ) including empty @Target sets => @Target({}) |
|
454 int grpEnd1 = (int)Math.pow(2, 2*targetVals.length) - 1; |
|
455 System.out.println("[Group 1]: 0 - " + grpEnd1); |
|
456 |
|
457 //Group 2: @Target not defined for base annotation ( 1048576 - 1049599 ). |
|
458 System.out.print("[Group 2]: " + (grpEnd1 + 1) + " - "); |
|
459 int grpEnd2 = grpEnd1 + 1 + (int)Math.pow(2, targetVals.length) - 1; |
|
460 System.out.println(grpEnd2); |
|
461 |
|
462 //Group 3: @Target not defined for container annotation ( 1049600 - 1050623 ). |
|
463 System.out.print("[Group 3]: " + (grpEnd2 + 1) + " - "); |
|
464 int grpEnd3 = grpEnd2 + 1 + (int)Math.pow(2, targetVals.length) - 1; |
|
465 System.out.println(grpEnd3); |
|
466 |
|
467 //Group 4: @Target not defined for both base and container annotations ( 1050624 ). |
|
468 System.out.println("[Group 4]: " + (grpEnd3 + 1)); |
|
469 } |
|
470 } |
507 } |
|
508 |