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