OpenModulesTest.java revision 3792:d516975e8110
1/*
2 * Copyright (c) 2016, 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 * @summary tests for multi-module mode compilation
27 * @library /tools/lib
28 * @modules jdk.compiler/com.sun.tools.javac.api
29 *          jdk.compiler/com.sun.tools.javac.main
30 *          jdk.jdeps/com.sun.tools.classfile
31 *          jdk.jdeps/com.sun.tools.javap
32 * @build toolbox.ToolBox toolbox.JavacTask toolbox.ModuleBuilder ModuleTestBase
33 * @run main OpenModulesTest
34 */
35
36import java.io.OutputStream;
37import java.nio.file.Files;
38import java.nio.file.Path;
39import java.util.Arrays;
40import java.util.HashMap;
41import java.util.List;
42import java.util.Map;
43import java.util.Objects;
44
45import com.sun.tools.classfile.Attribute;
46import com.sun.tools.classfile.Attributes;
47import com.sun.tools.classfile.ClassFile;
48import com.sun.tools.classfile.ClassWriter;
49import com.sun.tools.classfile.Module_attribute;
50import toolbox.JavacTask;
51import toolbox.JavapTask;
52import toolbox.Task;
53import toolbox.Task.Expect;
54import toolbox.Task.OutputKind;
55
56public class OpenModulesTest extends ModuleTestBase {
57
58    public static void main(String... args) throws Exception {
59        new OpenModulesTest().runTests();
60    }
61
62    @Test
63    public void testStrongModule(Path base) throws Exception {
64        Path m1 = base.resolve("m1");
65        tb.writeJavaFiles(m1,
66                          "module m1 { exports api1; opens api2; }",
67                          "package api1; public class Api1 {}",
68                          "package api2; public class Api2 {}",
69                          "package impl; public class Impl {}");
70        Path classes = base.resolve("classes");
71        Path m1Classes = classes.resolve("m1");
72        tb.createDirectories(m1Classes);
73
74        String log = new JavacTask(tb)
75                .outdir(m1Classes)
76                .files(findJavaFiles(m1))
77                .run()
78                .writeAll()
79                .getOutput(Task.OutputKind.DIRECT);
80
81        if (!log.isEmpty())
82            throw new Exception("expected output not found: " + log);
83
84        String decompiled = new JavapTask(tb)
85                .options("--system", "none", "-bootclasspath", "")
86                .classes(m1Classes.resolve("module-info.class").toString())
87                .run()
88                .writeAll()
89                .getOutput(OutputKind.DIRECT)
90                .replace(System.getProperty("line.separator"), "\n");
91
92        String expected = "module m1 {\n" +
93                          "  requires java.base;\n" +
94                          "  exports api1;\n" +
95                          "  opens api2;\n" +
96                          "}";
97
98        if (!decompiled.contains(expected)) {
99            throw new Exception("expected output not found: " + decompiled);
100        }
101
102        //compiling against a strong module read from binary:
103        Path m2 = base.resolve("m2");
104        tb.writeJavaFiles(m2,
105                          "module m2 { requires m1; }",
106                          "package test; public class Test { api1.Api1 a1; api2.Api2 a2; }");
107        Path m2Classes = classes.resolve("m2");
108        tb.createDirectories(m2Classes);
109
110        List<String> log2 = new JavacTask(tb)
111                .options("--module-path", m1Classes.toString(),
112                         "-XDrawDiagnostics")
113                .outdir(m2Classes)
114                .files(findJavaFiles(m2))
115                .run(Expect.FAIL)
116                .writeAll()
117                .getOutputLines(Task.OutputKind.DIRECT);
118
119        List<String> expected2 = Arrays.asList("Test.java:1:53: compiler.err.doesnt.exist: api2",
120                                               "1 error");
121        if (!Objects.equals(log2, expected2))
122            throw new Exception("expected output not found: " + log2);
123    }
124
125    @Test
126    public void testOpenModule(Path base) throws Exception {
127        Path m1 = base.resolve("m1");
128        tb.writeJavaFiles(m1,
129                          "open module m1 { exports api1; }",
130                          "package api1; public class Api1 {}",
131                          "package api2; public class Api2 {}",
132                          "package impl; public class Impl {}");
133        Path classes = base.resolve("classes");
134        Path m1Classes = classes.resolve("m1");
135        tb.createDirectories(m1Classes);
136
137        String log = new JavacTask(tb)
138                .outdir(m1Classes)
139                .files(findJavaFiles(m1))
140                .run()
141                .writeAll()
142                .getOutput(Task.OutputKind.DIRECT);
143
144        if (!log.isEmpty())
145            throw new Exception("expected output not found: " + log);
146
147        String decompiled = new JavapTask(tb)
148                .options("--system", "none", "-bootclasspath", "")
149                .classes(m1Classes.resolve("module-info.class").toString())
150                .run()
151                .writeAll()
152                .getOutput(OutputKind.DIRECT)
153                .replace(System.getProperty("line.separator"), "\n");
154
155        String expected = "open module m1 {\n" +
156                          "  requires java.base;\n" +
157                          "  exports api1;\n" +
158                          "}";
159
160        if (!decompiled.contains(expected)) {
161            throw new Exception("expected output not found: " + decompiled);
162        }
163
164        //compiling against a ordinary module read from binary:
165        Path m2 = base.resolve("m2");
166        tb.writeJavaFiles(m2,
167                          "module m2 { requires m1; }",
168                          "package test; public class Test { api1.Api1 a1; api2.Api2 a2; }");
169        Path m2Classes = classes.resolve("m2");
170        tb.createDirectories(m2Classes);
171
172        List<String> log2 = new JavacTask(tb)
173                .options("--module-path", m1Classes.toString(),
174                         "-XDrawDiagnostics")
175                .outdir(m2Classes)
176                .files(findJavaFiles(m2))
177                .run(Expect.FAIL)
178                .writeAll()
179                .getOutputLines(Task.OutputKind.DIRECT);
180
181        List<String> expected2 = Arrays.asList("Test.java:1:53: compiler.err.doesnt.exist: api2",
182                                               "1 error");
183        if (!Objects.equals(log2, expected2))
184            throw new Exception("expected output not found: " + log2);
185    }
186
187    @Test
188    public void testOpenModuleNoOpens(Path base) throws Exception {
189        Path m1 = base.resolve("m1");
190        tb.writeJavaFiles(m1,
191                          "open module m1 { exports api1; opens api2; }",
192                          "package api1; public class Api1 {}",
193                          "package api2; public class Api2 {}",
194                          "package impl; public class Impl {}");
195        Path classes = base.resolve("classes");
196        Path m1Classes = classes.resolve("m1");
197        tb.createDirectories(m1Classes);
198
199        List<String> log = new JavacTask(tb)
200                .options("-XDrawDiagnostics")
201                .outdir(m1Classes)
202                .files(findJavaFiles(m1))
203                .run(Expect.FAIL)
204                .writeAll()
205                .getOutputLines(Task.OutputKind.DIRECT);
206
207        List<String> expected = Arrays.asList("module-info.java:1:32: compiler.err.no.opens.unless.strong",
208                                              "1 error");
209
210        if (!expected.equals(log))
211            throw new Exception("expected output not found: " + log);
212
213    }
214
215    @Test
216    public void testNonZeroOpensInOpen(Path base) throws Exception {
217        Path m1 = base.resolve("m1");
218        tb.writeJavaFiles(m1,
219                          "module m1 { opens api; }",
220                          "package api; public class Api {}");
221        Path classes = base.resolve("classes");
222        Path m1Classes = classes.resolve("m1");
223        tb.createDirectories(m1Classes);
224
225        new JavacTask(tb)
226            .options("-XDrawDiagnostics")
227            .outdir(m1Classes)
228            .files(findJavaFiles(m1))
229            .run(Expect.SUCCESS)
230            .writeAll();
231
232        Path miClass = m1Classes.resolve("module-info.class");
233        ClassFile cf = ClassFile.read(miClass);
234        Module_attribute module = (Module_attribute) cf.attributes.map.get(Attribute.Module);
235        Module_attribute newModule = new Module_attribute(module.attribute_name_index,
236                                                          module.module_name,
237                                                          module.module_flags | Module_attribute.ACC_OPEN,
238                                                          module.requires,
239                                                          module.exports,
240                                                          module.opens,
241                                                          module.uses_index,
242                                                          module.provides);
243        Map<String, Attribute> attrs = new HashMap<>(cf.attributes.map);
244
245        attrs.put(Attribute.Module, newModule);
246
247        Attributes newAttributes = new Attributes(attrs);
248        ClassFile newClassFile = new ClassFile(cf.magic,
249                                               cf.minor_version,
250                                               cf.major_version,
251                                               cf.constant_pool,
252                                               cf.access_flags,
253                                               cf.this_class,
254                                               cf.super_class,
255                                               cf.interfaces,
256                                               cf.fields,
257                                               cf.methods,
258                                               newAttributes);
259
260        try (OutputStream out = Files.newOutputStream(miClass)) {
261            new ClassWriter().write(newClassFile, out);
262        }
263
264        Path test = base.resolve("test");
265        tb.writeJavaFiles(test,
266                          "package impl; public class Impl extends api.Api {}");
267        Path testClasses = base.resolve("test-classes");
268        tb.createDirectories(testClasses);
269
270        List<String> log = new JavacTask(tb)
271                .options("-XDrawDiagnostics",
272                         "--module-path", classes.toString(),
273                         "--add-modules", "m1")
274                .outdir(testClasses)
275                .files(findJavaFiles(test))
276                .run(Expect.FAIL)
277                .writeAll()
278                .getOutputLines(Task.OutputKind.DIRECT);
279
280        List<String> expected = Arrays.asList("- compiler.err.cant.access: m1.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.module.non.zero.opens: m1))",
281                                              "1 error");
282
283        if (!expected.equals(log))
284            throw new Exception("expected output not found: " + log);
285    }
286
287}
288