changeset 2319:5759b9c47c64

langtools_810165 by Steve Sides: improve tests for type annotations.
author wmdietl
date Sun, 17 Mar 2013 00:41:55 +0100
parents c20275a1f5fd
children 07c511efe87b
files test/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest3.java
diffstat 1 files changed, 547 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest3.java	Sun Mar 17 00:41:55 2013 +0100
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8005085 8005681 8008769 8010015
+ * @summary Check (repeating)type annotations on lambda usage.
+ * @run main CombinationsTargetTest3
+ */
+
+import com.sun.tools.classfile.*;
+import java.io.File;
+import java.util.Vector;
+
+public class CombinationsTargetTest3 extends ClassfileTestHelper {
+
+    // Helps identify test case in event of failure.
+    int testcount = 0;
+
+    // Known failure cases due to open bugs.
+    Vector<String> skippedTests = new Vector<>();
+    void printSkips() {
+        if(!skippedTests.isEmpty()) {
+            println(skippedTests.size() + " tests were skipped:");
+            for(String t : skippedTests)
+                println("    " + t);
+        }
+    }
+
+    // Test case descriptions and expected annotation counts.
+    enum srce  {
+        src1("type annotations on lambda expression as method arg.",4,0),
+        src2("type annotations on new in single line lambda expression",2,0),
+        src3("type annotations in lambda expression code block",4,0),
+        src4("type annotations in code block with recursion,cast",2,0),
+        src5("type annotations in lambda expression code block",4,0),
+        src6("type annotations on type parm in method reference",4,0),
+        src7("type annotations on inner class field of lambda expression",2,2),
+        src8("type annotations in inner class of lambda expression",4,2),
+        src9("type annotations on static method of interface",4,2);
+
+        String description;
+        // Expected annotation counts are same for Vis or Invis, but which one
+        // depends on retention type.
+        Integer[] exp = { 0, 0 };
+
+        // If class to test is inner class, this may be set in SourceString()
+        String innerClassname = null ;
+
+        // If class to test is not main or inner class; set in sourceString()
+        String altClassName = null;
+
+        srce(String desc, int e1, int e2) {
+            description = this + ": " +desc;
+            exp[0]=e1;
+            exp[1]=e2;
+        }
+    }
+
+    // Check for RuntimeInvisible or RuntimeVisible annotations.
+    String[] RType={"CLASS", "RUNTIME"};
+
+    // This can be a compile only test.
+    static boolean compileonly=false;
+
+    // Collect failure for end of test report()
+    Vector<String> vFailures = new Vector<>();
+
+    // pass/fail determined after all tests have run.
+    void report() {
+        if(vFailures.isEmpty()) {
+            printSkips();
+            println("PASS");
+        } else {
+           System.err.println("FAILED: There were failures:");
+           for(String f : vFailures)
+               System.err.println(f);
+           throw new RuntimeException("There were failures. See test log.");
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        if(args.length>0 && args[0].compareTo("compileonly")==0)
+            compileonly=true;
+        new CombinationsTargetTest3().run();
+    }
+
+    void run() throws Exception {
+        // Determines which repeat and order in source(ABMix).
+        Boolean As= false, BDs=true, ABMix=false;
+        int testrun=0;
+        // A repeats and/or B/D repeats, ABMix for order of As and Bs.
+        Boolean [][] bRepeat = new Boolean[][]{{false,false,false}, //no repeats
+                                               {true,false,false}, //repeat @A
+                                               {false,true,false}, //repeat @B
+                                               {true,true,false},  //repeat both
+                                               {false,false,true}  //repeat mix
+        };
+        // Added ElementType's. All set; not permuted (so far) for this test
+        String et = "TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE";
+ 
+        // test loop
+        for(Boolean[] bCombo : bRepeat) {
+            As=bCombo[0]; BDs=bCombo[1]; ABMix=bCombo[2];
+            for(srce src : srce.values())
+                for( String rtype : RType ) {
+                   switch( rtype ) {
+                       case "RUNTIME":
+                           test(0,src.exp[0],0,src.exp[1],As, BDs, ABMix,
+                                "RUNTIME", et, ++testrun, src);
+                           break;
+                       case "CLASS":
+                           test(src.exp[0],0,src.exp[1],0,As, BDs, ABMix,
+                                "CLASS", et, ++testrun, src);
+                           break;
+                }
+            }
+        }
+        report();
+    }
+
+    // Filter out skipped cases, compile, pass class file to test method,
+    // count annotations and asses results.
+    public void test(int tinv, int tvis, int inv, int vis, Boolean Arepeats,
+                     Boolean BDrepeats, Boolean ABmix, String rtn, String et2,
+                     Integer N, srce source) throws Exception {
+        ++testcount;
+        expected_tvisibles = tvis;
+        expected_tinvisibles = tinv;
+        expected_visibles = vis;
+        expected_invisibles = inv;
+        File testFile = null;
+        String tname="Test" + N.toString();
+        String testDef = "Test " + testcount + " parameters: tinv=" + tinv +
+                ", tvis=" + tvis + ", inv=" + inv + ", vis=" + vis +
+                ", Arepeats=" + Arepeats + ", BDrepeats=" + BDrepeats +
+                ", ABmix=" + ABmix + ", retention: " + rtn + ", anno2: " +
+                et2 + ", src=" + source;
+
+        // Skip failing cases with bug ID's
+        //8010015 type-annotations on field of inner class in lambda expression
+        if(source.equals(srce.src7)) {
+            skippedTests.add(testDef +
+                "\n--8010015 type-annotations on field of inner" +
+                " class in lambda expression.");
+            return;
+        } //8005681 repeated type-annotations on new/cast/array in
+          // inner class in lambda expression."
+         else if ((source.equals(srce.src2) || source.equals(srce.src4) ||
+            source.equals(srce.src5)) &&
+            (ABmix || (Arepeats && BDrepeats))) {
+                skippedTests.add(testDef +
+                  "\n--8005681 repeated type-annotations on new/cast/array in" +
+                  " inner class in lambda expression.");
+            return;
+        }//8008769 Repeated type-annotations on type parm of local variable
+         else if (source.equals(srce.src6) &&
+                   (ABmix || (Arepeats && BDrepeats))) {
+            skippedTests.add(testDef +  "\n--8008769 Repeated " +
+                             "type-annotations on type parm of local variable");
+            return;
+        }
+
+        println(testDef);
+        // Create test source and File.
+        String sourceString = sourceString(tname, rtn, et2, Arepeats,
+                                           BDrepeats, ABmix, source);
+        testFile = writeTestFile(tname+".java", sourceString);
+        // Compile test source and read classfile.
+        File classFile = null;
+        try {
+            classFile = compile(testFile);
+            System.out.println("pass compile: " + tname + ".java");
+        } catch (Error err) {
+            System.err.println("fail compile. Source:\n" + sourceString);
+            throw err;
+        }
+        if(!compileonly) {
+            //check if innerClassname is set
+            String classdir = classFile.getAbsolutePath();
+            if(source.innerClassname != null) {
+                StringBuffer sb = new StringBuffer(classdir);
+                classFile=new File(sb.insert(sb.lastIndexOf(".class"),
+                                   source.innerClassname).toString());
+                source.innerClassname=null;
+            } else if (source.altClassName != null) {
+                classdir = classdir.substring(0,classdir.lastIndexOf("Test"));
+                classFile=new File(classdir.concat(source.altClassName));
+                source.innerClassname=null;
+            }
+            ClassFile cf = ClassFile.read(classFile);
+
+            println("Testing classfile: " + cf.getName());
+            //Test class,fields and method counts.
+            test(cf);
+
+            for (Field f : cf.fields) {
+                test(cf, f);
+                test(cf, f, true);
+            }
+            for (Method m: cf.methods) {
+                test(cf, m);
+                test(cf, m, true);
+            }
+
+            countAnnotations(); // sets errors=0 before counting.
+            if (errors > 0) {
+                System.err.println( testDef );
+                System.err.println( "Source:\n" + sourceString );
+                vFailures.add(testDef);
+            }
+        }
+        if(errors==0) println("Pass"); println("");
+    }
+
+    /*
+     * Source definitions for test cases.
+     * To add a test:
+     *   Add enum to srce(near top of file) with expected annotation counts.
+     *   Add source defintion below.
+     */
+    String sourceString(String testname, String retentn, String annot2,
+                        Boolean Arepeats, Boolean BDrepeats, Boolean ABmix,
+                        srce src) {
+
+        String As = "@A", Bs = "@B", Ds = "@D";
+        if(Arepeats) As = "@A @A";
+        if(BDrepeats) {
+            Bs = "@B @B";
+            Ds = "@D @D";
+        }
+        if(ABmix) { As = "@A @B"; Bs = "@A @B"; Ds = "@D @D"; }
+
+        // Source to check for TYPE_USE and TYPE_PARAMETER annotations.
+        // Source base (annotations) is same for all test cases.
+        String source = new String();
+        String imports = new String("import java.lang.annotation.*; \n" +
+            "import static java.lang.annotation.RetentionPolicy.*; \n" +
+            "import static java.lang.annotation.ElementType.*; \n" +
+            "import java.util.List; \n" +
+            "import java.util.ArrayList;\n\n");
+
+            String sourceBase = new String(
+            "@Retention("+retentn+") @Target({TYPE_USE,_OTHER_}) @Repeatable( AC.class ) @interface A { }\n" +
+            "@Retention("+retentn+") @Target({TYPE_USE,_OTHER_}) @interface AC { A[] value(); } \n" +
+            "@Retention("+retentn+") @Target({TYPE_USE,_OTHER_}) @Repeatable( BC.class ) @interface B { }\n" +
+            "@Retention("+retentn+") @Target({TYPE_USE,_OTHER_}) @interface BC { B[] value(); } \n" +
+            "@Retention("+retentn+") @Target({TYPE_USE,TYPE_PARAMETER,_OTHER_}) @Repeatable(DC.class) @interface D { }\n" +
+            "@Retention("+retentn+") @Target({TYPE_USE,TYPE_PARAMETER,_OTHER_}) @interface DC { D[] value(); }");
+
+        // Test case sources with sample generated source
+        switch(src) {
+            case src1: //(repeating) type annotations on lambda expressions.
+                /*
+                 * class Test1 {
+                 * Test1(){}
+                 * interface MapFun<T,R> {  R m( T n); }
+                 * void meth( MapFun<String,Integer> mf ) {
+                 *     assert( mf.m("four") == 4);
+                 * }
+                 * void test(Integer i) {
+                 *     // lambda expression as method arg
+                 *     meth( (@A @B String s) -> { @A @B Integer len = s.length(); return len; } );
+                 * }}
+                 */
+                source = new String( source +
+                "// " + src.description + "\n" +
+                "class " + testname + " {\n" +
+                "  " + testname +"(){} \n" +
+                "  interface MapFun<T,R> {  R m( T n); }\n\n" +
+                "  void meth( MapFun<String,Integer> mf ) {\n" +
+                "    assert( mf.m(\"four\") == 4);\n" +
+                "  }\n\n" +
+                "  void test(Integer i) {\n" +
+                "    // lambda expression as method arg\n" +
+                "    meth( (_As_ _Bs_ String s) -> { _As_ _Bs_ Integer len = s.length(); return len; } );\n" +
+                "}}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
+                "\n";
+                break;
+            case src2: //(repeating) type annotations on new in single line lambda expression.
+                /*
+                 * //case2: (repeating) type annotations on new in single lambda expressions.
+                 * class Test2{
+                 *   interface MapFun<T, R> {  R m( T n); }
+                 *   MapFun<Integer, String> its;
+                 * void test(Integer i) {
+                 *   its = a -> "~"+new @A @B Integer(a).toString()+"~";
+                 *   System.out.println("in: " + i + " out: " + its.m(i));
+                 * }}
+                 */
+                source = new String( source +
+                "// " + src.description + "\n" +
+                "class " + testname + "{\n" +
+                "  interface MapFun<T, R> {  R m( T n); }\n" +
+                "  MapFun<Integer, String> its;\n" +
+                "  void test(Integer i) {\n" +
+                "    its = a -> \"~\"+new _As_ _Bs_ Integer(a).toString()+\"~\";\n" +
+                "    System.out.println(\"in: \" + i + \" out: \" + its.m(i));\n" +
+                "  }\n" +
+                "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
+                "\n";
+            break;
+            case src3: //(repeating) type annotations in lambda expression code block.
+                /*
+                 * class Test183{
+                 *   interface MapFun<T, R> {  R m( T n); }
+                 *   MapFun<List<Integer>, String> iLs;
+                 *   void testm(Integer i) {
+                 *       iLs = l -> { @A @B @A @B String ret = new String();
+                 *                    for( @A @B @A @B Integer i2 : l)
+                 *                        ret=ret.concat(i2.toString() + " ");
+                 *                    return ret; };
+                 *   List<Integer> li = new ArrayList<>();
+                 *   for(int j=0; j<i; j++) li.add(j);
+                 *   System.out.println(iLs.m(li) );
+                 * }}
+                 */
+                source = new String( source +
+                "// " + src.description + "\n" +
+                "class "+ testname + "{\n" +
+                "  interface MapFun<T, R> {  R m( T n); }\n" +
+                "  MapFun<List<Integer>, String> iLs;\n" +
+                "  void testm(Integer i) {\n" +
+                "    iLs = l -> { _As_ _Bs_ String ret = new String();\n" +
+                "                 for( _As_ _Bs_ Integer i2 : l)\n" +
+                "                   ret=ret.concat(i2.toString() + \" \");\n" +
+                "                 return ret; };\n" +
+                "  List<Integer> li = new ArrayList<>();\n" +
+                "  for(int j=0; j<i; j++) li.add(j);\n" +
+                "  System.out.println(iLs.m(li) );\n" +
+                "}\n" +
+                "\n" +
+                "    public static void main(String... args) {new " + testname + "().testm(5); }\n" +
+                "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
+                "\n";
+            break;
+            case src4: //(repeating) type annotations in code block with recursion,cast
+                /*
+                 * class Test194{
+                 *   interface MapFun<T, R> {  R m( T n); }
+                 *   MapFun<Integer, Double>  nf;
+                 *   void testm(Integer i) {
+                 *       nf = j -> { return j == 1 ? 1.0 : (@A @B @A @B  Double)(nf.m(j-1) * j); };
+                 *       System.out.println( "nf.m(" + i + "): " + nf.m(i));
+                 *   }
+                 * }
+                 */
+                source = new String( source +
+                "// " + src.description + "\n" +
+                "class "+ testname + "{\n" +
+                "  interface MapFun<T, R> {  R m( T n); }\n" +
+                "  MapFun<Integer, Double>  nf;\n" +
+                "  void testm(Integer i) {\n" +
+                "    nf = j -> { return j == 1 ? 1.0 : (_As_ _Bs_  Double)(nf.m(j-1) * j); };\n" +
+                "    System.out.println( \"nf.m(\" + i + \"): \" + nf.m(i));\n" +
+                "  }\n" +
+                "  public static void main(String... args) {new " + testname + "().testm(5); }\n" +
+                "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
+                "\n";
+            break;
+            case src5: //(repeating) type annotations in lambda expression code block.
+                   /*
+                    * class Test180 {
+                    *   interface MapFun<T, R> {  R m( T n); }
+                    *   MapFun<Integer,List<Integer>> iLi;
+                    *   void test(Integer i) {
+                    *     // type parameter use.
+                    *     iLi = n -> { List<@A @B @A @B Integer> LI = new ArrayList<@A @B @A @B Integer>(n);
+                    *                  for(int nn = n; nn >=0; nn--) LI.add(nn);
+                    *                  return LI; };
+                    *     List<Integer> li = iLi.m(i);
+                    *     for(Integer k : li) System.out.print(k);
+                    *   }
+                    * }
+                    */
+                source = new String( source +
+                "// " + src.description + "\n" +
+                "class "+ testname + "{\n" +
+                "  interface MapFun<T, R> {  R m( T n); }\n" +
+                "  MapFun<Integer,List<Integer>> iLi;\n" +
+                "  void test(Integer i) {\n" +
+                "    // type parameter use.\n" +
+                "    iLi = n -> { List<_As_ _Bs_ Integer> LI = new ArrayList<_As_ _Bs_ Integer>(n);\n" +
+                "                 for(int nn = n; nn >=0; nn--) LI.add(nn);\n" +
+                "                 return LI; };\n" +
+                "    List<Integer> li = iLi.m(i);\n" +
+                "    for(Integer k : li) System.out.print(k);\n" +
+                "}\n" +
+                "  public static void main(String... args) {new " + testname + "().test(5); }\n" +
+                "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs).replace("_Ds_",Ds) +
+                "\n";
+            break;
+            case src6: //(repeating) type annotations on type parm in method reference.
+                /*
+                 * class Test240{
+                 *   interface PrintString { void print(String s); }
+                 *   public void printArray(Object[] oa, PrintString ps) {
+                 *       for(Object o : oa ) ps.print(o.toString());
+                 *   }
+                 *   public void test() {
+                 *       Integer[] intarray = {1,2,3,4,5};
+                 *       printArray(intarray, @A @B @A @B TPrint::<@A @B @A @B String>print);
+                 *   }
+                 * }
+                 * class TPrint {
+                 *    public static <T> void print(T t) { System.out.println( t.toString()); }
+                 * }
+                 */
+                source = new String( source +
+                "// " + src.description + "\n" +
+                "class "+ testname + "{\n" +
+                "  interface PrintString { void print(String s); }\n" +
+                "  public void printArray(Object[] oa, PrintString ps) {\n" +
+                "      for(Object o : oa ) ps.print(o.toString());\n" +
+                "  }\n" +
+                "  public void test() {\n" +
+                "    Integer[] intarray = {1,2,3,4,5};\n" +
+                "    printArray(intarray, _As_ _Bs_ TPrint::<_As_ _Bs_ String>print);\n" +
+                "  }\n" +
+                "  public static void main(String... args) {new " + testname + "().test(); }\n" +
+                "}\n\n" +
+                "class TPrint {\n" +
+                "  public static <T> void print(T t) { System.out.println( t.toString()); }\n" +
+                "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
+                "\n";
+            break;
+            case src7: //(repeating)type annotations in inner class of lambda expression.
+                /*
+                 * class Test2{
+                 *   interface MapFun<T, R> {  R m( T n); }
+                 *   MapFun<Class<?>,String> cs;
+                 *   void test() {
+                 *     cs = c -> {
+                 *         class innerClass   {
+                 *           @A @B Class<?> icc = null;
+                 *           String getString() { return icc.toString(); }
+                 *         }
+                 *         return new innerClass().getString();
+                 *     };
+                 *     System.out.println("cs.m : " + cs.m(Integer.class));
+                 *   }
+                 * }
+                 */
+                source = new String( source +
+                "// " + src.description + "\n" +
+                "class "+ testname + "{\n" +
+                "  interface MapFun<T, R> {  R m( T n); }\n" +
+                "  MapFun<Class<?>,String> cs;\n" +
+                "  void test() {\n" +
+                "    cs = c -> {\n" +
+                "        class innerClass   {\n" +
+                "          _As_ _Bs_ Class<?> icc = null;\n" +
+                "          innerClass(Class<?> _c) { icc = _c; }\n" +
+                "          String getString() { return icc.toString(); }\n" +
+                "        }\n" +
+                "        return new innerClass(c).getString();\n" +
+                "    };\n" +
+                "    System.out.println(\"cs.m : \" + cs.m(Integer.class));\n" +
+                "  }\n" +
+                "\n" +
+                "    public static void main(String... args) {new " + testname + "().test(); }\n" +
+                "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
+                "\n";
+                src.innerClassname="$1innerClass";
+            break;
+            case src8: //(repeating)type annotations in inner class of lambda expression.
+                /*
+                 * class Test2{
+                 *   interface MapFun<T, R> {  R m( T n); }
+                 *   MapFun<Class<?>,String> cs;
+                 *   void test() {
+                 *     cs = c -> {
+                 *         class innerClass   {
+                 *             Class<?> icc;
+                 *             innerClass(@A @B Class<?> _c) { icc = _c; }
+                 *             @A @B String getString() { return icc.toString(); }
+                 *         }
+                 *         return new innerClass(c).getString();
+                 *     };
+                 *     System.out.println("cs.m : " + cs.m(Integer.class));
+                 *   }
+                 * }
+                 */
+                source = new String( source +
+                "// " + src.description + "\n" +
+                "class "+ testname + "{\n" +
+                "  interface MapFun<T, R> {  R m( T n); }\n" +
+                "  MapFun<Class<?>,String> cs;\n" +
+                "  void test() {\n" +
+                "    cs = c -> {\n" +
+                "        class innerClass {\n" +
+                "            Class<?> icc;\n" +
+                "            innerClass(_As_ _Bs_ Class<?> _c) { icc = _c; }\n" +
+                "            _As_ _Bs_ String getString() { return icc.toString(); }\n" +
+                "        }\n" +
+                "        return new innerClass(c).getString();\n" +
+                "    };\n" +
+                "    System.out.println(\"cs.m : \" + cs.m(Integer.class));\n" +
+                "  }\n" +
+                "\n" +
+                "    public static void main(String... args) {new " + testname + "().test(); }\n" +
+                "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
+                "\n";
+                src.innerClassname="$1innerClass";
+            break;
+            case src9: //(repeating)type annotations on static method of interface
+                /*
+                 *  class Test90{
+                 *    interface I  { 
+                 *      static @A @B @A @B String m() { @A @B @A @B String ret = "I.m"; return ret; }
+                 *    }
+                 *  }
+                 */
+                source = new String( source +
+                "// " + src.description + "\n" +
+                "class "+ testname + "{\n" +
+                "  interface I  { \n" +
+                "    static _As_ _Bs_ String m() { _As_ _Bs_ String ret = \"I.m\"; return ret; }\n" +
+                "  }\n" +
+                "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
+                "\n";
+                src.innerClassname="$I";
+            break;
+        }
+        return imports + source;
+    }
+}