1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/test/tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java Thu Feb 07 20:47:06 2013 -0800 1.3 @@ -0,0 +1,469 @@ 1.4 +/* 1.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + */ 1.26 + 1.27 +/** 1.28 + * @test 1.29 + * @bug 7195131 1.30 + * @author sogoel 1.31 + * @summary Combo test for all possible combinations for Target values 1.32 + * @build Helper 1.33 + * @compile TargetAnnoCombo.java TestCaseGenerator.java 1.34 + * @run main TargetAnnoCombo 1.35 + */ 1.36 + 1.37 +import java.io.IOException; 1.38 +import java.util.ArrayList; 1.39 +import java.util.Arrays; 1.40 +import java.util.HashSet; 1.41 +import java.util.Set; 1.42 +import javax.tools.Diagnostic; 1.43 +import javax.tools.DiagnosticCollector; 1.44 +import javax.tools.JavaFileObject; 1.45 + 1.46 +/* 1.47 + * TargetAnnoCombo gets a list of test case numbers using TestCaseGenerator. 1.48 + * For each of the test case number, @Target sets for base and container annotations 1.49 + * are determined, source files are generated, compiled, and the result is verified 1.50 + * based on if the @Target set for base and container is a positive or negative combination. 1.51 + * 1.52 + * @Target sets for base and container annotations are determined using a bit mapping of 1.53 + * 10 ElementType enum constants defined in JDK8. 1.54 + * 1.55 + * Bit Target value 1.56 + * 0 "ElementType.ANNOTATION_TYPE" 1.57 + * 1 "ElementType.CONSTRUCTOR" 1.58 + * 2 "ElementType.FIELD" 1.59 + * 3 "ElementType.LOCAL_VARIABLE" 1.60 + * 4 "ElementType.METHOD" 1.61 + * 5 "ElementType.TYPE" 1.62 + * 6 "ElementType.PARAMETER" 1.63 + * 7 "ElementType.PACKAGE" 1.64 + * 8 "ElementType.TYPE_USE" 1.65 + * 9 "ElementType.TYPE_PARAMETER" 1.66 + * 1.67 + * Group 1: 1.68 + * 20 bits mapping, representing a test case number, is used for all target set 1.69 + * combinations ( 0 to 1048575 ) including empty @Target sets => @Target({}). 1.70 + * From this 20 bits, 10 bits are for base followed by 10 bits for container 1.71 + * where each bit maps to an ElementType enum constant defined in JDK8. 1.72 + * 1.73 + * Examples: 1.74 + * Test case number: 4, binary: 100 => container=100, base=[], container=["ElementType.FIELD"] 1.75 + * Test case number: 1003575, binary: 11110101000000110111 => base=1111010100, container=0000110111; 1.76 + * base=["ElementType.PARAMETER", "ElementType.TYPE_USE", "ElementType.METHOD", "ElementType.FIELD", "ElementType.PACKAGE", "ElementType.TYPE_PARAMETER"], 1.77 + * container=["ElementType.TYPE", "ElementType.METHOD", "ElementType.ANNOTATION_TYPE", "ElementType.CONSTRUCTOR", "ElementType.FIELD"] 1.78 + * 1.79 + * In the following groups, no @Target set is represented by null. 1.80 + * Group 2: 1.81 + * @Target is not defined on base. 1.82 + * Target sets for container are determined using the 10-bit binary number 1.83 + * resulting in 1024 test cases, mapping them to test case numbers from 1.84 + * 1048576 to (1048576 + 1023) => 1048576 to 1049599. 1.85 + * 1.86 + * Example: 1.87 + * Test case number: 1048587 => 1048587 - 1048576 = test case 11 in Group 2, binary: 1011 => 1.88 + * base = null, 1.89 + * container = ["ElementType.ANNOTATION_TYPE","ElementType.CONSTRUCTOR","ElementType.LOCAL_VARIABLE"] 1.90 + * 1.91 + * Group 3: 1.92 + * @Target is not defined on container 1.93 + * Target sets for base are determined using the 10-bit binary number 1.94 + * resulting in 1024 test cases, mapping them to test case numbers from 1.95 + * 1049600 to (1049600 + 1023) => 1049600 to 1050623. 1.96 + * 1.97 + * Example: 1.98 + * Test case number: 1049708 => 1049708 - 1049600 = test case 108 in Group 3, binary: 1101100 => 1.99 + * base = ["ElementType.FIELD", "ElementType.LOCAL_VARIABLE", "ElementType.TYPE", "ElementType.PARAMETER"], 1.100 + * container = null 1.101 + * 1.102 + * For the above group, test case number: 1049855 gives compiler error, JDK-8006547 filed 1.103 + * 1.104 + * Group 4: 1.105 + * @Target not defined for both base and container annotations. 1.106 + * 1.107 + * This is the last test and corresponds to test case number 1050624. base=null, container=null 1.108 + * 1.109 + * Examples to run this test: 1.110 + * 1. Run a specific test case number: 1.111 + * ${JTREG} -DTestCaseNum=10782 -samevm -jdk:${JAVA_TEST} -reportDir ${REPORT} -workDir ${WORK} TargetAnnoCombo.java 1.112 + * 2. Run specific number of tests: 1.113 + * ${JTREG} -DNumberOfTests=4 -samevm -jdk:${JAVA_TEST} -reportDir ${REPORT} -workDir ${WORK} TargetAnnoCombo.java 1.114 + * 3. Run specific number of tests with a seed: 1.115 + * ${JTREG} -DNumberOfTests=4 -DTestSeed=-972894659 -samevm -jdk:${JAVA_TEST} -reportDir ${REPORT} -workDir ${WORK} TargetAnnoCombo.java 1.116 + * 4. Run tests in default mode (number of tests = 1000): 1.117 + * ${JTREG} -DTestMode=DEFAULT -samevm -jdk:${JAVA_TEST} -reportDir ${REPORT} -workDir ${WORK} TargetAnnoCombo.java 1.118 + * 5. Run all tests (FULL mode): 1.119 + * ${JTREG} -DTestMode=FULL -samevm -jdk:${JAVA_TEST} -reportDir ${REPORT} -workDir ${WORK} TargetAnnoCombo.java 1.120 + * 1.121 + */ 1.122 + 1.123 +public class TargetAnnoCombo { 1.124 + int errors = 0; 1.125 + static final String TESTPKG = "testpkg"; 1.126 + /* 1.127 + * Set it to true to get more debug information including base and 1.128 + * container target sets for a given test case number 1.129 + */ 1.130 + static final boolean DEBUG = false; 1.131 + 1.132 + // JDK 5/6/7/8 Targets 1.133 + static final String[] targetVals = {"ElementType.ANNOTATION_TYPE", 1.134 + "ElementType.CONSTRUCTOR", "ElementType.FIELD", 1.135 + "ElementType.LOCAL_VARIABLE", "ElementType.METHOD", 1.136 + "ElementType.TYPE", "ElementType.PARAMETER", 1.137 + "ElementType.PACKAGE", "ElementType.TYPE_USE", 1.138 + "ElementType.TYPE_PARAMETER"}; 1.139 + 1.140 + // TYPE_USE and TYPE_PARAMETER (added in JDK8) are not part of default Target set 1.141 + static final int DEFAULT_TARGET_CNT = 8; 1.142 + 1.143 + public static void main(String args[]) throws Exception { 1.144 + 1.145 + /* maxTestNum = (base and container combinations of targetVals elems [0 - 1048575 combos]) 1.146 + * + (combinations where base or container has no Target [1024 combos]) 1.147 + * + (no -1 even though 1st test is number 0 as last test is where both 1.148 + * base and container have no target) 1.149 + */ 1.150 + 1.151 + int maxTestNum = (int)Math.pow(2, 2*targetVals.length) + 2*(int)Math.pow(2, targetVals.length); 1.152 + TestCaseGenerator tcg = new TestCaseGenerator(maxTestNum); 1.153 + TargetAnnoCombo tac = new TargetAnnoCombo(); 1.154 + 1.155 + int testCtr = 0; 1.156 + int testCase = -1; 1.157 + while ( (testCase=tcg.getNextTestCase()) != -1 ) { 1.158 + tac.executeTestCase(testCase, maxTestNum); 1.159 + testCtr++; 1.160 + } 1.161 + 1.162 + System.out.println("Total tests run: " + testCtr); 1.163 + if (tac.errors > 0) 1.164 + throw new Exception(tac.errors + " errors found"); 1.165 + } 1.166 + 1.167 + /* 1.168 + * For given testCase, determine the base and container annotation Target sets, 1.169 + * get if testCase should compile, get test source file(s), get compilation result and verify. 1.170 + * 1.171 + */ 1.172 + private void executeTestCase(int testCase, int maxTestNum) { 1.173 + 1.174 + // Determine base and container annotation Target sets for the testCase 1.175 + Set<String> baseAnnoTarget = null; 1.176 + Set<String> conAnnoTarget = null; 1.177 + 1.178 + //Number of base and container combinations [0 - 1048575 combos] 1.179 + int baseContCombos = (int)Math.pow(2, 2*targetVals.length); 1.180 + //Number of either base or container combinations when one of them has no @Target [1024 combos] 1.181 + int targetValsCombos = (int)Math.pow(2, targetVals.length); 1.182 + 1.183 + if (testCase >= baseContCombos) { 1.184 + //Base annotation do not have @Target 1.185 + if (testCase < baseContCombos + targetValsCombos) { 1.186 + baseAnnoTarget = null; 1.187 + conAnnoTarget = getSetFromBitVec(Integer.toBinaryString(testCase - baseContCombos)); 1.188 + } else if (testCase < baseContCombos + 2*targetValsCombos) { 1.189 + //Container annotation do not have @Target 1.190 + baseAnnoTarget = getSetFromBitVec(Integer.toBinaryString(testCase - baseContCombos - targetValsCombos)); 1.191 + conAnnoTarget = null; 1.192 + } else { 1.193 + //Both Base and Container annotation do not have @Target 1.194 + baseAnnoTarget = null; 1.195 + conAnnoTarget = null; 1.196 + } 1.197 + } else { 1.198 + //TestCase number is represented as 10-bits for base followed by container bits 1.199 + String bin = Integer.toBinaryString(testCase); 1.200 + String base="", cont=bin; 1.201 + if (bin.length() > targetVals.length){ 1.202 + base = bin.substring(0, bin.length() - targetVals.length); 1.203 + cont = bin.substring(bin.length() - targetVals.length,bin.length()); 1.204 + } 1.205 + baseAnnoTarget = getSetFromBitVec(base); 1.206 + conAnnoTarget = getSetFromBitVec(cont); 1.207 + } 1.208 + 1.209 + debugPrint("Test case number = " + testCase + " => binary = " + Integer.toBinaryString(testCase)); 1.210 + debugPrint(" => baseAnnoTarget = " + baseAnnoTarget); 1.211 + debugPrint(" => containerAnnoTarget = " + conAnnoTarget); 1.212 + 1.213 + // Determine if a testCase should compile or not 1.214 + String className = "TC" + testCase; 1.215 + boolean shouldCompile = isValidSubSet(baseAnnoTarget, conAnnoTarget); 1.216 + 1.217 + // Get test source file(s) 1.218 + Iterable<? extends JavaFileObject> files = getFileList(className, baseAnnoTarget, 1.219 + conAnnoTarget, shouldCompile); 1.220 + 1.221 + // Get result of compiling test src file(s) 1.222 + boolean result = getCompileResult(className, shouldCompile, files); 1.223 + 1.224 + // List test src code if test fails 1.225 + if(!result) { 1.226 + System.out.println("FAIL: Test " + testCase); 1.227 + try { 1.228 + for (JavaFileObject f: files) { 1.229 + System.out.println("File: " + f.getName() + "\n" + f.getCharContent(true)); 1.230 + } 1.231 + } catch (IOException ioe) { 1.232 + System.out.println("Exception: " + ioe); 1.233 + } 1.234 + } else { 1.235 + debugPrint("PASS: Test " + testCase); 1.236 + } 1.237 + } 1.238 + 1.239 + // Get a Set<String> based on bits that are set to 1 1.240 + public Set<String> getSetFromBitVec(String bitVec) { 1.241 + Set<String> ret = new HashSet<>(); 1.242 + char[] bit = bitVec.toCharArray(); 1.243 + for (int i=bit.length-1, j=0; i>=0; i--, j++){ 1.244 + if (bit[i] == '1') { 1.245 + ret.add(targetVals[j]); 1.246 + } 1.247 + } 1.248 + return ret; 1.249 + } 1.250 + 1.251 + // Compile the test source file(s) and return test result 1.252 + private boolean getCompileResult(String className, boolean shouldCompile, 1.253 + Iterable<? extends JavaFileObject> files) { 1.254 + 1.255 + DiagnosticCollector<JavaFileObject> diagnostics = 1.256 + new DiagnosticCollector<JavaFileObject>(); 1.257 + Helper.compileCode(diagnostics, files); 1.258 + 1.259 + // Test case pass or fail 1.260 + boolean ok = false; 1.261 + 1.262 + String errMesg = ""; 1.263 + int numDiags = diagnostics.getDiagnostics().size(); 1.264 + 1.265 + if (numDiags == 0) { 1.266 + if (shouldCompile) { 1.267 + debugPrint("Test passed, compiled as expected."); 1.268 + ok = true; 1.269 + } else { 1.270 + errMesg = "Test failed, compiled unexpectedly."; 1.271 + ok = false; 1.272 + } 1.273 + } else { 1.274 + if (shouldCompile) { 1.275 + // did not compile 1.276 + errMesg = "Test failed, did not compile."; 1.277 + ok = false; 1.278 + } else { 1.279 + // Error in compilation as expected 1.280 + String expectedErrKey = "compiler.err.invalid.repeatable." + 1.281 + "annotation.incompatible.target"; 1.282 + for (Diagnostic<?> d : diagnostics.getDiagnostics()) { 1.283 + if((d.getKind() == Diagnostic.Kind.ERROR) && 1.284 + d.getCode().contains(expectedErrKey)) { 1.285 + // Error message as expected 1.286 + debugPrint("Error message as expected."); 1.287 + ok = true; 1.288 + break; 1.289 + } else { 1.290 + // error message is incorrect 1.291 + ok = false; 1.292 + } 1.293 + } 1.294 + if (!ok) { 1.295 + errMesg = "Incorrect error received when compiling " + 1.296 + className + ", expected: " + expectedErrKey; 1.297 + } 1.298 + } 1.299 + } 1.300 + 1.301 + if(!ok) { 1.302 + error(errMesg); 1.303 + for (Diagnostic<?> d : diagnostics.getDiagnostics()) 1.304 + System.out.println(" Diags: " + d); 1.305 + } 1.306 + return ok; 1.307 + } 1.308 + 1.309 + private void debugPrint(String string) { 1.310 + if(DEBUG) 1.311 + System.out.println(string); 1.312 + } 1.313 + 1.314 + // Create src code and corresponding JavaFileObjects 1.315 + private Iterable<? extends JavaFileObject> getFileList(String className, 1.316 + Set<String> baseAnnoTarget, Set<String> conAnnoTarget, 1.317 + boolean shouldCompile) { 1.318 + 1.319 + String srcContent = ""; 1.320 + String pkgInfoContent = ""; 1.321 + String template = Helper.template; 1.322 + String baseTarget = "", conTarget = ""; 1.323 + 1.324 + String target = Helper.ContentVars.TARGET.getVal(); 1.325 + if(baseAnnoTarget != null) { 1.326 + baseTarget = target.replace("#VAL", baseAnnoTarget.toString()) 1.327 + .replace("[", "{").replace("]", "}"); 1.328 + } 1.329 + if(conAnnoTarget != null) { 1.330 + conTarget = target.replace("#VAL", conAnnoTarget.toString()) 1.331 + .replace("[", "{").replace("]", "}"); 1.332 + } 1.333 + 1.334 + String annoData = Helper.ContentVars.IMPORTSTMTS.getVal() + 1.335 + conTarget + 1.336 + Helper.ContentVars.CONTAINER.getVal() + 1.337 + baseTarget + 1.338 + Helper.ContentVars.REPEATABLE.getVal() + 1.339 + Helper.ContentVars.BASE.getVal(); 1.340 + 1.341 + JavaFileObject pkgInfoFile = null; 1.342 + 1.343 + /* 1.344 + * If shouldCompile = true and no @Target is specified for container annotation, 1.345 + * then all 8 ElementType enum constants are applicable as targets for 1.346 + * container annotation. 1.347 + */ 1.348 + if(shouldCompile && conAnnoTarget == null) { 1.349 + //conAnnoTarget = new HashSet<String>(Arrays.asList(targetVals)); 1.350 + conAnnoTarget = getDefaultTargetSet(); 1.351 + } 1.352 + 1.353 + if(shouldCompile) { 1.354 + boolean isPkgCasePresent = new ArrayList<String>(conAnnoTarget).contains("ElementType.PACKAGE"); 1.355 + String repeatableAnno = Helper.ContentVars.BASEANNO.getVal() + " " + Helper.ContentVars.BASEANNO.getVal(); 1.356 + for(String s: conAnnoTarget) { 1.357 + s = s.replace("ElementType.",""); 1.358 + String replaceStr = "/*"+s+"*/"; 1.359 + if(s.equalsIgnoreCase("PACKAGE")) { 1.360 + //Create packageInfo file 1.361 + String pkgInfoName = TESTPKG + "." + "package-info"; 1.362 + pkgInfoContent = repeatableAnno + "\npackage " + TESTPKG + ";" + annoData; 1.363 + pkgInfoFile = Helper.getFile(pkgInfoName, pkgInfoContent); 1.364 + } else { 1.365 + template = template.replace(replaceStr, repeatableAnno); 1.366 + //srcContent = template.replace("#ClassName",className); 1.367 + if(!isPkgCasePresent) { 1.368 + srcContent = template.replace("/*ANNODATA*/", annoData).replace("#ClassName",className); 1.369 + } else { 1.370 + replaceStr = "/*PACKAGE*/"; 1.371 + srcContent = template.replace(replaceStr, "package " + TESTPKG + ";") 1.372 + .replace("#ClassName", className); 1.373 + } 1.374 + } 1.375 + } 1.376 + } else { 1.377 + // For invalid cases, compilation should fail at declaration site 1.378 + template = "class #ClassName {}"; 1.379 + srcContent = annoData + template.replace("#ClassName",className); 1.380 + } 1.381 + JavaFileObject srcFile = Helper.getFile(className, srcContent); 1.382 + Iterable<? extends JavaFileObject> files = null; 1.383 + if(pkgInfoFile != null) 1.384 + files = Arrays.asList(pkgInfoFile,srcFile); 1.385 + else 1.386 + files = Arrays.asList(srcFile); 1.387 + return files; 1.388 + } 1.389 + 1.390 + private Set<String> getDefaultTargetSet() { 1.391 + Set<String> defaultSet = new HashSet<>(); 1.392 + int ctr = 0; 1.393 + for(String s : targetVals) { 1.394 + if(ctr++ < DEFAULT_TARGET_CNT) { 1.395 + defaultSet.add(s); 1.396 + } 1.397 + } 1.398 + return defaultSet; 1.399 + } 1.400 + 1.401 + private boolean isValidSubSet(Set<String> baseAnnoTarget, Set<String> conAnnoTarget) { 1.402 + /* 1.403 + * RULE 1: conAnnoTarget should be a subset of baseAnnoTarget 1.404 + * RULE 2: For empty @Target ({}) - annotation cannot be applied anywhere 1.405 + * - Empty sets for both is valid 1.406 + * - Empty baseTarget set is invalid with non-empty conTarget set 1.407 + * - Non-empty baseTarget set is valid with empty conTarget set 1.408 + * RULE 3: For no @Target specified - annotation can be applied to any JDK 7 targets 1.409 + * - No @Target for both is valid 1.410 + * - No @Target for baseTarget set with @Target conTarget set is valid 1.411 + * - @Target for baseTarget set with no @Target for conTarget is invalid 1.412 + */ 1.413 + 1.414 + 1.415 + /* If baseAnno has no @Target, Foo can be either applied to @Target specified for container annotation 1.416 + * else will be applicable for all default targets if no @Target is present for container annotation. 1.417 + * In both cases, the set will be a valid set with no @Target for base annotation 1.418 + */ 1.419 + if(baseAnnoTarget == null) { 1.420 + if(conAnnoTarget == null) return true; 1.421 + return !(conAnnoTarget.contains("ElementType.TYPE_USE") || conAnnoTarget.contains("ElementType.TYPE_PARAMETER")); 1.422 + } 1.423 + 1.424 + Set<String> tempBaseSet = new HashSet<>(baseAnnoTarget); 1.425 + // If BaseAnno has TYPE, then ANNOTATION_TYPE is allowed by default 1.426 + if(baseAnnoTarget.contains("ElementType.TYPE")) { 1.427 + tempBaseSet.add("ElementType.ANNOTATION_TYPE"); 1.428 + } 1.429 + 1.430 + /* 1.431 + * If containerAnno has no @Target, only valid case if baseAnnoTarget has all targets defined 1.432 + * else invalid set 1.433 + */ 1.434 + if(conAnnoTarget == null) { 1.435 + return (tempBaseSet.containsAll(getDefaultTargetSet())); 1.436 + } 1.437 + 1.438 + // At this point, neither conAnnoTarget or baseAnnoTarget are null 1.439 + if(conAnnoTarget.size() == 0) return true; 1.440 + 1.441 + // At this point, conAnnoTarget is non-empty 1.442 + if (baseAnnoTarget.size() == 0) return false; 1.443 + 1.444 + // At this point, neither conAnnoTarget or baseAnnoTarget are empty 1.445 + return tempBaseSet.containsAll(conAnnoTarget); 1.446 + } 1.447 + 1.448 + void error(String msg) { 1.449 + System.out.println("ERROR: " + msg); 1.450 + errors++; 1.451 + } 1.452 + 1.453 + // Lists the start and end range for the given set of target vals 1.454 + void showGroups() { 1.455 + //Group 1: All target set combinations ( 0 to 1048575 ) including empty @Target sets => @Target({}) 1.456 + int grpEnd1 = (int)Math.pow(2, 2*targetVals.length) - 1; 1.457 + System.out.println("[Group 1]: 0 - " + grpEnd1); 1.458 + 1.459 + //Group 2: @Target not defined for base annotation ( 1048576 - 1049599 ). 1.460 + System.out.print("[Group 2]: " + (grpEnd1 + 1) + " - "); 1.461 + int grpEnd2 = grpEnd1 + 1 + (int)Math.pow(2, targetVals.length) - 1; 1.462 + System.out.println(grpEnd2); 1.463 + 1.464 + //Group 3: @Target not defined for container annotation ( 1049600 - 1050623 ). 1.465 + System.out.print("[Group 3]: " + (grpEnd2 + 1) + " - "); 1.466 + int grpEnd3 = grpEnd2 + 1 + (int)Math.pow(2, targetVals.length) - 1; 1.467 + System.out.println(grpEnd3); 1.468 + 1.469 + //Group 4: @Target not defined for both base and container annotations ( 1050624 ). 1.470 + System.out.println("[Group 4]: " + (grpEnd3 + 1)); 1.471 + } 1.472 +}