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