SamConversionComboTest.java revision 2702:b9daa6475f12
1/* 2 * Copyright (c) 2011, 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 */ 23 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 */ 32 33import com.sun.source.util.JavacTask; 34import java.net.URI; 35import java.util.Arrays; 36import javax.tools.Diagnostic; 37import javax.tools.JavaCompiler; 38import javax.tools.JavaFileManager; 39import javax.tools.JavaFileObject; 40import javax.tools.SimpleJavaFileObject; 41import javax.tools.ToolProvider; 42 43public class SamConversionComboTest { 44 45 enum FInterface { 46 A("A", "interface A { Integer m(int i); }"), 47 B("B", "interface B { int m(Integer i); }"), 48 C("C", "interface C { int m(Integer i) throws Exception; }"); 49 50 String interfaceType; 51 String interfaceDef; 52 53 FInterface(String interfaceType, String interfaceDef) { 54 this.interfaceType = interfaceType; 55 this.interfaceDef = interfaceDef; 56 } 57 58 String getParameterType() { 59 switch(this) { 60 case A: 61 return "int"; 62 case B: 63 case C: 64 return "Integer"; 65 default: 66 return null; 67 } 68 } 69 } 70 71 enum Context { 72 ASSIGNMENT("#FType f = #LBody;"), 73 METHOD_CALL("void method1(#FType f) { }\n" + 74 " void method2() {\n" + 75 " method1(#LBody);\n" + 76 " }"), 77 CONSTRUCTOR("X x = new X(#LBody);"), 78 RETURN_OF_METHOD("#FType method1() {\n" + 79 " return #LBody;\n" + 80 "}"), 81 ARRAY_INITIALIZER("Object[] oarray = {\"a\", 1, (#FType)#LBody};"), 82 LAMBDA_BODY("#FType f = n -> ((#FType)#LBody).m(n);"), 83 CAST("void test() throws Exception { int n = ((#FType)#LBody).m(1); }"), 84 CONDITIONAL_EXPRESSION("#FType f = 2 > 1 ? #LBody : null;"); 85 86 String context; 87 88 Context(String context) { 89 this.context = context; 90 } 91 92 String getContext(FInterface f, LambdaKind lk, LambdaBody lb, ReturnValue rv) { 93 return context.replace("#FType", f.interfaceType).replace("#LBody", lb.getLambdaBody(f, lk, rv)); 94 } 95 } 96 97 enum LambdaKind { 98 EXPRESSION("#VAL"), 99 STATEMENT("{return #VAL;}"), 100 EXCEPTION_STMT("{throw new Exception();}"); 101 102 String stmt; 103 104 LambdaKind(String stmt) { 105 this.stmt = stmt; 106 } 107 } 108 109 enum ReturnValue { 110 INT("i + 1"), 111 INTEGER("new Integer(i+1)"), 112 INT2("i.intValue() + 1"), 113 STRING("i + \"\""), 114 DOUBLE("i * 1.0"); 115 116 String rValue; 117 118 ReturnValue(String rValue) { 119 this.rValue = rValue; 120 } 121 } 122 123 enum LambdaBody { 124 IMPLICIT("i -> #RET"),//type inferred 125 EXPLICIT("(#Type i) -> #RET");//explicit type 126 127 String bodyStr; 128 129 LambdaBody(String bodyStr) { 130 this.bodyStr = bodyStr; 131 } 132 133 String getLambdaBody(FInterface fi, LambdaKind lk, ReturnValue rv) { 134 return bodyStr.replace("#Type", fi.getParameterType()).replace("#RET", lk.stmt.replace("#VAL", rv.rValue)); 135 } 136 } 137 138 boolean checkSamConversion() { 139 if(lambdaKind != LambdaKind.EXCEPTION_STMT && (returnValue == ReturnValue.DOUBLE || returnValue == ReturnValue.STRING)) //return type mismatch 140 return false; 141 if(context != Context.CONSTRUCTOR) {//context other than construcotr argument 142 if(fInterface != FInterface.C && lambdaKind == LambdaKind.EXCEPTION_STMT) 143 return false; 144 if(fInterface == FInterface.A && returnValue == ReturnValue.INT2) 145 return false; 146 } 147 else { //constructor argument context 148 //match X(A a) or X(B b) or X(C c) 149 if (lambdaKind == LambdaKind.EXCEPTION_STMT) { 150 return false; //ambiguous target type 151 } 152 else if(lambdaBody == LambdaBody.IMPLICIT) { 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 } 166 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 }; 175 176 String clientTemplate = "class Client {\n" + 177 " #Context\n" + 178 "}\n\n" + 179 180 "class X {\n" + 181 " int value = 0;\n\n" + 182 183 " X(A a) {\n" + 184 " value = a.m(6);\n" + 185 " }\n\n" + 186 187 " X(B b) {\n" + 188 " value = b.m(7);\n" + 189 " }\n\n" + 190 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 }; 202 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"))); 209 210 DiagnosticChecker dc = new DiagnosticChecker(); 211 JavacTask ct = (JavacTask)comp.getTask(null, fm, dc, null, null, Arrays.asList(samSourceFile, clientSourceFile)); 212 try { 213 ct.analyze(); 214 } catch (Exception e) { 215 throw new AssertionError("failing SAM source file \n" + samSourceFile + "\n\n" + "failing client source file \n"+ clientSourceFile); 216 } 217 if (dc.errorFound == checkSamConversion()) { 218 throw new AssertionError(samSourceFile + "\n\n" + clientSourceFile); 219 } 220 count++; 221 } 222 223 abstract class SourceFile extends SimpleJavaFileObject { 224 225 protected String template; 226 227 public SourceFile(String filename, String template) { 228 super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE); 229 this.template = template; 230 } 231 232 @Override 233 public CharSequence getCharContent(boolean ignoreEncodingErrors) { 234 return toString(); 235 } 236 237 public abstract String toString(); 238 } 239 240 static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> { 241 242 boolean errorFound = false; 243 244 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 245 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { 246 errorFound = true; 247 } 248 } 249 } 250 251 FInterface fInterface; 252 Context context; 253 LambdaBody lambdaBody; 254 LambdaKind lambdaKind; 255 ReturnValue returnValue; 256 static int count = 0; 257 258 static JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); 259 static JavaFileManager fm = comp.getStandardFileManager(null, null, null); 260 261 SamConversionComboTest(FInterface f, Context c, LambdaBody lb, LambdaKind lk, ReturnValue rv) { 262 fInterface = f; 263 context = c; 264 lambdaKind = lk; 265 lambdaBody = lb; 266 returnValue = rv; 267 } 268 269 public static void main(String[] args) throws Exception { 270 try { 271 for(Context ct : Context.values()) { 272 for (FInterface fi : FInterface.values()) { 273 for (LambdaKind lk: LambdaKind.values()) { 274 for (LambdaBody lb : LambdaBody.values()) { 275 for(ReturnValue rv : ReturnValue.values()) { 276 new SamConversionComboTest(fi, ct, lb, lk, rv).test(); 277 } 278 } 279 } 280 } 281 } 282 System.out.println("total tests: " + count); 283 } finally { 284 fm.close(); 285 } 286 } 287} 288