ModuleInfoTest.java revision 3573:c4a18ee691c4
1/*
2 * Copyright (c) 2015, 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 * @bug 8158123
27 * @summary tests for module declarations
28 * @library /tools/lib
29 * @modules
30 *      jdk.compiler/com.sun.tools.javac.api
31 *      jdk.compiler/com.sun.tools.javac.main
32 *      jdk.jdeps/com.sun.tools.javap
33 * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase
34 * @run main ModuleInfoTest
35 */
36
37import java.nio.file.Files;
38import java.nio.file.Path;
39import java.util.Arrays;
40
41import toolbox.JavacTask;
42import toolbox.Task;
43import toolbox.ToolBox;
44
45public class ModuleInfoTest extends ModuleTestBase {
46
47    public static void main(String... args) throws Exception {
48        ModuleInfoTest t = new ModuleInfoTest();
49        t.runTests();
50    }
51
52    /**
53     * Check error message if module declaration not in module-info.java.
54     */
55    @Test
56    public void testModuleDeclNotInModuleJava(Path base) throws Exception {
57        Path src = base.resolve("src");
58        tb.writeFile(src.resolve("M.java"), "module M { }");
59        String log = new JavacTask(tb)
60                .options("-XDrawDiagnostics")
61                .files(findJavaFiles(src))
62                .run(Task.Expect.FAIL)
63                .writeAll()
64                .getOutput(Task.OutputKind.DIRECT);
65
66        if (!log.contains("M.java:1:1: compiler.err.module.decl.sb.in.module-info.java"))
67            throw new Exception("expected output not found");
68    }
69
70    /**
71     * Verify that a package private class can be put in module-info.java.
72     */
73    @Test
74    public void testNotModuleDeclInModuleJava_1(Path base) throws Exception {
75        Path src = base.resolve("src");
76        tb.writeFile(src.resolve("module-info.java"), "class C { }");
77        new JavacTask(tb)
78                .options("-XDrawDiagnostics")
79                .files(findJavaFiles(src))
80                .run()
81                .writeAll();
82    }
83
84    /**
85     * Verify that a public class cannot be put in module-info.java.
86     */
87    @Test
88    public void testNotModuleDeclInModuleJava_2(Path base) throws Exception {
89        Path src = base.resolve("src");
90        tb.writeFile(src.resolve("module-info.java"), "public class C { }");
91        String log = new JavacTask(tb)
92                .options("-XDrawDiagnostics")
93                .files(findJavaFiles(src))
94                .run(Task.Expect.FAIL)
95                .writeAll()
96                .getOutput(Task.OutputKind.DIRECT);
97
98        if (!log.contains("module-info.java:1:8: compiler.err.class.public.should.be.in.file: C"))
99            throw new Exception("expected output not found");
100    }
101
102    /**
103     * Verify that only one module decl can be put in module-info.java.
104     */
105    @Test
106    public void testSingleModuleDecl(Path base) throws Exception {
107        Path src = base.resolve("src");
108        tb.writeJavaFiles(src, "module M1 { } /*...*/ module M2 { }");
109        String log = new JavacTask(tb)
110                .options("-XDrawDiagnostics")
111                .files(findJavaFiles(src))
112                .run(Task.Expect.FAIL)
113                .writeAll()
114                .getOutput(Task.OutputKind.DIRECT);
115
116        if (!log.contains("module-info.java:1:14: compiler.err.expected: token.end-of-input"))
117            throw new Exception("expected output not found");
118    }
119
120    /**
121     * Verify that missing requires are reported.
122     */
123    @Test
124    public void testRequiresNotFound(Path base) throws Exception {
125        Path src = base.resolve("src");
126        tb.writeJavaFiles(src, "module M1 { requires M2; }");
127        String log = new JavacTask(tb)
128                .options("-XDrawDiagnostics")
129                .files(findJavaFiles(src))
130                .run(Task.Expect.FAIL)
131                .writeAll()
132                .getOutput(Task.OutputKind.DIRECT);
133
134        if (!log.contains("module-info.java:1:22: compiler.err.module.not.found: M2"))
135            throw new Exception("expected output not found");
136    }
137
138    /**
139     * Verify that missing exports are reported.
140     */
141    @Test
142    public void testExportsNotFound(Path base) throws Exception {
143        Path src = base.resolve("src");
144        tb.writeJavaFiles(src, "module M1 { exports p to M2; }");
145        String log = new JavacTask(tb)
146                .options("-XDrawDiagnostics")
147                .files(findJavaFiles(src))
148                .run(Task.Expect.FAIL)
149                .writeAll()
150                .getOutput(Task.OutputKind.DIRECT);
151
152        if (!log.contains("module-info.java:1:26: compiler.err.module.not.found: M2"))
153            throw new Exception("expected output not found");
154    }
155
156    /**
157     * Verify that a simple loop is detected.
158     */
159    @Test
160    public void testRequiresSelf(Path base) throws Exception {
161        Path src = base.resolve("src");
162        tb.writeJavaFiles(src, "module M { requires M; }");
163        String log = new JavacTask(tb)
164                .options("-XDrawDiagnostics")
165                .files(findJavaFiles(src))
166                .run(Task.Expect.FAIL)
167                .writeAll()
168                .getOutput(Task.OutputKind.DIRECT);
169
170        if (!log.contains("module-info.java:1:21: compiler.err.cyclic.requires: M"))
171            throw new Exception("expected output not found");
172    }
173
174    /**
175     * Verify that a multi-module loop is detected.
176     */
177    @Test
178    public void testRequiresLoop(Path base) throws Exception {
179        Path src = base.resolve("src");
180        Path src_m1 = src.resolve("m1");
181        tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { requires m2; }");
182        Path src_m2 = src.resolve("m2");
183        tb.writeFile(src_m2.resolve("module-info.java"), "module m2 { requires m3; }");
184        Path src_m3 = src.resolve("m3");
185        tb.writeFile(src_m3.resolve("module-info.java"), "module m3 { requires m1; }");
186
187        Path classes = base.resolve("classes");
188        Files.createDirectories(classes);
189
190        String log = new JavacTask(tb)
191                .options("-XDrawDiagnostics", "--module-source-path", src.toString())
192                .outdir(classes)
193                .files(findJavaFiles(src))
194                .run(Task.Expect.FAIL)
195                .writeAll()
196                .getOutput(Task.OutputKind.DIRECT);
197
198        if (!log.contains("module-info.java:1:22: compiler.err.cyclic.requires: m3"))
199            throw new Exception("expected output not found");
200    }
201
202    /**
203     * Verify that a multi-module loop is detected.
204     */
205    @Test
206    public void testRequiresPublicLoop(Path base) throws Exception {
207        Path src = base.resolve("src");
208        Path src_m1 = src.resolve("m1");
209        tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { requires m2; }");
210        Path src_m2 = src.resolve("m2");
211        tb.writeFile(src_m2.resolve("module-info.java"), "module m2 { requires public m3; }");
212        Path src_m3 = src.resolve("m3");
213        tb.writeFile(src_m3.resolve("module-info.java"), "module m3 { requires m1; }");
214
215        Path classes = base.resolve("classes");
216        Files.createDirectories(classes);
217
218        String log = new JavacTask(tb)
219                .options("-XDrawDiagnostics", "--module-source-path", src.toString())
220                .outdir(classes)
221                .files(findJavaFiles(src))
222                .run(Task.Expect.FAIL)
223                .writeAll()
224                .getOutput(Task.OutputKind.DIRECT);
225
226        if (!log.contains("module-info.java:1:29: compiler.err.cyclic.requires: m3"))
227            throw new Exception("expected output not found");
228    }
229
230    /**
231     * Verify that duplicate requires are detected.
232     */
233    @Test
234    public void testDuplicateRequires(Path base) throws Exception {
235        Path src = base.resolve("src");
236        Path src_m1 = src.resolve("m1");
237        tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { }");
238        Path src_m2 = src.resolve("m2");
239        tb.writeFile(src_m2.resolve("module-info.java"), "module m2 { requires m1; requires m1; }");
240
241        Path classes = base.resolve("classes");
242        Files.createDirectories(classes);
243
244        String log = new JavacTask(tb)
245                .options("-XDrawDiagnostics", "--module-source-path", src.toString())
246                .outdir(classes)
247                .files(findJavaFiles(src))
248                .run(Task.Expect.FAIL)
249                .writeAll()
250                .getOutput(Task.OutputKind.DIRECT);
251
252        if (!log.contains("module-info.java:1:35: compiler.err.duplicate.requires: m1"))
253            throw new Exception("expected output not found");
254    }
255
256    /**
257     * Verify that duplicate exported packages are detected.
258     */
259    @Test
260    public void testDuplicateExports_packages(Path base) throws Exception {
261        Path src = base.resolve("src");
262        tb.writeJavaFiles(src, "module m1 { exports p; exports p; }");
263
264        Path classes = base.resolve("classes");
265        Files.createDirectories(classes);
266
267        String log = new JavacTask(tb)
268                .options("-XDrawDiagnostics")
269                .outdir(classes)
270                .files(findJavaFiles(src))
271                .run(Task.Expect.FAIL)
272                .writeAll()
273                .getOutput(Task.OutputKind.DIRECT);
274
275        if (!log.contains("module-info.java:1:32: compiler.err.duplicate.exports: p"))
276            throw new Exception("expected output not found");
277    }
278
279    /**
280     * Verify that duplicate exported packages are detected.
281     */
282    @Test
283    public void testDuplicateExports_packages2(Path base) throws Exception {
284        Path src = base.resolve("src");
285        tb.writeJavaFiles(src.resolve("m1"), "module m1 { exports p; exports p to m2; }");
286        tb.writeJavaFiles(src.resolve("m2"), "module m2 { }");
287
288        Path classes = base.resolve("classes");
289        Files.createDirectories(classes);
290
291        String log = new JavacTask(tb)
292                .options("-XDrawDiagnostics", "--module-source-path", src.toString())
293                .outdir(classes)
294                .files(findJavaFiles(src))
295                .run(Task.Expect.FAIL)
296                .writeAll()
297                .getOutput(Task.OutputKind.DIRECT);
298
299        if (!log.contains("module-info.java:1:32: compiler.err.duplicate.exports: p"))
300            throw new Exception("expected output not found");
301    }
302
303    /**
304     * Verify that duplicate exported packages are detected.
305     */
306    @Test
307    public void testDuplicateExports_modules(Path base) throws Exception {
308        Path src = base.resolve("src");
309        Path src_m1 = src.resolve("m1");
310        tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { }");
311        Path src_m2 = src.resolve("m2");
312        tb.writeFile(src_m2.resolve("module-info.java"), "module m2 { exports p to m1, m1; }");
313
314        Path classes = base.resolve("classes");
315        Files.createDirectories(classes);
316
317        String log = new JavacTask(tb)
318                .options("-XDrawDiagnostics", "--module-source-path", src.toString())
319                .outdir(classes)
320                .files(findJavaFiles(src))
321                .run(Task.Expect.FAIL)
322                .writeAll()
323                .getOutput(Task.OutputKind.DIRECT);
324
325        if (!log.contains("module-info.java:1:30: compiler.err.duplicate.exports: m1"))
326            throw new Exception("expected output not found");
327    }
328
329    /**
330     * Verify that annotations are not permitted at
331     * any of the module names or the package names.
332     */
333    @Test
334    public void testAnnotations(Path base) throws Exception {
335        Path src = base.resolve("src");
336        Path src_m1 = src.resolve("m1.sub");
337        Path classes = base.resolve("classes");
338        Files.createDirectories(classes);
339
340        String code = "module @m1.@sub { " +
341                "requires @p1.@p2; " +
342                "exports @p1.@p2; " +
343                "exports @p1.@p2 to @m2.@sub; " +
344                "exports @p1.@p2 to @m2.@sub, @m3.@sub; " +
345                "uses @p1.@Interface; " +
346                "provides @p1.@Interface with @p2.@Concrete; " +
347                "}";
348        String[] splittedCode = code.split("@");
349        int length = splittedCode.length;
350        String anno = "@Anno ";
351
352        for (int i = 1; i < length; i++) {
353            String preAnno = String.join("", Arrays.copyOfRange(splittedCode, 0, i));
354            String postAnno = String.join("", Arrays.copyOfRange(splittedCode, i, length));
355            String moduleInfo = preAnno + anno + postAnno;
356            tb.writeFile(src_m1.resolve("module-info.java"), moduleInfo);
357
358            String log = new JavacTask(tb)
359                    .options("-XDrawDiagnostics", "--module-source-path", src.toString())
360                    .outdir(classes)
361                    .files(findJavaFiles(src))
362                    .run(Task.Expect.FAIL)
363                    .writeAll()
364                    .getOutput(Task.OutputKind.DIRECT);
365
366            if (!log.matches("(?s)^module\\-info\\.java:\\d+:\\d+: compiler\\.err\\.expected: token\\.identifier.*"))
367                throw new Exception("expected output not found");
368        }
369    }
370}
371