test/tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java

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

mercurial