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