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 24import java.lang.annotation.Annotation; 25import java.util.Arrays; 26import java.util.EnumSet; 27import java.util.List; 28import java.util.Set; 29import javax.annotation.processing.*; 30import javax.lang.model.element.*; 31import javax.lang.model.type.MirroredTypeException; 32import javax.lang.model.type.TypeMirror; 33import javax.lang.model.util.Elements; 34 35public class ElementRepAnnoTester extends JavacTestingAbstractProcessor { 36 // All methods to test. 37 final EnumSet<TestMethod> ALL_TEST_METHODS = EnumSet.allOf(TestMethod.class); 38 int count = 0; 39 int error = 0; 40 41 public boolean process(Set<? extends TypeElement> annotations, 42 RoundEnvironment roundEnv) { 43 if (!roundEnv.processingOver()) { 44 List<String> superClass = Arrays.asList("A", "B", "C", "D", "E", 45 "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P"); 46 // Go through all test classes 47 for (Element element : roundEnv.getRootElements()) { 48 // For now, no testing super classes (TODO) 49 if (element.getKind() == ElementKind.CLASS 50 && !superClass.contains(element.getSimpleName().toString())) { 51 // Compare expected and actual values from methods. 52 checkAnnoValues(element, ALL_TEST_METHODS); 53 // Now, look for enclosed elements in test classes. 54 for (Element elements : element.getEnclosedElements()) { 55 // Look for Methods annotations. 56 if (elements.getKind() == ElementKind.METHOD 57 && elements.getSimpleName().toString().equals("testMethod")) { 58 checkAnnoValues(elements, ALL_TEST_METHODS); 59 } 60 // Look for Field annotations. 61 if (elements.getKind() == ElementKind.FIELD 62 && elements.getSimpleName().toString().equals("testField")) { 63 checkAnnoValues(elements, ALL_TEST_METHODS); 64 } 65 } 66 } 67 } 68 69 if (error != 0) { 70 System.out.println("Total tests : " + count); 71 System.out.println("Total test failures : " + error); 72 throw new RuntimeException(); 73 } else { 74 System.out.println("ALL TESTS PASSED. " + count); 75 } 76 } 77 return true; 78 } 79 80 enum TestMethod { 81 getAnnotation, 82 getAnnotationsByType, 83 getAllAnnotationMirrors, 84 getAnnotationMirrors 85 } 86 87 protected void checkAnnoValues(Element element, EnumSet<TestMethod> testMethods) { 88 boolean baseAnnoPresent = false; 89 boolean conAnnoPresent = false; 90 ExpectedBase eb = null; 91 ExpectedContainer ec = null; 92 // Getting the expected values to compare with. 93 eb = element.getAnnotation(ExpectedBase.class); 94 ec = element.getAnnotation(ExpectedContainer.class); 95 96 if (eb == null) { 97 System.out.println("Did not find ExpectedBase Annotation in " 98 + element.getSimpleName().toString() + ", Test will exit"); 99 throw new RuntimeException(); 100 } 101 if (ec == null) { 102 System.out.println("Did not find ExpectedContainer Annotation in " 103 + element.getSimpleName().toString() + " Test will exit"); 104 throw new RuntimeException(); 105 } 106 // Look if all test cases have ExpectedBase and ExpectedContainer values(). 107 TypeMirror valueBase = null; 108 TypeMirror valueCon = null; 109 110 try { 111 eb.value(); 112 } catch (MirroredTypeException mte) { 113 valueBase = mte.getTypeMirror(); 114 } 115 116 try { 117 ec.value(); 118 } catch (MirroredTypeException mte1) { 119 valueCon = mte1.getTypeMirror(); 120 } 121 122 String expectedBaseAnno = valueBase.toString(); 123 String expectedConAnno = valueCon.toString(); 124 125 if (!expectedBaseAnno.equals("java.lang.annotation.Annotation")) { 126 baseAnnoPresent = true; 127 } 128 if (!expectedConAnno.equalsIgnoreCase("java.lang.annotation.Annotation")) { 129 conAnnoPresent = true; 130 } 131 132 // Look into TestMethod and compare method's output with expected values. 133 for (TestMethod testMethod : testMethods) { 134 boolean isBasePass = true; 135 boolean isConPass = true; 136 137 switch (testMethod) { 138 case getAnnotation: 139 if (baseAnnoPresent) { 140 count++; 141 Annotation actualAnno = getAnnotationBase(element); 142 String expectedAnno = eb.getAnnotation(); 143 isBasePass = compareAnnotation(actualAnno, expectedAnno); 144 } 145 if (conAnnoPresent) { 146 count++; 147 Annotation actualAnno = getAnnotationContainer(element); 148 String expectedAnno = ec.getAnnotation(); 149 isConPass = compareAnnotation(actualAnno, expectedAnno); 150 } 151 if (!isBasePass || !isConPass) { 152 System.out.println("FAIL in " + element.getSimpleName() 153 + "-" + element.getKind() 154 + " method: getAnnotation(class <T>)"); 155 error++; 156 } 157 break; 158 159 case getAnnotationMirrors: 160 if (baseAnnoPresent) { 161 count++; 162 List<? extends AnnotationMirror> actualDeclAnnos = 163 element.getAnnotationMirrors(); 164 String[] expectedAnnos = eb.getAnnotationMirrors(); 165 isBasePass = compareArrVals(actualDeclAnnos, expectedAnnos); 166 } 167 if (conAnnoPresent) { 168 isConPass = true; 169 } 170 if (!isBasePass || !isConPass) { 171 System.out.println("FAIL in " + element.getSimpleName() 172 + "-" + element.getKind() 173 + " method: getAnnotationMirrors()"); 174 error++; 175 } 176 break; 177 178 case getAnnotationsByType: 179 if (baseAnnoPresent) { 180 count++; 181 Annotation[] actualAnnosArgs = getAnnotationsBase(element); 182 String[] expectedAnnos = eb.getAnnotationsByType(); 183 isBasePass = compareArrVals(actualAnnosArgs, expectedAnnos); 184 } 185 if (conAnnoPresent) { 186 count++; 187 Annotation[] actualAnnosArgs = getAnnotationsContainer(element); 188 String[] expectedAnnos = ec.getAnnotationsByType(); 189 isConPass = compareArrVals(actualAnnosArgs, expectedAnnos); 190 } 191 if (!isBasePass || !isConPass) { 192 System.out.println("FAIL in " + element.getSimpleName() 193 + "-" + element.getKind() 194 + " method: getAnnotationsByType(class <T>)"); 195 error++; 196 } 197 break; 198 199 case getAllAnnotationMirrors: 200 if (baseAnnoPresent) { 201 count++; 202 Elements elements = processingEnv.getElementUtils(); 203 List<? extends AnnotationMirror> actualAnnosMirrors = 204 elements.getAllAnnotationMirrors(element); 205 String[] expectedAnnos = eb.getAllAnnotationMirrors(); 206 isBasePass = compareArrVals(actualAnnosMirrors, expectedAnnos); 207 } 208 if (conAnnoPresent) { 209 isConPass = true; 210 } 211 if (!isBasePass || !isConPass) { 212 System.out.println("FAIL in " + element.getSimpleName() 213 + "-" + element.getKind() 214 + " method: getAllAnnotationMirrors(e)"); 215 error++; 216 } 217 break; 218 } 219 } 220 } 221 // Sort tests to be run with different anno processors. 222 final List<String> singularAnno = Arrays.asList( 223 "SingularBasicTest" 224 ); 225 final List<String> singularInheritedAnno = Arrays.asList( 226 "SingularInheritedATest" 227 ); 228 final List<String> repeatableAnno = Arrays.asList( 229 "RepeatableBasicTest", 230 "MixRepeatableAndOfficialContainerBasicTest", 231 "OfficialContainerBasicTest", 232 "RepeatableOfficialContainerBasicTest" 233 ); 234 final List<String> repeatableInheritedAnno = Arrays.asList( 235 "RepeatableInheritedTest", 236 "RepeatableOverrideATest", 237 "RepeatableOverrideBTest", 238 "OfficialContainerInheritedTest", 239 "MixRepeatableAndOfficialContainerInheritedA1Test", 240 "MixRepeatableAndOfficialContainerInheritedB1Test", 241 "MixRepeatableAndOfficialContainerInheritedA2Test", 242 "MixRepeatableAndOfficialContainerInheritedB2Test" 243 ); 244 final List<String> repeatableContainerInheritedAnno = Arrays.asList( 245 "RepeatableOfficialContainerInheritedTest" 246 ); 247 final List<String> unofficialAnno = Arrays.asList( 248 "UnofficialContainerBasicTest", 249 "MixSingularAndUnofficialContainerBasicTest" 250 ); 251 final List<String> unofficialInheritedAnno = Arrays.asList( 252 "UnofficialContainerInheritedTest", 253 "SingularInheritedBTest", 254 "MixSingularAndUnofficialContainerInheritedA1Test", 255 "MixSingularAndUnofficialContainerInheritedB1Test", 256 "MixSingularAndUnofficialContainerInheritedA2Test", 257 "MixSingularAndUnofficialContainerInheritedB2Test" 258 ); 259 // Respective container annotation for the different test cases to test. 260 final List<String> repeatableAnnoContainer = repeatableAnno; 261 final List<String> repeatableInheritedAnnoContainer = repeatableInheritedAnno; 262 final List<String> repeatableContainerInheritedAnnoContainer = 263 repeatableContainerInheritedAnno; 264 final List<String> unofficialAnnoContainer = unofficialAnno; 265 final List<String> unofficialInheritedAnnoContainer = unofficialInheritedAnno; 266 267 // Variables to verify if all test cases have been run. 268 private Annotation specialAnno = new Annotation() { 269 @Override 270 public Class annotationType() { 271 return null; 272 } 273 }; 274 private Annotation[] specialAnnoArray = new Annotation[1]; 275 private List<AnnotationMirror> specialAnnoMirrors = 276 new java.util.ArrayList<AnnotationMirror>(2); 277 278 private Annotation getAnnotationBase(Element e) { 279 Annotation actualAnno = specialAnno; 280 281 if (singularAnno.contains( 282 e.getEnclosingElement().toString()) 283 || singularAnno.contains( 284 e.getSimpleName().toString()) 285 || unofficialAnno.contains( 286 e.getEnclosingElement().toString()) 287 || unofficialAnno.contains( 288 e.getSimpleName().toString())) { 289 actualAnno = e.getAnnotation(Foo.class); 290 } 291 if (singularInheritedAnno.contains( 292 e.getEnclosingElement().toString()) 293 || singularInheritedAnno.contains( 294 e.getSimpleName().toString()) 295 || unofficialInheritedAnno.contains( 296 e.getEnclosingElement().toString()) 297 || unofficialInheritedAnno.contains( 298 e.getSimpleName().toString())) { 299 actualAnno = e.getAnnotation(FooInherited.class); 300 } 301 if (repeatableAnno.contains( 302 e.getEnclosingElement().toString()) 303 || repeatableAnno.contains( 304 e.getSimpleName().toString())) { 305 actualAnno = e.getAnnotation(Bar.class); 306 } 307 if (repeatableInheritedAnno.contains( 308 e.getEnclosingElement().toString()) 309 || repeatableInheritedAnno.contains( 310 e.getSimpleName().toString())) { 311 actualAnno = e.getAnnotation(BarInherited.class); 312 } 313 if (repeatableContainerInheritedAnno.contains( 314 e.getEnclosingElement().toString()) 315 || repeatableContainerInheritedAnno.contains( 316 e.getSimpleName().toString())) { 317 actualAnno = e.getAnnotation(BarInheritedContainer.class); 318 } 319 return actualAnno; 320 } 321 322 private Annotation getAnnotationContainer(Element e) { 323 Annotation actualAnno = specialAnno; 324 325 if (repeatableAnnoContainer.contains( 326 e.getEnclosingElement().toString()) 327 || repeatableAnnoContainer.contains( 328 e.getSimpleName().toString())) { 329 actualAnno = e.getAnnotation(BarContainer.class); 330 } 331 if (repeatableInheritedAnnoContainer.contains( 332 e.getEnclosingElement().toString()) 333 || repeatableInheritedAnnoContainer.contains( 334 e.getSimpleName().toString())) { 335 actualAnno = e.getAnnotation(BarInheritedContainer.class); 336 } 337 if (repeatableContainerInheritedAnnoContainer.contains( 338 e.getEnclosingElement().toString()) 339 || repeatableContainerInheritedAnnoContainer.contains( 340 e.getSimpleName().toString())) { 341 actualAnno = e.getAnnotation(BarInheritedContainerContainer.class); 342 } 343 if (unofficialAnnoContainer.contains( 344 e.getEnclosingElement().toString()) 345 || unofficialAnnoContainer.contains( 346 e.getSimpleName().toString())) { 347 actualAnno = e.getAnnotation(UnofficialContainer.class); 348 } 349 if (unofficialInheritedAnnoContainer.contains( 350 e.getEnclosingElement().toString()) 351 || unofficialInheritedAnnoContainer.contains( 352 e.getSimpleName().toString())) { 353 actualAnno = e.getAnnotation(UnofficialInheritedContainer.class); 354 } 355 return actualAnno; 356 } 357 358 private Annotation[] getAnnotationsBase(Element e) { 359 Annotation[] actualAnnosArgs = specialAnnoArray; 360 361 if (singularAnno.contains( 362 e.getEnclosingElement().toString()) 363 || singularAnno.contains( 364 e.getSimpleName().toString()) 365 || unofficialAnno.contains( 366 e.getEnclosingElement().toString()) 367 || unofficialAnno.contains( 368 e.getSimpleName().toString())) { 369 actualAnnosArgs = e.getAnnotationsByType(Foo.class); 370 } 371 if (singularInheritedAnno.contains( 372 e.getEnclosingElement().toString()) 373 || singularInheritedAnno.contains( 374 e.getSimpleName().toString()) 375 || unofficialInheritedAnno.contains( 376 e.getEnclosingElement().toString()) 377 || unofficialInheritedAnno.contains( 378 e.getSimpleName().toString())) { 379 actualAnnosArgs = e.getAnnotationsByType(FooInherited.class); 380 } 381 if (repeatableAnno.contains( 382 e.getEnclosingElement().toString()) 383 || repeatableAnno.contains( 384 e.getSimpleName().toString())) { 385 actualAnnosArgs = e.getAnnotationsByType(Bar.class); 386 } 387 if (repeatableInheritedAnno.contains( 388 e.getEnclosingElement().toString()) 389 || repeatableInheritedAnno.contains( 390 e.getSimpleName().toString())) { 391 actualAnnosArgs = e.getAnnotationsByType(BarInherited.class); 392 } 393 if (repeatableContainerInheritedAnno.contains( 394 e.getEnclosingElement().toString()) 395 || repeatableContainerInheritedAnno.contains( 396 e.getSimpleName().toString())) { 397 actualAnnosArgs = e.getAnnotationsByType(BarInheritedContainer.class); 398 } 399 return actualAnnosArgs; 400 } 401 402 private Annotation[] getAnnotationsContainer(Element e) { 403 Annotation[] actualAnnosArgs = specialAnnoArray; 404 405 if (repeatableAnnoContainer.contains( 406 e.getEnclosingElement().toString()) 407 || repeatableAnnoContainer.contains( 408 e.getSimpleName().toString())) { 409 actualAnnosArgs = e.getAnnotationsByType(BarContainer.class); 410 } 411 if (repeatableInheritedAnnoContainer.contains( 412 e.getEnclosingElement().toString()) 413 || repeatableInheritedAnnoContainer.contains( 414 e.getSimpleName().toString())) { 415 actualAnnosArgs = e.getAnnotationsByType(BarInheritedContainer.class); 416 } 417 if (repeatableContainerInheritedAnnoContainer.contains( 418 e.getEnclosingElement().toString()) 419 || repeatableContainerInheritedAnnoContainer.contains( 420 e.getSimpleName().toString())) { 421 actualAnnosArgs = e.getAnnotationsByType(BarInheritedContainerContainer.class); 422 } 423 if (unofficialAnnoContainer.contains( 424 e.getEnclosingElement().toString()) 425 || unofficialAnnoContainer.contains( 426 e.getSimpleName().toString())) { 427 actualAnnosArgs = e.getAnnotationsByType(UnofficialContainer.class); 428 } 429 if (unofficialInheritedAnnoContainer.contains( 430 e.getEnclosingElement().toString()) 431 || unofficialInheritedAnnoContainer.contains( 432 e.getSimpleName().toString())) { 433 actualAnnosArgs = e.getAnnotationsByType(UnofficialInheritedContainer.class); 434 } 435 return actualAnnosArgs; 436 } 437 438 // Array comparison: Length should be same and all expected values 439 // should be present in actualAnnos[]. 440 private boolean compareArrVals(Annotation[] actualAnnos, String[] expectedAnnos) { 441 // Look if test case was run. 442 if (actualAnnos == specialAnnoArray) { 443 return false; // no testcase matches 444 } 445 if (actualAnnos.length != expectedAnnos.length) { 446 System.out.println("Length not same. " 447 + " actualAnnos length = " + actualAnnos.length 448 + " expectedAnnos length = " + expectedAnnos.length); 449 printArrContents(actualAnnos); 450 printArrContents(expectedAnnos); 451 return false; 452 } else { 453 int i = 0; 454 String[] actualArr = new String[actualAnnos.length]; 455 for (Annotation a : actualAnnos) { 456 actualArr[i++] = a.toString(); 457 } 458 List<String> actualList = Arrays.asList(actualArr); 459 List<String> expectedList = Arrays.asList(expectedAnnos); 460 461 if (!actualList.containsAll(expectedList)) { 462 System.out.println("Array values are not same"); 463 printArrContents(actualAnnos); 464 printArrContents(expectedAnnos); 465 return false; 466 } 467 } 468 return true; 469 } 470 471 // Array comparison: Length should be same and all expected values 472 // should be present in actualAnnos List<?>. 473 private boolean compareArrVals(List<? extends AnnotationMirror> actualAnnos, 474 String[] expectedAnnos) { 475 // Look if test case was run. 476 if (actualAnnos == specialAnnoMirrors) { 477 return false; //no testcase run 478 } 479 if (actualAnnos.size() != expectedAnnos.length) { 480 System.out.println("Length not same. " 481 + " actualAnnos length = " + actualAnnos.size() 482 + " expectedAnnos length = " + expectedAnnos.length); 483 printArrContents(actualAnnos); 484 printArrContents(expectedAnnos); 485 return false; 486 } else { 487 int i = 0; 488 String[] actualArr = new String[actualAnnos.size()]; 489 String annoTypeName = ""; 490 for (AnnotationMirror annotationMirror : actualAnnos) { 491 if (annotationMirror.getAnnotationType().toString().contains("Expected")) { 492 annoTypeName = annotationMirror.getAnnotationType().toString(); 493 } else { 494 annoTypeName = annotationMirror.toString(); 495 } 496 actualArr[i++] = annoTypeName; 497 } 498 List<String> actualList = Arrays.asList(actualArr); 499 List<String> expectedList = Arrays.asList(expectedAnnos); 500 501 if (!actualList.containsAll(expectedList)) { 502 System.out.println("Array values are not same"); 503 printArrContents(actualAnnos); 504 printArrContents(expectedAnnos); 505 return false; 506 } 507 } 508 return true; 509 } 510 511 private void printArrContents(Annotation[] actualAnnos) { 512 for (Annotation a : actualAnnos) { 513 System.out.println("actualAnnos values = " + a); 514 } 515 } 516 517 private void printArrContents(String[] expectedAnnos) { 518 for (String s : expectedAnnos) { 519 System.out.println("expectedAnnos values = " + s); 520 } 521 } 522 523 private void printArrContents(List<? extends AnnotationMirror> actualAnnos) { 524 for (AnnotationMirror annotationMirror : actualAnnos) { 525 System.out.println("actualAnnos values = " + annotationMirror); 526 } 527 } 528 529 private boolean compareAnnotation(Annotation actualAnno, String expectedAnno) { 530 //String actualAnnoName = ""; 531 boolean isSame = true; 532 // Look if test case was run. 533 if (actualAnno == specialAnno) { 534 return false; //no testcase run 535 } 536 if (actualAnno != null) { 537 if (!actualAnno.toString().equalsIgnoreCase(expectedAnno)) { 538 System.out.println("Anno did not match. " 539 + " expectedAnno = " + expectedAnno 540 + " actualAnno = " + actualAnno); 541 isSame = false; 542 } else { 543 isSame = true; 544 } 545 } else { 546 if (expectedAnno.compareToIgnoreCase("null") == 0) { 547 isSame = true; 548 } else { 549 System.out.println("Actual anno is null"); 550 isSame = false; 551 } 552 } 553 return isSame; 554 } 555} 556