1 /*
2  * Copyright (c) 2015, 2018, 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 8207032
27  * @summary Test the --add-exports option
28  * @library /tools/lib
29  * @modules jdk.compiler/com.sun.tools.javac.api
30  *          jdk.compiler/com.sun.tools.javac.main
31  * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase
32  * @run main AddExportsTest
33  */
34 
35 import java.nio.file.Path;
36 
37 import toolbox.JavacTask;
38 import toolbox.Task;
39 import toolbox.Task.Expect;
40 import toolbox.Task.OutputKind;
41 
42 public class AddExportsTest extends ModuleTestBase {
43 
main(String... args)44     public static void main(String... args) throws Exception {
45         new AddExportsTest().runTests();
46     }
47 
48     @Test
testEmpty(Path base)49     public void testEmpty(Path base) throws Exception {
50         Path src = base.resolve("src");
51         tb.writeJavaFiles(src, "class Dummy { }");
52         Path classes = base.resolve("classes");
53         tb.createDirectories(classes);
54         testEmpty(src, classes, "--add-exports", "");
55         testEmpty(src, classes, "--add-exports=");
56     }
57 
testEmpty(Path src, Path classes, String... options)58     private void testEmpty(Path src, Path classes, String... options) throws Exception {
59         String log = new JavacTask(tb, Task.Mode.CMDLINE)
60                 .options(options)
61                 .outdir(classes)
62                 .files(findJavaFiles(src))
63                 .run(Task.Expect.FAIL)
64                 .writeAll()
65                 .getOutput(Task.OutputKind.DIRECT);
66 
67         checkOutputContains(log,
68             "error: no value for --add-exports option");
69     }
70 
71     @Test
testEmptyItem(Path base)72     public void testEmptyItem(Path base) throws Exception {
73         Path src = base.resolve("src");
74         Path src_m1 = src.resolve("m1x");
75         tb.writeJavaFiles(src_m1,
76                           "module m1x { }",
77                           "package p1; public class C1 { }");
78         Path src_m2 = src.resolve("m2x");
79         tb.writeJavaFiles(src_m2,
80                           "module m2x { requires m1x; }",
81                           "package p2; class C2 { p1.C1 c1; }");
82         Path src_m3 = src.resolve("m3x");
83         tb.writeJavaFiles(src_m3,
84                           "module m3x { requires m1x; }",
85                           "package p3; class C3 { p1.C1 c1; }");
86         Path classes = base.resolve("classes");
87         tb.createDirectories(classes);
88 
89         testEmptyItem(src, classes, "m1x/p1=,m2x,m3x");
90         testEmptyItem(src, classes, "m1x/p1=m2x,,m3x");
91         testEmptyItem(src, classes, "m1x/p1=m2x,m3x,");
92     }
93 
testEmptyItem(Path src, Path classes, String option)94     void testEmptyItem(Path src, Path classes, String option) throws Exception {
95         new JavacTask(tb)
96                 .options("--module-source-path", src.toString(),
97                          "--add-exports", option)
98                 .outdir(classes)
99                 .files(findJavaFiles(src))
100                 .run()
101                 .writeAll();
102     }
103 
104     @Test
testEmptyList(Path base)105     public void testEmptyList(Path base) throws Exception {
106         Path src = base.resolve("src");
107         Path src_m1 = src.resolve("m1x");
108         tb.writeJavaFiles(src_m1,
109                           "module m1x { exports p1; }",
110                           "package p1; public class C1 { }");
111         Path classes = base.resolve("classes");
112         tb.createDirectories(classes);
113 
114         testEmptyList(src, classes, "m1x/p1=");
115         testEmptyList(src, classes, "m1x/p1=,");
116     }
117 
testEmptyList(Path src, Path classes, String option)118     void testEmptyList(Path src, Path classes, String option) throws Exception {
119         String log = new JavacTask(tb, Task.Mode.CMDLINE)
120                 .options("--module-source-path", src.toString(),
121                          "--add-exports", option)
122                 .outdir(classes)
123                 .files(findJavaFiles(src))
124                 .run(Task.Expect.FAIL)
125                 .writeAll()
126                 .getOutput(Task.OutputKind.DIRECT);
127 
128         checkOutputContains(log,
129             "error: bad value for --add-exports option: '" + option + "'");
130     }
131 
132     @Test
testMissingSourceParts(Path base)133     public void testMissingSourceParts(Path base) throws Exception {
134         Path src = base.resolve("src");
135         Path src_m1 = src.resolve("m1x");
136         tb.writeJavaFiles(src_m1,
137                           "module m1x { exports p1; }",
138                           "package p1; public class C1 { }");
139         Path src_m2 = src.resolve("m2x");
140         tb.writeJavaFiles(src_m2,
141                           "module m2x { }",
142                           "package p2; class C2 { p1.C1 c1; }");
143         Path classes = base.resolve("classes");
144         tb.createDirectories(classes);
145 
146         testMissingSourcePart(src, classes, "=m2x");
147         testMissingSourcePart(src, classes, "/=m2x");
148         testMissingSourcePart(src, classes, "m1x/=m2x");
149         testMissingSourcePart(src, classes, "/p1=m2x");
150         testMissingSourcePart(src, classes, "m1xp1=m2x");
151     }
152 
testMissingSourcePart(Path src, Path classes, String option)153     private void testMissingSourcePart(Path src, Path classes, String option) throws Exception {
154         String log = new JavacTask(tb, Task.Mode.CMDLINE)
155                 .options("--module-source-path", src.toString(),
156                          "--add-exports", option)
157                 .outdir(classes)
158                 .files(findJavaFiles(src))
159                 .run(Task.Expect.FAIL)
160                 .writeAll()
161                 .getOutput(Task.OutputKind.DIRECT);
162 
163         checkOutputContains(log,
164             "error: bad value for --add-exports option: '" + option + "'");
165     }
166 
167     @Test
testBadSourceParts(Path base)168     public void testBadSourceParts(Path base) throws Exception {
169         Path src = base.resolve("src");
170         Path src_m1 = src.resolve("m1x");
171         tb.writeJavaFiles(src_m1,
172                           "module m1x { exports p1; }",
173                           "package p1; public class C1 { }");
174         Path src_m2 = src.resolve("m2x");
175         tb.writeJavaFiles(src_m2,
176                           "module m2x { }",
177                           "package p2; class C2 { p1.C1 c1; }");
178         Path classes = base.resolve("classes");
179         tb.createDirectories(classes);
180 
181         testBadSourcePart(src, classes, "m!/p1=m2x", "m!");
182         testBadSourcePart(src, classes, "m1x/p!=m2x", "p!");
183     }
184 
testBadSourcePart(Path src, Path classes, String option, String badName)185     private void testBadSourcePart(Path src, Path classes, String option, String badName)
186                 throws Exception {
187         String log = new JavacTask(tb, Task.Mode.CMDLINE)
188                 .options("-XDrawDiagnostics",
189                          "--module-source-path", src.toString(),
190                          "--add-exports", option)
191                 .outdir(classes)
192                 .files(findJavaFiles(src))
193                 .run(Task.Expect.FAIL)
194                 .writeAll()
195                 .getOutput(Task.OutputKind.DIRECT);
196 
197         checkOutputContains(log,
198             "- compiler.warn.bad.name.for.option: --add-exports, " + badName);
199     }
200 
201     @Test
testBadTarget(Path base)202     public void testBadTarget(Path base) throws Exception {
203         Path src = base.resolve("src");
204         Path src_m1 = src.resolve("m1x");
205         tb.writeJavaFiles(src_m1,
206                           "module m1x { exports p1; }",
207                           "package p1; public class C1 { }");
208         Path classes = base.resolve("classes");
209         tb.createDirectories(classes);
210 
211         String log = new JavacTask(tb, Task.Mode.CMDLINE)
212                 .options("-XDrawDiagnostics",
213                          "--module-source-path", src.toString(),
214                          "--add-exports", "m1x/p1=m!")
215                 .outdir(classes)
216                 .files(findJavaFiles(src))
217                 .run()
218                 .writeAll()
219                 .getOutput(Task.OutputKind.DIRECT);
220 
221         checkOutputContains(log,
222             "- compiler.warn.bad.name.for.option: --add-exports, m!");
223     }
224 
225     @Test
testSourceNotFound(Path base)226     public void testSourceNotFound(Path base) throws Exception {
227         Path src = base.resolve("src");
228         Path src_m1 = src.resolve("m1x");
229         tb.writeJavaFiles(src_m1,
230                           "module m1x { }");
231         Path classes = base.resolve("classes");
232         tb.createDirectories(classes);
233 
234         String log = new JavacTask(tb, Task.Mode.CMDLINE)
235                 .options("-XDrawDiagnostics",
236                          "--module-source-path", src.toString(),
237                          "--add-exports", "DoesNotExist/p=m1x")
238                 .outdir(classes)
239                 .files(findJavaFiles(src))
240                 .run()
241                 .writeAll()
242                 .getOutput(Task.OutputKind.DIRECT);
243 
244         checkOutputContains(log,
245             "- compiler.warn.module.for.option.not.found: --add-exports, DoesNotExist");
246     }
247 
248     @Test
testTargetNotFound(Path base)249     public void testTargetNotFound(Path base) throws Exception {
250         Path src = base.resolve("src");
251         Path src_m1 = src.resolve("m1x");
252         tb.writeJavaFiles(src_m1,
253                           "module m1x { }",
254                           "package p1; class C1 { }");
255         Path classes = base.resolve("classes");
256         tb.createDirectories(classes);
257 
258         String log = new JavacTask(tb, Task.Mode.CMDLINE)
259                 .options("-XDrawDiagnostics",
260                          "--module-source-path", src.toString(),
261                          "--add-exports", "m1x/p1=DoesNotExist")
262                 .outdir(classes)
263                 .files(findJavaFiles(src))
264                 .run()
265                 .writeAll()
266                 .getOutput(Task.OutputKind.DIRECT);
267 
268         checkOutputContains(log,
269             "- compiler.warn.module.for.option.not.found: --add-exports, DoesNotExist");
270     }
271 
272     @Test
testDuplicate(Path base)273     public void testDuplicate(Path base) throws Exception {
274         Path src = base.resolve("src");
275         Path src_m1 = src.resolve("m1x");
276         tb.writeJavaFiles(src_m1,
277                           "module m1x { }",
278                           "package p1; public class C1 { }");
279         Path src_m2 = src.resolve("m2x");
280         tb.writeJavaFiles(src_m2,
281                           "module m2x { requires m1x; }",
282                           "package p2; class C2 { p1.C1 c1; }");
283         Path classes = base.resolve("classes");
284         tb.createDirectories(classes);
285 
286         new JavacTask(tb)
287                 .options("--module-source-path", src.toString(),
288                          "--add-exports", "m1x/p1=m2x,m2x")
289                 .outdir(classes)
290                 .files(findJavaFiles(src))
291                 .run()
292                 .writeAll();
293     }
294 
295     @Test
testRepeated_SameTarget(Path base)296     public void testRepeated_SameTarget(Path base) throws Exception {
297         Path src = base.resolve("src");
298         Path src_m1 = src.resolve("m1x");
299         tb.writeJavaFiles(src_m1,
300                           "module m1x { }",
301                           "package p1; public class C1 { }");
302         Path src_m2 = src.resolve("m2x");
303         tb.writeJavaFiles(src_m2,
304                           "module m2x { requires m1x; }",
305                           "package p2; class C2 { p1.C1 c1; }");
306         Path classes = base.resolve("classes");
307         tb.createDirectories(classes);
308 
309         new JavacTask(tb)
310                 .options("--module-source-path", src.toString(),
311                          "--add-exports", "m1x/p1=m2x",
312                          "--add-exports", "m1x/p1=m2x")
313                 .outdir(classes)
314                 .files(findJavaFiles(src))
315                 .run()
316                 .writeAll();
317     }
318 
319     @Test
testRepeated_DifferentTarget(Path base)320     public void testRepeated_DifferentTarget(Path base) throws Exception {
321         Path src = base.resolve("src");
322         Path src_m1 = src.resolve("m1x");
323         tb.writeJavaFiles(src_m1,
324                           "module m1x { }",
325                           "package p1; public class C1 { }");
326         Path src_m2 = src.resolve("m2x");
327         tb.writeJavaFiles(src_m2,
328                           "module m2x { requires m1x; }",
329                           "package p2; class C2 { p1.C1 c1; }");
330         Path src_m3 = src.resolve("m3x");
331         tb.writeJavaFiles(src_m3,
332                           "module m3x { requires m1x; }",
333                           "package p3; class C3 { p1.C1 c1; }");
334         Path classes = base.resolve("classes");
335         tb.createDirectories(classes);
336 
337         new JavacTask(tb)
338                 .options("--module-source-path", src.toString(),
339                          "--add-exports", "m1x/p1=m2x",
340                          "--add-exports", "m1x/p1=m3x")
341                 .outdir(classes)
342                 .files(findJavaFiles(src))
343                 .run()
344                 .writeAll();
345     }
346 
347     @Test
testNoReads(Path base)348     public void testNoReads(Path base) throws Exception {
349         Path src = base.resolve("src");
350         Path src_m1 = src.resolve("m1x");
351         tb.writeJavaFiles(src_m1,
352                           "module m1x { }",
353                           "package p1; public class C1 { }");
354         Path src_m2 = src.resolve("m2x");
355         tb.writeJavaFiles(src_m2,
356                           "module m2x { }",
357                           "package p2; class C2 { p1.C1 c1; }");
358         Path classes = base.resolve("classes");
359         tb.createDirectories(classes);
360 
361         String log;
362 
363         log = new JavacTask(tb)
364                 .options("--module-source-path", src.toString(),
365                          "-XDrawDiagnostics")
366                 .outdir(classes)
367                 .files(findJavaFiles(src))
368                 .run(Expect.FAIL)
369                 .writeAll()
370                 .getOutput(OutputKind.DIRECT);
371 
372         checkOutputContains(log,
373             "C2.java:1:24: compiler.err.package.not.visible: p1, (compiler.misc.not.def.access.does.not.read: m2x, p1, m1x)");
374 
375         log = new JavacTask(tb)
376                 .options("--module-source-path", src.toString(),
377                          "-XDrawDiagnostics",
378                          "--add-exports", "m1x/p1=m2x")
379                 .outdir(classes)
380                 .files(findJavaFiles(src))
381                 .run(Expect.FAIL)
382                 .writeAll()
383                 .getOutput(OutputKind.DIRECT);
384 
385         checkOutputContains(log,
386             "C2.java:1:24: compiler.err.package.not.visible: p1, (compiler.misc.not.def.access.does.not.read: m2x, p1, m1x)");
387 
388         Path mp = base.resolve("mp");
389         tb.createDirectories(mp);
390 
391         new JavacTask(tb)
392                 .options("--module-source-path", src.toString(),
393                          "-XDrawDiagnostics",
394                          "--add-exports", "m1x/p1=m2x",
395                          "--add-reads", "m2x=m1x")
396                 .outdir(mp)
397                 .files(findJavaFiles(src))
398                 .run(Expect.SUCCESS)
399                 .writeAll();
400 
401         log = new JavacTask(tb)
402                 .options("-XDrawDiagnostics",
403                          "--add-exports", "m1x/p1=m2x",
404                          "--add-reads", "m2x=m1x",
405                          "--module-path", mp.toString())
406                 .outdir(classes)
407                 .files(findJavaFiles(src_m2))
408                 .run(Expect.FAIL)
409                 .writeAll()
410                 .getOutput(OutputKind.DIRECT);
411 
412         checkOutputContains(log,
413             "C2.java:1:24: compiler.err.package.not.visible: p1, (compiler.misc.not.def.access.does.not.read: m2x, p1, m1x)");
414         checkOutputContains(log,
415             "- compiler.warn.module.for.option.not.found: --add-reads, m1x");
416         checkOutputContains(log,
417             "- compiler.warn.module.for.option.not.found: --add-exports, m1x");
418 
419         new JavacTask(tb)
420                 .options("-XDrawDiagnostics",
421                          "--add-exports", "m1x/p1=m2x",
422                          "--add-reads", "m2x=m1x",
423                          "--module-path", mp.toString(),
424                          "--add-modules", "m1x")
425                 .outdir(classes)
426                 .files(findJavaFiles(src_m2))
427                 .run(Expect.SUCCESS)
428                 .writeAll()
429                 .getOutput(OutputKind.DIRECT);
430     }
431 }
432