langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java
changeset 14723 46aa71a5e4e0
child 15040 99fd9483d3f0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/FunctionalInterfaceConversionTest.java	Fri Nov 30 15:14:25 2012 +0000
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2012, 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 8003280 8004102
+ * @summary Add lambda tests
+ *  perform several automated checks in lambda conversion, esp. around accessibility
+ * @author  Maurizio Cimadamore
+ * @run main FunctionalInterfaceConversionTest
+ */
+
+import com.sun.source.util.JavacTask;
+import java.net.URI;
+import java.util.Arrays;
+import javax.tools.Diagnostic;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+public class FunctionalInterfaceConversionTest {
+
+    enum PackageKind {
+        NO_PKG(""),
+        PKG_A("a");
+
+        String pkg;
+
+        PackageKind(String pkg) {
+            this.pkg = pkg;
+        }
+
+        String getPkgDecl() {
+            return this == NO_PKG ?
+                "" :
+                "package " + pkg + ";";
+        }
+
+        String getImportStat() {
+            return this == NO_PKG ?
+                "" :
+                "import " + pkg + ".*;";
+        }
+    }
+
+    enum SamKind {
+        CLASS("public class Sam {  }"),
+        ABSTACT_CLASS("public abstract class Sam {  }"),
+        ANNOTATION("public @interface Sam {  }"),
+        ENUM("public enum Sam { }"),
+        INTERFACE("public interface Sam { \n #METH; \n }");
+
+        String sam_str;
+
+        SamKind(String sam_str) {
+            this.sam_str = sam_str;
+        }
+
+        String getSam(String methStr) {
+            return sam_str.replaceAll("#METH", methStr);
+        }
+    }
+
+    enum ModifierKind {
+        PUBLIC("public"),
+        PACKAGE("");
+
+        String modifier_str;
+
+        ModifierKind(String modifier_str) {
+            this.modifier_str = modifier_str;
+        }
+
+        boolean stricterThan(ModifierKind that) {
+            return this.ordinal() > that.ordinal();
+        }
+    }
+
+    enum TypeKind {
+        EXCEPTION("Exception"),
+        PKG_CLASS("PackageClass");
+
+        String typeStr;
+
+        private TypeKind(String typeStr) {
+            this.typeStr = typeStr;
+        }
+    }
+
+    enum ExprKind {
+        LAMBDA("x -> null"),
+        MREF("this::m");
+
+        String exprStr;
+
+        private ExprKind(String exprStr) {
+            this.exprStr = exprStr;
+        }
+    }
+
+    enum MethodKind {
+        NONE(""),
+        NON_GENERIC("public abstract #R m(#ARG s) throws #T;"),
+        GENERIC("public abstract <X> #R m(#ARG s) throws #T;");
+
+        String methodTemplate;
+
+        private MethodKind(String methodTemplate) {
+            this.methodTemplate = methodTemplate;
+        }
+
+        String getMethod(TypeKind retType, TypeKind argType, TypeKind thrownType) {
+            return methodTemplate.replaceAll("#R", retType.typeStr).
+                    replaceAll("#ARG", argType.typeStr).
+                    replaceAll("#T", thrownType.typeStr);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+        StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+        for (PackageKind samPkg : PackageKind.values()) {
+            for (ModifierKind modKind : ModifierKind.values()) {
+                for (SamKind samKind : SamKind.values()) {
+                    for (MethodKind samMeth : MethodKind.values()) {
+                        for (MethodKind clientMeth : MethodKind.values()) {
+                            for (TypeKind retType : TypeKind.values()) {
+                                for (TypeKind argType : TypeKind.values()) {
+                                    for (TypeKind thrownType : TypeKind.values()) {
+                                        for (ExprKind exprKind : ExprKind.values()) {
+                                            new FunctionalInterfaceConversionTest(samPkg, modKind, samKind,
+                                                    samMeth, clientMeth, retType, argType, thrownType, exprKind).test(comp, fm);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    PackageKind samPkg;
+    ModifierKind modKind;
+    SamKind samKind;
+    MethodKind samMeth;
+    MethodKind clientMeth;
+    TypeKind retType;
+    TypeKind argType;
+    TypeKind thrownType;
+    ExprKind exprKind;
+    DiagnosticChecker dc;
+
+    SourceFile samSourceFile = new SourceFile("Sam.java", "#P \n #C") {
+        public String toString() {
+            return template.replaceAll("#P", samPkg.getPkgDecl()).
+                    replaceAll("#C", samKind.getSam(samMeth.getMethod(retType, argType, thrownType)));
+        }
+    };
+
+    SourceFile pkgClassSourceFile = new SourceFile("PackageClass.java",
+                                                   "#P\n #M class PackageClass extends Exception { }") {
+        public String toString() {
+            return template.replaceAll("#P", samPkg.getPkgDecl()).
+                    replaceAll("#M", modKind.modifier_str);
+        }
+    };
+
+    SourceFile clientSourceFile = new SourceFile("Client.java",
+                                                 "#I\n abstract class Client { \n" +
+                                                 "  Sam s = #E;\n" +
+                                                 "  #M \n }") {
+        public String toString() {
+            return template.replaceAll("#I", samPkg.getImportStat())
+                    .replaceAll("#E", exprKind.exprStr)
+                    .replaceAll("#M", clientMeth.getMethod(retType, argType, thrownType));
+        }
+    };
+
+    FunctionalInterfaceConversionTest(PackageKind samPkg, ModifierKind modKind, SamKind samKind,
+            MethodKind samMeth, MethodKind clientMeth, TypeKind retType, TypeKind argType,
+            TypeKind thrownType, ExprKind exprKind) {
+        this.samPkg = samPkg;
+        this.modKind = modKind;
+        this.samKind = samKind;
+        this.samMeth = samMeth;
+        this.clientMeth = clientMeth;
+        this.retType = retType;
+        this.argType = argType;
+        this.thrownType = thrownType;
+        this.exprKind = exprKind;
+        this.dc = new DiagnosticChecker();
+    }
+
+    void test(JavaCompiler comp, StandardJavaFileManager fm) throws Exception {
+        JavacTask ct = (JavacTask)comp.getTask(null, fm, dc,
+                null, null, Arrays.asList(samSourceFile, pkgClassSourceFile, clientSourceFile));
+        ct.analyze();
+        if (dc.errorFound == checkSamConversion()) {
+            throw new AssertionError(samSourceFile + "\n\n" + pkgClassSourceFile + "\n\n" + clientSourceFile);
+        }
+    }
+
+    boolean checkSamConversion() {
+        if (samKind != SamKind.INTERFACE) {
+            //sam type must be an interface
+            return false;
+        } else if (samMeth == MethodKind.NONE) {
+            //interface must have at least a method
+            return false;
+        } else if (exprKind == ExprKind.LAMBDA &&
+                samMeth != MethodKind.NON_GENERIC) {
+            //target method for lambda must be non-generic
+            return false;
+        } else if (exprKind == ExprKind.MREF &&
+                clientMeth == MethodKind.NONE) {
+            return false;
+        } else if (samPkg != PackageKind.NO_PKG &&
+                modKind != ModifierKind.PUBLIC &&
+                (retType == TypeKind.PKG_CLASS ||
+                argType == TypeKind.PKG_CLASS ||
+                thrownType == TypeKind.PKG_CLASS)) {
+            //target must not contain inaccessible types
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    abstract class SourceFile extends SimpleJavaFileObject {
+
+        protected String template;
+
+        public SourceFile(String filename, String template) {
+            super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
+            this.template = template;
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return toString();
+        }
+
+        public abstract String toString();
+    }
+
+    static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
+
+        boolean errorFound = false;
+
+        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+                errorFound = true;
+            }
+        }
+    }
+}