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