SamConversionComboTest.java revision 2253:3b4db9e3824d
1268899Sbapt/* 2234949Sbapt * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. 3234949Sbapt * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4234949Sbapt * 5268899Sbapt * This code is free software; you can redistribute it and/or modify it 6268899Sbapt * under the terms of the GNU General Public License version 2 only, as 7268899Sbapt * published by the Free Software Foundation. 8268899Sbapt * 9268899Sbapt * This code is distributed in the hope that it will be useful, but WITHOUT 10268899Sbapt * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11268899Sbapt * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12268899Sbapt * version 2 for more details (a copy is included in the LICENSE file that 13268899Sbapt * accompanied this code). 14268899Sbapt * 15268899Sbapt * You should have received a copy of the GNU General Public License version 16234949Sbapt * 2 along with this work; if not, write to the Free Software Foundation, 17234949Sbapt * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18234949Sbapt * 19234949Sbapt * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20234949Sbapt * or visit www.oracle.com if you need additional information or have any 21234949Sbapt * questions. 22234949Sbapt */ 23234949Sbapt 24234949Sbapt/** 25234949Sbapt * @test 26234949Sbapt * @bug 8003280 27234949Sbapt * @summary Add lambda tests 28234949Sbapt * Test SAM conversion of lambda expressions in combinations of different contexts, 29234949Sbapt * lambda body types(statement/expression), explict/implicit target type etc, to verify 30234949Sbapt * SAM conversion being conducted successfully as expected. 31234949Sbapt */ 32234949Sbapt 33234949Sbaptimport com.sun.source.util.JavacTask; 34234949Sbaptimport java.net.URI; 35234949Sbaptimport java.util.Arrays; 36234949Sbaptimport javax.tools.Diagnostic; 37234949Sbaptimport javax.tools.JavaCompiler; 38234949Sbaptimport javax.tools.JavaFileObject; 39234949Sbaptimport javax.tools.SimpleJavaFileObject; 40234949Sbaptimport javax.tools.ToolProvider; 41234949Sbapt 42234949Sbaptpublic class SamConversionComboTest { 43234949Sbapt 44234949Sbapt enum FInterface { 45234949Sbapt A("A", "interface A { Integer m(int i); }"), 46234949Sbapt B("B", "interface B { int m(Integer i); }"), 47234949Sbapt C("C", "interface C { int m(Integer i) throws Exception; }"); 48234949Sbapt 49234949Sbapt String interfaceType; 50234949Sbapt String interfaceDef; 51234949Sbapt 52234949Sbapt FInterface(String interfaceType, String interfaceDef) { 53234949Sbapt this.interfaceType = interfaceType; 54234949Sbapt this.interfaceDef = interfaceDef; 55234949Sbapt } 56234949Sbapt 57234949Sbapt String getParameterType() { 58234949Sbapt switch(this) { 59234949Sbapt case A: 60234949Sbapt return "int"; 61234949Sbapt case B: 62234949Sbapt case C: 63234949Sbapt return "Integer"; 64234949Sbapt default: 65234949Sbapt return null; 66234949Sbapt } 67234949Sbapt } 68234949Sbapt } 69234949Sbapt 70234949Sbapt enum Context { 71234949Sbapt ASSIGNMENT("#FType f = #LBody;"), 72234949Sbapt METHOD_CALL("void method1(#FType f) { }\n" + 73234949Sbapt " void method2() {\n" + 74234949Sbapt " method1(#LBody);\n" + 75234949Sbapt " }"), 76234949Sbapt CONSTRUCTOR("X x = new X(#LBody);"), 77234949Sbapt RETURN_OF_METHOD("#FType method1() {\n" + 78234949Sbapt " return #LBody;\n" + 79234949Sbapt "}"), 80234949Sbapt ARRAY_INITIALIZER("Object[] oarray = {\"a\", 1, (#FType)#LBody};"), 81234949Sbapt LAMBDA_BODY("#FType f = n -> ((#FType)#LBody).m(n);"), 82234949Sbapt CAST("void test() throws Exception { int n = ((#FType)#LBody).m(1); }"), 83234949Sbapt CONDITIONAL_EXPRESSION("#FType f = 2 > 1 ? #LBody : null;"); 84234949Sbapt 85234949Sbapt String context; 86234949Sbapt 87234949Sbapt Context(String context) { 88234949Sbapt this.context = context; 89234949Sbapt } 90234949Sbapt 91234949Sbapt String getContext(FInterface f, LambdaKind lk, LambdaBody lb, ReturnValue rv) { 92234949Sbapt return context.replace("#FType", f.interfaceType).replace("#LBody", lb.getLambdaBody(f, lk, rv)); 93234949Sbapt } 94234949Sbapt } 95234949Sbapt 96234949Sbapt enum LambdaKind { 97234949Sbapt EXPRESSION("#VAL"), 98234949Sbapt STATEMENT("{return #VAL;}"), 99234949Sbapt EXCEPTION_STMT("{throw new Exception();}"); 100234949Sbapt 101234949Sbapt String stmt; 102234949Sbapt 103234949Sbapt LambdaKind(String stmt) { 104234949Sbapt this.stmt = stmt; 105234949Sbapt } 106234949Sbapt } 107234949Sbapt 108234949Sbapt enum ReturnValue { 109234949Sbapt INT("i + 1"), 110234949Sbapt INTEGER("new Integer(i+1)"), 111234949Sbapt INT2("i.intValue() + 1"), 112234949Sbapt STRING("i + \"\""), 113234949Sbapt DOUBLE("i * 1.0"); 114234949Sbapt 115234949Sbapt String rValue; 116234949Sbapt 117234949Sbapt ReturnValue(String rValue) { 118234949Sbapt this.rValue = rValue; 119234949Sbapt } 120234949Sbapt } 121234949Sbapt 122234949Sbapt enum LambdaBody { 123234949Sbapt IMPLICIT("i -> #RET"),//type inferred 124234949Sbapt EXPLICIT("(#Type i) -> #RET");//explicit type 125234949Sbapt 126234949Sbapt String bodyStr; 127234949Sbapt 128234949Sbapt LambdaBody(String bodyStr) { 129234949Sbapt this.bodyStr = bodyStr; 130234949Sbapt } 131234949Sbapt 132234949Sbapt String getLambdaBody(FInterface fi, LambdaKind lk, ReturnValue rv) { 133234949Sbapt return bodyStr.replace("#Type", fi.getParameterType()).replace("#RET", lk.stmt.replace("#VAL", rv.rValue)); 134234949Sbapt } 135234949Sbapt } 136234949Sbapt 137234949Sbapt boolean checkSamConversion() { 138234949Sbapt if(lambdaKind != LambdaKind.EXCEPTION_STMT && (returnValue == ReturnValue.DOUBLE || returnValue == ReturnValue.STRING)) //return type mismatch 139234949Sbapt return false; 140234949Sbapt if(context != Context.CONSTRUCTOR) {//context other than construcotr argument 141234949Sbapt if(fInterface != FInterface.C && lambdaKind == LambdaKind.EXCEPTION_STMT) 142234949Sbapt return false; 143234949Sbapt if(fInterface == FInterface.A && returnValue == ReturnValue.INT2) 144234949Sbapt return false; 145234949Sbapt } 146234949Sbapt else { //constructor argument context 147234949Sbapt //match X(A a) or X(B b) or X(C c) 148234949Sbapt if (lambdaKind == LambdaKind.EXCEPTION_STMT) { 149234949Sbapt return false; //ambiguous target type 150234949Sbapt } 151234949Sbapt else if(lambdaBody == LambdaBody.IMPLICIT) { 152234949Sbapt return false; 153234949Sbapt } 154234949Sbapt else { //explicit parameter type 155234949Sbapt if(fInterface.getParameterType().equals("Integer")) //ambiguous target type 156234949Sbapt //e.g. X x = new X((Integer i) -> i + 1); 157234949Sbapt return false; 158234949Sbapt if(returnValue == ReturnValue.INT2) 159234949Sbapt //e.g. X x = new X(int i -> i.intValue() + 1); 160234949Sbapt return false; 161234949Sbapt } 162234949Sbapt } 163234949Sbapt return true; 164234949Sbapt } 165234949Sbapt 166234949Sbapt SourceFile samSourceFile = new SourceFile("FInterface.java", "#C") { 167234949Sbapt public String toString() { 168234949Sbapt String interfaces = ""; 169234949Sbapt for(FInterface fi : FInterface.values()) 170234949Sbapt interfaces += fi.interfaceDef + "\n"; 171234949Sbapt return template.replace("#C", interfaces); 172234949Sbapt } 173234949Sbapt }; 174234949Sbapt 175234949Sbapt String clientTemplate = "class Client {\n" + 176234949Sbapt " #Context\n" + 177234949Sbapt "}\n\n" + 178234949Sbapt 179234949Sbapt "class X {\n" + 180234949Sbapt " int value = 0;\n\n" + 181234949Sbapt 182234949Sbapt " X(A a) {\n" + 183234949Sbapt " value = a.m(6);\n" + 184234949Sbapt " }\n\n" + 185234949Sbapt 186234949Sbapt " X(B b) {\n" + 187234949Sbapt " value = b.m(7);\n" + 188234949Sbapt " }\n\n" + 189234949Sbapt 190234949Sbapt " X(C c) {\n" + 191234949Sbapt " try {\n" + 192234949Sbapt " value = c.m(8);\n" + 193234949Sbapt " } catch (Exception e){}\n" + 194240517Sbapt " }\n" + 195234949Sbapt "}"; 196234949Sbapt SourceFile clientSourceFile = new SourceFile("Client.java", clientTemplate) { 197234949Sbapt public String toString() { 198234949Sbapt return template.replace("#Context", context.getContext(fInterface, lambdaKind, lambdaBody, returnValue)); 199234949Sbapt } 200234949Sbapt }; 201234949Sbapt 202234949Sbapt void test() throws Exception { 203234949Sbapt System.out.println("\n===================================="); 204268899Sbapt System.out.println(fInterface + ", " + context + ", " + lambdaKind + ", " + lambdaBody + ", " + returnValue); 205234949Sbapt System.out.println(samSourceFile + "\n"); 206234949Sbapt String clientFileStr = clientSourceFile.toString(); 207234949Sbapt System.out.println(clientFileStr.substring(0, clientFileStr.indexOf("\n\n"))); 208234949Sbapt 209234949Sbapt final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); 210234949Sbapt DiagnosticChecker dc = new DiagnosticChecker(); 211234949Sbapt JavacTask ct = (JavacTask)tool.getTask(null, null, dc, null, null, Arrays.asList(samSourceFile, clientSourceFile)); 212234949Sbapt ct.analyze(); 213234949Sbapt if (dc.errorFound == checkSamConversion()) { 214234949Sbapt throw new AssertionError(samSourceFile + "\n\n" + clientSourceFile); 215234949Sbapt } 216234949Sbapt count++; 217234949Sbapt } 218234949Sbapt 219234949Sbapt abstract class SourceFile extends SimpleJavaFileObject { 220234949Sbapt 221234949Sbapt protected String template; 222234949Sbapt 223234949Sbapt public SourceFile(String filename, String template) { 224234949Sbapt super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE); 225234949Sbapt this.template = template; 226234949Sbapt } 227234949Sbapt 228234949Sbapt @Override 229234949Sbapt public CharSequence getCharContent(boolean ignoreEncodingErrors) { 230234949Sbapt return toString(); 231234949Sbapt } 232234949Sbapt 233234949Sbapt public abstract String toString(); 234234949Sbapt } 235234949Sbapt 236234949Sbapt static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> { 237234949Sbapt 238234949Sbapt boolean errorFound = false; 239268899Sbapt 240268899Sbapt public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 241268899Sbapt if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { 242234949Sbapt errorFound = true; 243234949Sbapt } 244234949Sbapt } 245234949Sbapt } 246268899Sbapt 247234949Sbapt FInterface fInterface; 248234949Sbapt Context context; 249234949Sbapt LambdaBody lambdaBody; 250268899Sbapt LambdaKind lambdaKind; 251234949Sbapt ReturnValue returnValue; 252234949Sbapt static int count = 0; 253234949Sbapt 254234949Sbapt SamConversionComboTest(FInterface f, Context c, LambdaBody lb, LambdaKind lk, ReturnValue rv) { 255268899Sbapt fInterface = f; 256234949Sbapt context = c; 257234949Sbapt lambdaKind = lk; 258234949Sbapt lambdaBody = lb; 259234949Sbapt returnValue = rv; 260234949Sbapt } 261234949Sbapt 262234949Sbapt public static void main(String[] args) throws Exception { 263234949Sbapt for(Context ct : Context.values()) { 264234949Sbapt for (FInterface fi : FInterface.values()) { 265234949Sbapt for (LambdaKind lk: LambdaKind.values()) { 266234949Sbapt for (LambdaBody lb : LambdaBody.values()) { 267234949Sbapt for(ReturnValue rv : ReturnValue.values()) { 268234949Sbapt new SamConversionComboTest(fi, ct, lb, lk, rv).test(); 269234949Sbapt } 270234949Sbapt } 271234949Sbapt } 272234949Sbapt } 273234949Sbapt } 274234949Sbapt System.out.println("total tests: " + count); 275234949Sbapt } 276234949Sbapt} 277234949Sbapt