test/tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java

Thu, 23 Jan 2014 14:09:29 +0100

author
jfranck
date
Thu, 23 Jan 2014 14:09:29 +0100
changeset 2250
66570bfdbdd7
parent 1641
195b71850b56
child 2525
2eb010b6cb22
permissions
-rw-r--r--

8029017: ElementType.TYPE_USE should be a logical superset of ElementType.TYPE and ANNOTATION_TYPE
Reviewed-by: abuckley, jlahoda, vromero

     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  */
    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  */
    32 import java.util.Set;
    33 import java.util.List;
    34 import java.io.IOException;
    35 import java.lang.annotation.ElementType;
    36 import java.util.ArrayList;
    37 import java.util.Arrays;
    38 import java.util.EnumSet;
    39 import javax.tools.Diagnostic;
    40 import javax.tools.DiagnosticCollector;
    41 import javax.tools.JavaFileObject;
    43 import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
    44 import static java.lang.annotation.ElementType.CONSTRUCTOR;
    45 import static java.lang.annotation.ElementType.FIELD;
    46 import static java.lang.annotation.ElementType.METHOD;
    47 import static java.lang.annotation.ElementType.PARAMETER;
    48 import static java.lang.annotation.ElementType.TYPE;
    49 import static java.lang.annotation.ElementType.PACKAGE;
    50 import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
    51 import static java.lang.annotation.ElementType.TYPE_USE;
    52 import static java.lang.annotation.ElementType.TYPE_PARAMETER;
    54 public class TargetAnnoCombo {
    56     static final String TESTPKG = "testpkg";
    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;
    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);
    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);
    70     // [TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE,
    71     // PACKAGE]
    72     final static Set<ElementType> jdk7 = EnumSet.range(TYPE, PACKAGE);
    74     // [TYPE_USE, TYPE_PARAMETER]
    75     final static Set<ElementType> jdk8 = EnumSet.range(TYPE_PARAMETER, TYPE_USE);
    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>();
    81     int errors = 0;
    83     // Identify test cases that fail.
    84     enum IgnoreKind {
    85         RUN,
    86         IGNORE
    87     };
    89     private class TestCase {
    91         private Set<ElementType> baseAnnotations;
    92         private Set<ElementType> containerAnnotations;
    93         private IgnoreKind ignore;
    95         public TestCase(Set<ElementType> baseAnnotations, Set<ElementType> containerAnnotations) {
    96             this(baseAnnotations, containerAnnotations, IgnoreKind.RUN);
    97         }
    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         }
   106         public Set getBaseAnnotations() {
   107             return baseAnnotations;
   108         }
   110         public Set getContainerAnnotations() {
   111             return containerAnnotations;
   112         }
   114         public boolean isIgnored() {
   115             return ignore == IgnoreKind.IGNORE;
   116         }
   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              */
   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             }
   146             Set<ElementType> tempBaseSet = EnumSet.noneOf(ElementType.class);
   147             tempBaseSet.addAll(baseAnnotations);
   149             // If BaseAnno has TYPE, then ANNOTATION_TYPE is allowed by default.
   150             if (baseAnnotations.contains(TYPE)) {
   151                 tempBaseSet.add(ANNOTATION_TYPE);
   152             }
   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             }
   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             }
   167             // At this point, neither conAnnoTarget or baseAnnoTarget are null.
   168             if (containerAnnotations.isEmpty()) {
   169                 return true;
   170             }
   172             // At this point, conAnnoTarget is non-empty.
   173             if (baseAnnotations.isEmpty()) {
   174                 return false;
   175             }
   177             // At this point, neither conAnnoTarget or baseAnnoTarget are empty.
   178             return tempBaseSet.containsAll(containerAnnotations);
   179         }
   180     }
   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     }
   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     }
   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     }
   317     private void executeTestCase(TestCase testCase, int index) {
   318         debugPrint("Test case number = " + index);
   319         debugPrint(" => baseAnnoTarget = " + testCase.getBaseAnnotations());
   320         debugPrint(" => containerAnnoTarget = " + testCase.getContainerAnnotations());
   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         }
   341     }
   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 = "";
   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         }
   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();
   370         JavaFileObject pkgInfoFile = null;
   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         }
   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     }
   419     // Compile the test source file(s) and return test result.
   420     private boolean getCompileResult(String className, boolean shouldCompile,
   421             Iterable<? extends JavaFileObject> files) {
   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         }
   466         if (!ok) {
   467             error(errMesg);
   468             for (Diagnostic<?> d : diagnostics.getDiagnostics()) {
   469                 System.out.println(" Diags: " + d);
   470             }
   471         }
   472         return ok;
   473     }
   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     }
   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     }
   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     }
   505     private void debugPrint(String string) {
   506         if (DEBUG) {
   507             System.out.println(string);
   508         }
   509     }
   511     private void error(String msg) {
   512         System.out.println("ERROR: " + msg);
   513         errors++;
   514     }
   515 }

mercurial