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

Mon, 18 Feb 2013 14:29:40 -0800

author
jjg
date
Mon, 18 Feb 2013 14:29:40 -0800
changeset 1589
87884cd0fea3
parent 1554
5125b9854d07
child 1641
195b71850b56
permissions
-rw-r--r--

8008339: Test TargetAnnoCombo.java is broken
Reviewed-by: jjh

     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  */
    24 /**
    25  * @test
    26  * @bug      7195131
    27  * @author   sogoel
    28  * @summary  Combo test for all possible combinations for Target values
    29  * @ignore   8008339 Test TargetAnnoCombo.java is broken
    30  * @build    Helper
    31  * @compile  TargetAnnoCombo.java TestCaseGenerator.java
    32  * @run main TargetAnnoCombo
    33  */
    35 import java.io.IOException;
    36 import java.util.ArrayList;
    37 import java.util.Arrays;
    38 import java.util.HashSet;
    39 import java.util.Set;
    40 import javax.tools.Diagnostic;
    41 import javax.tools.DiagnosticCollector;
    42 import javax.tools.JavaFileObject;
    44 /*
    45  * TargetAnnoCombo gets a list of test case numbers using TestCaseGenerator.
    46  * For each of the test case number, @Target sets for base and container annotations
    47  * are determined, source files are generated, compiled, and the result is verified
    48  * based on if the @Target set for base and container is a positive or negative combination.
    49  *
    50  * @Target sets for base and container annotations are determined using a bit mapping of
    51  * 10 ElementType enum constants defined in JDK8.
    52  *
    53  * Bit      Target value
    54  *  0  "ElementType.ANNOTATION_TYPE"
    55  *  1  "ElementType.CONSTRUCTOR"
    56  *  2  "ElementType.FIELD"
    57  *  3  "ElementType.LOCAL_VARIABLE"
    58  *  4  "ElementType.METHOD"
    59  *  5  "ElementType.TYPE"
    60  *  6  "ElementType.PARAMETER"
    61  *  7  "ElementType.PACKAGE"
    62  *  8  "ElementType.TYPE_USE"
    63  *  9  "ElementType.TYPE_PARAMETER"
    64  *
    65  * Group 1:
    66  * 20 bits mapping, representing a test case number, is used for all target set
    67  * combinations ( 0 to 1048575 ) including empty @Target sets => @Target({}).
    68  * From this 20 bits, 10 bits are for base followed by 10 bits for container
    69  * where each bit maps to an ElementType enum constant defined in JDK8.
    70  *
    71  * Examples:
    72  * Test case number: 4, binary: 100 => container=100, base=[], container=["ElementType.FIELD"]
    73  * Test case number: 1003575, binary: 11110101000000110111 => base=1111010100, container=0000110111;
    74  *                   base=["ElementType.PARAMETER", "ElementType.TYPE_USE", "ElementType.METHOD", "ElementType.FIELD", "ElementType.PACKAGE", "ElementType.TYPE_PARAMETER"],
    75  *                   container=["ElementType.TYPE", "ElementType.METHOD", "ElementType.ANNOTATION_TYPE", "ElementType.CONSTRUCTOR", "ElementType.FIELD"]
    76  *
    77  * In the following groups, no @Target set is represented by null.
    78  * Group 2:
    79  * @Target is not defined on base.
    80  * Target sets for container are determined using the 10-bit binary number
    81  * resulting in 1024 test cases, mapping them to test case numbers from
    82  * 1048576 to (1048576 + 1023) => 1048576 to 1049599.
    83  *
    84  * Example:
    85  * Test case number: 1048587 => 1048587 - 1048576 = test case 11 in Group 2, binary: 1011 =>
    86  *                   base = null,
    87  *                   container = ["ElementType.ANNOTATION_TYPE","ElementType.CONSTRUCTOR","ElementType.LOCAL_VARIABLE"]
    88  *
    89  * Group 3:
    90  * @Target is not defined on container
    91  * Target sets for base are determined using the 10-bit binary number
    92  * resulting in 1024 test cases, mapping them to test case numbers from
    93  * 1049600 to (1049600 + 1023) => 1049600 to 1050623.
    94  *
    95  * Example:
    96  * Test case number: 1049708 => 1049708 - 1049600 = test case 108 in Group 3, binary: 1101100 =>
    97  *                   base = ["ElementType.FIELD", "ElementType.LOCAL_VARIABLE", "ElementType.TYPE", "ElementType.PARAMETER"],
    98  *                   container = null
    99  *
   100  * For the above group, test case number: 1049855 gives compiler error, JDK-8006547 filed
   101  *
   102  * Group 4:
   103  * @Target not defined for both base and container annotations.
   104  *
   105  * This is the last test and corresponds to test case number 1050624. base=null, container=null
   106  *
   107  * Examples to run this test:
   108  * 1. Run a specific test case number:
   109  *    ${JTREG} -DTestCaseNum=10782 -samevm -jdk:${JAVA_TEST} -reportDir ${REPORT} -workDir ${WORK} TargetAnnoCombo.java
   110  * 2. Run specific number of tests:
   111  *    ${JTREG} -DNumberOfTests=4 -samevm -jdk:${JAVA_TEST} -reportDir ${REPORT} -workDir ${WORK} TargetAnnoCombo.java
   112  * 3. Run specific number of tests with a seed:
   113  *    ${JTREG} -DNumberOfTests=4 -DTestSeed=-972894659 -samevm -jdk:${JAVA_TEST} -reportDir ${REPORT} -workDir ${WORK} TargetAnnoCombo.java
   114  * 4. Run tests in default mode (number of tests = 1000):
   115  *    ${JTREG} -DTestMode=DEFAULT -samevm -jdk:${JAVA_TEST} -reportDir ${REPORT} -workDir ${WORK} TargetAnnoCombo.java
   116  * 5. Run all tests (FULL mode):
   117  *    ${JTREG} -DTestMode=FULL -samevm -jdk:${JAVA_TEST} -reportDir ${REPORT} -workDir ${WORK} TargetAnnoCombo.java
   118  *
   119  */
   121 public class TargetAnnoCombo {
   122     int errors = 0;
   123     static final String TESTPKG = "testpkg";
   124     /*
   125      *  Set it to true to get more debug information including base and
   126      *  container target sets for a given test case number
   127      */
   128     static final boolean DEBUG = false;
   130     // JDK 5/6/7/8 Targets
   131     static final String[] targetVals = {"ElementType.ANNOTATION_TYPE",
   132       "ElementType.CONSTRUCTOR", "ElementType.FIELD",
   133       "ElementType.LOCAL_VARIABLE", "ElementType.METHOD",
   134       "ElementType.TYPE", "ElementType.PARAMETER",
   135       "ElementType.PACKAGE", "ElementType.TYPE_USE",
   136       "ElementType.TYPE_PARAMETER"};
   138     // TYPE_USE and TYPE_PARAMETER (added in JDK8) are not part of default Target set
   139     static final int DEFAULT_TARGET_CNT = 8;
   141     public static void main(String args[]) throws Exception {
   143         /* maxTestNum = (base and container combinations of targetVals elems [0 - 1048575 combos])
   144          *              + (combinations where base or container has no Target [1024 combos])
   145          *              + (no -1 even though 1st test is number 0 as last test is where both
   146          *                 base and container have no target)
   147          */
   149         int maxTestNum = (int)Math.pow(2, 2*targetVals.length) + 2*(int)Math.pow(2, targetVals.length);
   150         TestCaseGenerator tcg = new TestCaseGenerator(maxTestNum);
   151         TargetAnnoCombo tac = new TargetAnnoCombo();
   153         int testCtr = 0;
   154         int testCase = -1;
   155         while ( (testCase=tcg.getNextTestCase()) != -1 ) {
   156             tac.executeTestCase(testCase, maxTestNum);
   157             testCtr++;
   158         }
   160         System.out.println("Total tests run: " + testCtr);
   161         if (tac.errors > 0)
   162             throw new Exception(tac.errors + " errors found");
   163     }
   165     /*
   166      * For given testCase, determine the base and container annotation Target sets,
   167      * get if testCase should compile, get test source file(s), get compilation result and verify.
   168      *
   169      */
   170     private void executeTestCase(int testCase, int maxTestNum) {
   172         // Determine base and container annotation Target sets for the testCase
   173         Set<String> baseAnnoTarget = null;
   174         Set<String> conAnnoTarget = null;
   176         //Number of base and container combinations [0 - 1048575 combos]
   177         int baseContCombos = (int)Math.pow(2, 2*targetVals.length);
   178         //Number of either base or container combinations when one of them has no @Target [1024 combos]
   179         int targetValsCombos = (int)Math.pow(2, targetVals.length);
   181         if (testCase >= baseContCombos) {
   182             //Base annotation do not have @Target
   183             if (testCase < baseContCombos + targetValsCombos) {
   184                 baseAnnoTarget = null;
   185                 conAnnoTarget = getSetFromBitVec(Integer.toBinaryString(testCase - baseContCombos));
   186             } else if (testCase < baseContCombos + 2*targetValsCombos) {
   187                 //Container annotation do not have @Target
   188                 baseAnnoTarget = getSetFromBitVec(Integer.toBinaryString(testCase - baseContCombos - targetValsCombos));
   189                 conAnnoTarget = null;
   190             } else {
   191                 //Both Base and Container annotation do not have @Target
   192                 baseAnnoTarget = null;
   193                 conAnnoTarget = null;
   194             }
   195         } else {
   196             //TestCase number is represented as 10-bits for base followed by container bits
   197             String bin = Integer.toBinaryString(testCase);
   198             String base="", cont=bin;
   199             if (bin.length() > targetVals.length){
   200                 base = bin.substring(0, bin.length() - targetVals.length);
   201                 cont = bin.substring(bin.length() - targetVals.length,bin.length());
   202             }
   203             baseAnnoTarget = getSetFromBitVec(base);
   204             conAnnoTarget = getSetFromBitVec(cont);
   205         }
   207         debugPrint("Test case number = " + testCase + " => binary = " + Integer.toBinaryString(testCase));
   208         debugPrint(" => baseAnnoTarget = " + baseAnnoTarget);
   209         debugPrint(" => containerAnnoTarget = " + conAnnoTarget);
   211         // Determine if a testCase should compile or not
   212         String className = "TC" + testCase;
   213         boolean shouldCompile = isValidSubSet(baseAnnoTarget, conAnnoTarget);
   215         // Get test source file(s)
   216         Iterable<? extends JavaFileObject> files = getFileList(className, baseAnnoTarget,
   217                 conAnnoTarget, shouldCompile);
   219         // Get result of compiling test src file(s)
   220         boolean result = getCompileResult(className, shouldCompile, files);
   222         // List test src code if test fails
   223         if(!result) {
   224             System.out.println("FAIL: Test " + testCase);
   225             try {
   226                 for (JavaFileObject f: files) {
   227                     System.out.println("File: " + f.getName() + "\n" + f.getCharContent(true));
   228                 }
   229             } catch (IOException ioe) {
   230                 System.out.println("Exception: " + ioe);
   231             }
   232         } else {
   233             debugPrint("PASS: Test " + testCase);
   234         }
   235     }
   237     // Get a Set<String> based on bits that are set to 1
   238     public Set<String> getSetFromBitVec(String bitVec) {
   239         Set<String> ret = new HashSet<>();
   240         char[] bit = bitVec.toCharArray();
   241         for (int i=bit.length-1, j=0; i>=0; i--, j++){
   242             if (bit[i] == '1') {
   243                 ret.add(targetVals[j]);
   244             }
   245         }
   246         return ret;
   247     }
   249     // Compile the test source file(s) and return test result
   250     private boolean getCompileResult(String className, boolean shouldCompile,
   251             Iterable<? extends JavaFileObject> files) {
   253         DiagnosticCollector<JavaFileObject> diagnostics =
   254                 new DiagnosticCollector<JavaFileObject>();
   255         Helper.compileCode(diagnostics, files);
   257         // Test case pass or fail
   258         boolean ok = false;
   260         String errMesg = "";
   261         int numDiags = diagnostics.getDiagnostics().size();
   263         if (numDiags == 0) {
   264             if (shouldCompile) {
   265                 debugPrint("Test passed, compiled as expected.");
   266                 ok = true;
   267             } else {
   268                 errMesg = "Test failed, compiled unexpectedly.";
   269                 ok = false;
   270             }
   271         } else {
   272             if (shouldCompile) {
   273                 // did not compile
   274                 errMesg = "Test failed, did not compile.";
   275                 ok = false;
   276             } else {
   277                 // Error in compilation as expected
   278                 String expectedErrKey = "compiler.err.invalid.repeatable." +
   279                         "annotation.incompatible.target";
   280                 for (Diagnostic<?> d : diagnostics.getDiagnostics()) {
   281                     if((d.getKind() == Diagnostic.Kind.ERROR) &&
   282                         d.getCode().contains(expectedErrKey)) {
   283                         // Error message as expected
   284                         debugPrint("Error message as expected.");
   285                         ok = true;
   286                         break;
   287                     } else {
   288                         // error message is incorrect
   289                         ok = false;
   290                     }
   291                 }
   292                 if (!ok) {
   293                     errMesg = "Incorrect error received when compiling " +
   294                         className + ", expected: " + expectedErrKey;
   295                 }
   296             }
   297         }
   299         if(!ok) {
   300             error(errMesg);
   301             for (Diagnostic<?> d : diagnostics.getDiagnostics())
   302                 System.out.println(" Diags: " + d);
   303         }
   304         return ok;
   305     }
   307     private void debugPrint(String string) {
   308         if(DEBUG)
   309             System.out.println(string);
   310     }
   312     // Create src code and corresponding JavaFileObjects
   313     private Iterable<? extends JavaFileObject> getFileList(String className,
   314             Set<String> baseAnnoTarget, Set<String> conAnnoTarget,
   315             boolean shouldCompile) {
   317         String srcContent = "";
   318         String pkgInfoContent = "";
   319         String template = Helper.template;
   320         String baseTarget = "", conTarget = "";
   322         String target = Helper.ContentVars.TARGET.getVal();
   323         if(baseAnnoTarget != null) {
   324             baseTarget = target.replace("#VAL", baseAnnoTarget.toString())
   325                                   .replace("[", "{").replace("]", "}");
   326         }
   327         if(conAnnoTarget != null) {
   328             conTarget = target.replace("#VAL", conAnnoTarget.toString())
   329                                  .replace("[", "{").replace("]", "}");
   330         }
   332         String annoData = Helper.ContentVars.IMPORTSTMTS.getVal() +
   333                           conTarget +
   334                           Helper.ContentVars.CONTAINER.getVal() +
   335                           baseTarget +
   336                           Helper.ContentVars.REPEATABLE.getVal() +
   337                           Helper.ContentVars.BASE.getVal();
   339         JavaFileObject pkgInfoFile = null;
   341         /*
   342          *  If shouldCompile = true and no @Target is specified for container annotation,
   343          *  then all 8 ElementType enum constants are applicable as targets for
   344          *  container annotation.
   345          */
   346         if(shouldCompile && conAnnoTarget == null) {
   347             //conAnnoTarget = new HashSet<String>(Arrays.asList(targetVals));
   348             conAnnoTarget = getDefaultTargetSet();
   349         }
   351         if(shouldCompile) {
   352             boolean isPkgCasePresent = new ArrayList<String>(conAnnoTarget).contains("ElementType.PACKAGE");
   353             String repeatableAnno = Helper.ContentVars.BASEANNO.getVal() + " " + Helper.ContentVars.BASEANNO.getVal();
   354             for(String s: conAnnoTarget) {
   355                 s = s.replace("ElementType.","");
   356                 String replaceStr = "/*"+s+"*/";
   357                 if(s.equalsIgnoreCase("PACKAGE")) {
   358                     //Create packageInfo file
   359                     String pkgInfoName = TESTPKG + "." + "package-info";
   360                     pkgInfoContent = repeatableAnno + "\npackage " + TESTPKG + ";" + annoData;
   361                     pkgInfoFile = Helper.getFile(pkgInfoName, pkgInfoContent);
   362                 } else {
   363                     template = template.replace(replaceStr, repeatableAnno);
   364                     //srcContent = template.replace("#ClassName",className);
   365                     if(!isPkgCasePresent) {
   366                         srcContent = template.replace("/*ANNODATA*/", annoData).replace("#ClassName",className);
   367                     } else {
   368                         replaceStr = "/*PACKAGE*/";
   369                         srcContent = template.replace(replaceStr, "package " + TESTPKG + ";")
   370                                      .replace("#ClassName", className);
   371                     }
   372                 }
   373             }
   374         } else {
   375             // For invalid cases, compilation should fail at declaration site
   376             template = "class #ClassName {}";
   377             srcContent = annoData + template.replace("#ClassName",className);
   378         }
   379         JavaFileObject srcFile = Helper.getFile(className, srcContent);
   380         Iterable<? extends JavaFileObject> files = null;
   381         if(pkgInfoFile != null)
   382             files = Arrays.asList(pkgInfoFile,srcFile);
   383         else
   384             files = Arrays.asList(srcFile);
   385         return files;
   386     }
   388     private Set<String> getDefaultTargetSet() {
   389         Set<String> defaultSet = new HashSet<>();
   390         int ctr = 0;
   391         for(String s : targetVals) {
   392             if(ctr++ < DEFAULT_TARGET_CNT) {
   393                 defaultSet.add(s);
   394             }
   395         }
   396         return defaultSet;
   397     }
   399     private boolean isValidSubSet(Set<String> baseAnnoTarget, Set<String> conAnnoTarget) {
   400         /*
   401          *  RULE 1: conAnnoTarget should be a subset of baseAnnoTarget
   402          *  RULE 2: For empty @Target ({}) - annotation cannot be applied anywhere
   403          *         - Empty sets for both is valid
   404          *         - Empty baseTarget set is invalid with non-empty conTarget set
   405          *         - Non-empty baseTarget set is valid with empty conTarget set
   406          *  RULE 3: For no @Target specified - annotation can be applied to any JDK 7 targets
   407          *         - No @Target for both is valid
   408          *         - No @Target for baseTarget set with @Target conTarget set is valid
   409          *         - @Target for baseTarget set with no @Target for conTarget is invalid
   410          */
   413         /* If baseAnno has no @Target, Foo can be either applied to @Target specified for container annotation
   414          * else will be applicable for all default targets if no @Target is present for container annotation.
   415          * In both cases, the set will be a valid set with no @Target for base annotation
   416          */
   417         if(baseAnnoTarget == null) {
   418             if(conAnnoTarget == null) return true;
   419             return !(conAnnoTarget.contains("ElementType.TYPE_USE") || conAnnoTarget.contains("ElementType.TYPE_PARAMETER"));
   420         }
   422         Set<String> tempBaseSet = new HashSet<>(baseAnnoTarget);
   423         // If BaseAnno has TYPE, then ANNOTATION_TYPE is allowed by default
   424         if(baseAnnoTarget.contains("ElementType.TYPE")) {
   425             tempBaseSet.add("ElementType.ANNOTATION_TYPE");
   426         }
   428         /*
   429          * If containerAnno has no @Target, only valid case if baseAnnoTarget has all targets defined
   430          * else invalid set
   431          */
   432         if(conAnnoTarget == null) {
   433             return (tempBaseSet.containsAll(getDefaultTargetSet()));
   434         }
   436         // At this point, neither conAnnoTarget or baseAnnoTarget are null
   437         if(conAnnoTarget.size() == 0) return true;
   439         // At this point, conAnnoTarget is non-empty
   440         if (baseAnnoTarget.size() == 0) return false;
   442         // At this point, neither conAnnoTarget or baseAnnoTarget are empty
   443         return tempBaseSet.containsAll(conAnnoTarget);
   444     }
   446     void error(String msg) {
   447         System.out.println("ERROR: " + msg);
   448         errors++;
   449     }
   451     // Lists the start and end range for the given set of target vals
   452     void showGroups() {
   453         //Group 1: All target set combinations ( 0 to 1048575 ) including empty @Target sets => @Target({})
   454         int grpEnd1 = (int)Math.pow(2, 2*targetVals.length) - 1;
   455         System.out.println("[Group 1]: 0 - " + grpEnd1);
   457         //Group 2: @Target not defined for base annotation ( 1048576 - 1049599 ).
   458         System.out.print("[Group 2]: " + (grpEnd1 + 1) + " - ");
   459         int grpEnd2 = grpEnd1 + 1 + (int)Math.pow(2, targetVals.length) - 1;
   460         System.out.println(grpEnd2);
   462         //Group 3: @Target not defined for container annotation ( 1049600 - 1050623 ).
   463         System.out.print("[Group 3]: " + (grpEnd2 + 1) + " - ");
   464         int grpEnd3 = grpEnd2 + 1 + (int)Math.pow(2, targetVals.length) - 1;
   465         System.out.println(grpEnd3);
   467         //Group 4: @Target not defined for both base and container annotations ( 1050624 ).
   468         System.out.println("[Group 4]: " + (grpEnd3 + 1));
   469     }
   470 }

mercurial