FunctionalInterfaceConversionTest.java revision 2933:49d207bf704d
1/* 2 * Copyright (c) 2012, 2015, 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 8004102 8006694 27 * @summary Add lambda tests 28 * perform several automated checks in lambda conversion, esp. around accessibility 29 * temporarily workaround combo tests are causing time out in several platforms 30 * @author Maurizio Cimadamore 31 * @library ../lib 32 * @modules jdk.compiler 33 * @build JavacTestingAbstractThreadedTest 34 * @run main/timeout=600/othervm FunctionalInterfaceConversionTest 35 */ 36 37// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) 38// see JDK-8006746 39 40import java.io.IOException; 41import java.net.URI; 42import java.util.Arrays; 43import javax.tools.Diagnostic; 44import javax.tools.JavaCompiler; 45import javax.tools.JavaFileObject; 46import javax.tools.SimpleJavaFileObject; 47import javax.tools.ToolProvider; 48import com.sun.source.util.JavacTask; 49 50public class FunctionalInterfaceConversionTest 51 extends JavacTestingAbstractThreadedTest 52 implements Runnable { 53 54 enum PackageKind { 55 NO_PKG(""), 56 PKG_A("a"); 57 58 String pkg; 59 60 PackageKind(String pkg) { 61 this.pkg = pkg; 62 } 63 64 String getPkgDecl() { 65 return this == NO_PKG ? 66 "" : 67 "package " + pkg + ";"; 68 } 69 70 String getImportStat() { 71 return this == NO_PKG ? 72 "" : 73 "import " + pkg + ".*;"; 74 } 75 } 76 77 enum SamKind { 78 CLASS("public class Sam { }"), 79 ABSTACT_CLASS("public abstract class Sam { }"), 80 ANNOTATION("public @interface Sam { }"), 81 ENUM("public enum Sam { }"), 82 INTERFACE("public interface Sam { \n #METH; \n }"); 83 84 String sam_str; 85 86 SamKind(String sam_str) { 87 this.sam_str = sam_str; 88 } 89 90 String getSam(String methStr) { 91 return sam_str.replaceAll("#METH", methStr); 92 } 93 } 94 95 enum ModifierKind { 96 PUBLIC("public"), 97 PACKAGE(""); 98 99 String modifier_str; 100 101 ModifierKind(String modifier_str) { 102 this.modifier_str = modifier_str; 103 } 104 105 boolean stricterThan(ModifierKind that) { 106 return this.ordinal() > that.ordinal(); 107 } 108 } 109 110 enum TypeKind { 111 EXCEPTION("Exception"), 112 PKG_CLASS("PackageClass"); 113 114 String typeStr; 115 116 private TypeKind(String typeStr) { 117 this.typeStr = typeStr; 118 } 119 } 120 121 enum ExprKind { 122 LAMBDA("x -> null"), 123 MREF("this::m"); 124 125 String exprStr; 126 127 private ExprKind(String exprStr) { 128 this.exprStr = exprStr; 129 } 130 } 131 132 enum MethodKind { 133 NONE(""), 134 NON_GENERIC("public abstract #R m(#ARG s) throws #T;"), 135 GENERIC("public abstract <X> #R m(#ARG s) throws #T;"); 136 137 String methodTemplate; 138 139 private MethodKind(String methodTemplate) { 140 this.methodTemplate = methodTemplate; 141 } 142 143 String getMethod(TypeKind retType, TypeKind argType, TypeKind thrownType) { 144 return methodTemplate.replaceAll("#R", retType.typeStr). 145 replaceAll("#ARG", argType.typeStr). 146 replaceAll("#T", thrownType.typeStr); 147 } 148 } 149 150 public static void main(String[] args) throws Exception { 151 for (PackageKind samPkg : PackageKind.values()) { 152 for (ModifierKind modKind : ModifierKind.values()) { 153 for (SamKind samKind : SamKind.values()) { 154 for (MethodKind samMeth : MethodKind.values()) { 155 for (MethodKind clientMeth : MethodKind.values()) { 156 for (TypeKind retType : TypeKind.values()) { 157 for (TypeKind argType : TypeKind.values()) { 158 for (TypeKind thrownType : TypeKind.values()) { 159 for (ExprKind exprKind : ExprKind.values()) { 160 pool.execute( 161 new FunctionalInterfaceConversionTest( 162 samPkg, modKind, samKind, 163 samMeth, clientMeth, retType, 164 argType, thrownType, exprKind)); 165 } 166 } 167 } 168 } 169 } 170 } 171 } 172 } 173 } 174 175 checkAfterExec(false); 176 } 177 178 PackageKind samPkg; 179 ModifierKind modKind; 180 SamKind samKind; 181 MethodKind samMeth; 182 MethodKind clientMeth; 183 TypeKind retType; 184 TypeKind argType; 185 TypeKind thrownType; 186 ExprKind exprKind; 187 DiagnosticChecker dc; 188 189 SourceFile samSourceFile = new SourceFile("Sam.java", "#P \n #C") { 190 @Override 191 public String toString() { 192 return template.replaceAll("#P", samPkg.getPkgDecl()). 193 replaceAll("#C", samKind.getSam( 194 samMeth.getMethod(retType, argType, thrownType))); 195 } 196 }; 197 198 SourceFile pkgClassSourceFile = 199 new SourceFile("PackageClass.java", 200 "#P\n #M class PackageClass extends Exception { }") { 201 @Override 202 public String toString() { 203 return template.replaceAll("#P", samPkg.getPkgDecl()). 204 replaceAll("#M", modKind.modifier_str); 205 } 206 }; 207 208 SourceFile clientSourceFile = 209 new SourceFile("Client.java", 210 "#I\n abstract class Client { \n" + 211 " Sam s = #E;\n" + 212 " #M \n }") { 213 @Override 214 public String toString() { 215 return template.replaceAll("#I", samPkg.getImportStat()) 216 .replaceAll("#E", exprKind.exprStr) 217 .replaceAll("#M", clientMeth.getMethod(retType, argType, thrownType)); 218 } 219 }; 220 221 FunctionalInterfaceConversionTest(PackageKind samPkg, ModifierKind modKind, 222 SamKind samKind, MethodKind samMeth, MethodKind clientMeth, 223 TypeKind retType, TypeKind argType, TypeKind thrownType, 224 ExprKind exprKind) { 225 this.samPkg = samPkg; 226 this.modKind = modKind; 227 this.samKind = samKind; 228 this.samMeth = samMeth; 229 this.clientMeth = clientMeth; 230 this.retType = retType; 231 this.argType = argType; 232 this.thrownType = thrownType; 233 this.exprKind = exprKind; 234 this.dc = new DiagnosticChecker(); 235 } 236 237 @Override 238 public void run() { 239 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); 240 241 JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), dc, null, null, 242 Arrays.asList(samSourceFile, pkgClassSourceFile, clientSourceFile)); 243 try { 244 ct.analyze(); 245 } catch (IOException ex) { 246 throw new AssertionError("Test failing with cause", ex.getCause()); 247 } 248 if (dc.errorFound == checkSamConversion()) { 249 throw new AssertionError(samSourceFile + "\n\n" + 250 pkgClassSourceFile + "\n\n" + clientSourceFile); 251 } 252 } 253 254 boolean checkSamConversion() { 255 if (samKind != SamKind.INTERFACE) { 256 //sam type must be an interface 257 return false; 258 } else if (samMeth == MethodKind.NONE) { 259 //interface must have at least a method 260 return false; 261 } else if (exprKind == ExprKind.LAMBDA && 262 samMeth != MethodKind.NON_GENERIC) { 263 //target method for lambda must be non-generic 264 return false; 265 } else if (exprKind == ExprKind.MREF && 266 clientMeth == MethodKind.NONE) { 267 return false; 268 } else if (samPkg != PackageKind.NO_PKG && 269 modKind != ModifierKind.PUBLIC && 270 (retType == TypeKind.PKG_CLASS || 271 argType == TypeKind.PKG_CLASS || 272 thrownType == TypeKind.PKG_CLASS)) { 273 //target must not contain inaccessible types 274 return false; 275 } else { 276 return true; 277 } 278 } 279 280 abstract class SourceFile extends SimpleJavaFileObject { 281 282 protected String template; 283 284 public SourceFile(String filename, String template) { 285 super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE); 286 this.template = template; 287 } 288 289 @Override 290 public CharSequence getCharContent(boolean ignoreEncodingErrors) { 291 return toString(); 292 } 293 294 @Override 295 public abstract String toString(); 296 } 297 298 static class DiagnosticChecker 299 implements javax.tools.DiagnosticListener<JavaFileObject> { 300 301 boolean errorFound = false; 302 303 @Override 304 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 305 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { 306 errorFound = true; 307 } 308 } 309 } 310} 311