test/tools/javac/lambda/lambdaExpression/SamConversionComboTest.java

Sat, 17 Nov 2012 19:01:03 +0000

author
mcimadamore
date
Sat, 17 Nov 2012 19:01:03 +0000
changeset 1415
01c9d4161882
child 1510
7873d37f5b37
permissions
-rw-r--r--

8003280: Add lambda tests
Summary: Turn on lambda expression, method reference and default method support
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2011, 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 8003280
    27  * @summary Add lambda tests
    28  *   Test SAM conversion of lambda expressions in combinations of different contexts,
    29  *           lambda body types(statement/expression), explict/implicit target type etc, to verify
    30  *           SAM conversion being conducted successfully as expected.
    31  */
    33 import com.sun.source.util.JavacTask;
    34 import java.net.URI;
    35 import java.util.Arrays;
    36 import javax.tools.Diagnostic;
    37 import javax.tools.JavaCompiler;
    38 import javax.tools.JavaFileObject;
    39 import javax.tools.SimpleJavaFileObject;
    40 import javax.tools.ToolProvider;
    42 public class SamConversionComboTest {
    44     enum FInterface {
    45         A("A", "interface A { Integer m(int i); }"),
    46         B("B", "interface B { int m(Integer i); }"),
    47         C("C", "interface C { int m(Integer i) throws Exception; }");
    49         String interfaceType;
    50         String interfaceDef;
    52         FInterface(String interfaceType, String interfaceDef) {
    53             this.interfaceType = interfaceType;
    54             this.interfaceDef = interfaceDef;
    55         }
    57         String getParameterType() {
    58             switch(this) {
    59             case A:
    60                 return "int";
    61             case B:
    62             case C:
    63                 return "Integer";
    64             default:
    65                 return null;
    66             }
    67         }
    68     }
    70     enum Context {
    71         ASSIGNMENT("#FType f = #LBody;"),
    72         METHOD_CALL("void method1(#FType f) { }\n" +
    73                     "    void method2() {\n" +
    74                     "        method1(#LBody);\n" +
    75                     "    }"),
    76         CONSTRUCTOR("X x = new X(#LBody);"),
    77         RETURN_OF_METHOD("#FType method1() {\n" +
    78                          "    return #LBody;\n" +
    79                          "}"),
    80         ARRAY_INITIALIZER("Object[] oarray = {\"a\", 1, (#FType)#LBody};"),
    81         LAMBDA_BODY("#FType f = n -> ((#FType)#LBody).m(n);"),
    82         CAST("void test() throws Exception { int n = ((#FType)#LBody).m(1); }"),
    83         CONDITIONAL_EXPRESSION("#FType f = 2 > 1 ? #LBody : null;");
    85         String context;
    87         Context(String context) {
    88             this.context = context;
    89         }
    91         String getContext(FInterface f, LambdaKind lk, LambdaBody lb, ReturnValue rv) {
    92             return context.replace("#FType", f.interfaceType).replace("#LBody", lb.getLambdaBody(f, lk, rv));
    93         }
    94     }
    96     enum LambdaKind {
    97         EXPRESSION("#VAL"),
    98         STATEMENT("{return #VAL;}"),
    99         EXCEPTION_STMT("{throw new Exception();}");
   101         String stmt;
   103         LambdaKind(String stmt) {
   104             this.stmt = stmt;
   105         }
   106     }
   108     enum ReturnValue {
   109         INT("i + 1"),
   110         INTEGER("new Integer(i+1)"),
   111         INT2("i.intValue() + 1"),
   112         STRING("i + \"\""),
   113         DOUBLE("i * 1.0");
   115         String rValue;
   117         ReturnValue(String rValue) {
   118             this.rValue = rValue;
   119         }
   120     }
   122     enum LambdaBody {
   123         IMPLICIT("i -> #RET"),//type inferred
   124         EXPLICIT("(#Type i) -> #RET");//explicit type
   126         String bodyStr;
   128         LambdaBody(String bodyStr) {
   129             this.bodyStr = bodyStr;
   130         }
   132         String getLambdaBody(FInterface fi, LambdaKind lk, ReturnValue rv) {
   133             return bodyStr.replace("#Type", fi.getParameterType()).replace("#RET", lk.stmt.replace("#VAL", rv.rValue));
   134         }
   135     }
   137     boolean checkSamConversion() {
   138         if(lambdaKind != LambdaKind.EXCEPTION_STMT && (returnValue == ReturnValue.DOUBLE || returnValue == ReturnValue.STRING)) //return type mismatch
   139             return false;
   140         if(context != Context.CONSTRUCTOR) {//context other than construcotr argument
   141             if(fInterface != FInterface.C && lambdaKind == LambdaKind.EXCEPTION_STMT)
   142                 return false;
   143             if(fInterface == FInterface.A && returnValue == ReturnValue.INT2)
   144                 return false;
   145         }
   146         else { //constructor argument context
   147             //match X(A a) or X(B b) or X(C c)
   148             if (lambdaKind == LambdaKind.EXCEPTION_STMT) {
   149                 return false; //ambiguous target type
   150             }
   151             else if(lambdaBody == LambdaBody.IMPLICIT) {
   152                 if(returnValue != ReturnValue.INTEGER) //ambiguous target type
   153                     return false;
   154             }
   155             else { //explicit parameter type
   156                 if(fInterface.getParameterType().equals("Integer")) //ambiguous target type
   157                 //e.g. X x = new X((Integer i) -> i + 1);
   158                     return false;
   159                 if(returnValue == ReturnValue.INT2)
   160                 //e.g. X x = new X(int i -> i.intValue() + 1);
   161                     return false;
   162             }
   163         }
   164         return true;
   165     }
   167     SourceFile samSourceFile = new SourceFile("FInterface.java", "#C") {
   168         public String toString() {
   169             String interfaces = "";
   170             for(FInterface fi : FInterface.values())
   171                 interfaces += fi.interfaceDef + "\n";
   172             return template.replace("#C", interfaces);
   173         }
   174     };
   176     String clientTemplate = "class Client {\n" +
   177                             "    #Context\n" +
   178                             "}\n\n" +
   180                             "class X {\n" +
   181                             "    int value = 0;\n\n" +
   183                             "    X(A a) {\n" +
   184                             "        value = a.m(6);\n" +
   185                             "    }\n\n" +
   187                             "    X(B b) {\n" +
   188                             "        value = b.m(7);\n" +
   189                             "    }\n\n" +
   191                             "    X(C c) {\n" +
   192                             "        try {\n" +
   193                             "            value = c.m(8);\n" +
   194                             "        } catch (Exception e){}\n" +
   195                             "    }\n" +
   196                             "}";
   197     SourceFile clientSourceFile = new SourceFile("Client.java", clientTemplate) {
   198         public String toString() {
   199             return template.replace("#Context", context.getContext(fInterface, lambdaKind, lambdaBody, returnValue));
   200         }
   201     };
   203     void test() throws Exception {
   204         System.out.println("\n====================================");
   205         System.out.println(fInterface + ", " +  context + ", " + lambdaKind + ", " + lambdaBody + ", " + returnValue);
   206         System.out.println(samSourceFile + "\n");
   207         String clientFileStr = clientSourceFile.toString();
   208         System.out.println(clientFileStr.substring(0, clientFileStr.indexOf("\n\n")));
   210         final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
   211         DiagnosticChecker dc = new DiagnosticChecker();
   212         JavacTask ct = (JavacTask)tool.getTask(null, null, dc, null, null, Arrays.asList(samSourceFile, clientSourceFile));
   213         ct.analyze();
   214         if (dc.errorFound == checkSamConversion()) {
   215             throw new AssertionError(samSourceFile + "\n\n" + clientSourceFile);
   216         }
   217         count++;
   218     }
   220     abstract class SourceFile extends SimpleJavaFileObject {
   222         protected String template;
   224         public SourceFile(String filename, String template) {
   225             super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
   226             this.template = template;
   227         }
   229         @Override
   230         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   231             return toString();
   232         }
   234         public abstract String toString();
   235     }
   237     static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
   239         boolean errorFound = false;
   241         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   242             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
   243                 errorFound = true;
   244             }
   245         }
   246     }
   248     FInterface fInterface;
   249     Context context;
   250     LambdaBody lambdaBody;
   251     LambdaKind lambdaKind;
   252     ReturnValue returnValue;
   253     static int count = 0;
   255     SamConversionComboTest(FInterface f, Context c, LambdaBody lb, LambdaKind lk, ReturnValue rv) {
   256         fInterface = f;
   257         context = c;
   258         lambdaKind = lk;
   259         lambdaBody = lb;
   260         returnValue = rv;
   261     }
   263     public static void main(String[] args) throws Exception {
   264         for(Context ct : Context.values()) {
   265             for (FInterface fi : FInterface.values()) {
   266                 for (LambdaKind lk: LambdaKind.values()) {
   267                     for (LambdaBody lb : LambdaBody.values()) {
   268                         for(ReturnValue rv : ReturnValue.values()) {
   269                             new SamConversionComboTest(fi, ct, lb, lk, rv).test();
   270                         }
   271                     }
   272                 }
   273             }
   274         }
   275         System.out.println("total tests: " + count);
   276     }
   277 }

mercurial