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