1/*
2 * Copyright (c) 2016, 2017, 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 8159305 8166127 8175860 8176481
27 * @summary Tests primarily the module graph computations.
28 * @modules
29 *      jdk.javadoc/jdk.javadoc.internal.api
30 *      jdk.javadoc/jdk.javadoc.internal.tool
31 *      jdk.compiler/com.sun.tools.javac.api
32 *      jdk.compiler/com.sun.tools.javac.main
33 * @library /tools/lib
34 * @build toolbox.ToolBox toolbox.TestRunner
35 * @run main Modules
36 */
37
38import java.io.IOException;
39import java.nio.file.Files;
40import java.nio.file.Path;
41import java.nio.file.Paths;
42
43import toolbox.*;
44import toolbox.Task.Expect;
45import toolbox.Task.OutputKind;
46
47public class Modules extends ModuleTestBase {
48
49    public static void main(String... args) throws Exception {
50        new Modules().runTests();
51    }
52
53    @Test
54    public void testBasicMoption(Path base) throws Exception {
55        Files.createDirectory(base);
56        Path src = base.resolve("src");
57        ModuleBuilder mb = new ModuleBuilder(tb, "m1");
58        mb.comment("The first module.")
59                .exports("pub")
60                .classes("package pub; /** Class A */ public class A {}")
61                .classes("package pro; /** Class B */ public class B {}")
62                .write(src);
63        execTask("--module-source-path", src.toString(),
64                 "--module", "m1");
65        checkModulesSpecified("m1");
66        checkPackagesIncluded("pub");
67        checkTypesIncluded("pub.A");
68    }
69
70    @Test
71    public void testMultipleModulesOption1(Path base) throws Exception {
72        Path src = base.resolve("src");
73
74        ModuleBuilder mb1 = new ModuleBuilder(tb, "m1");
75        mb1.comment("The first module.")
76                .exports("m1pub")
77                .requires("m2")
78                .classes("package m1pub; /** Class A */ public class A {}")
79                .classes("package m1pro; /** Class B */ public class B {}")
80                .write(src);
81
82        ModuleBuilder mb2 = new ModuleBuilder(tb, "m2");
83        mb2.comment("The second module.")
84                .exports("m2pub")
85                .classes("package m2pub; /** Class A */ public class A {}")
86                .classes("package m2pro; /** Class B */ public class B {}")
87                .write(src);
88        execTask("--module-source-path", src.toString(),
89            "--module", "m1,m2");
90        checkModulesSpecified("m1", "m2");
91        checkPackagesIncluded("m1pub", "m2pub");
92        checkTypesIncluded("m1pub.A", "m2pub.A");
93
94    }
95
96    @Test
97    public void testMissingModuleWithSourcePath(Path base) throws Exception {
98        Path src = base.resolve("src");
99        Path mod = src.resolve("m1");
100
101        ModuleBuilder mb1 = new ModuleBuilder(tb, "m1");
102        mb1.comment("The first module.")
103                .exports("m1pub")
104                .requires("m2")
105                .classes("package m1pub; /** Class A */ public class A {}")
106                .classes("package m1pro; /** Class B */ public class B {}")
107                .write(src);
108
109        Path javafile = Paths.get(mod.toString(), "m1pub/A.java");
110
111        execNegativeTask("--source-path", mod.toString(),
112                javafile.toString());
113
114        assertMessagePresent("error: cannot access module-info");
115        assertMessageNotPresent("error - fatal error encountered");
116
117    }
118
119    @Test
120    public void testMultipleModulesAggregatedModuleOption(Path base) throws Exception {
121        Path src = base.resolve("src");
122
123        ModuleBuilder mb1 = new ModuleBuilder(tb, "m1");
124        mb1.comment("The first module.")
125                .exports("m1pub")
126                .requires("m2")
127                .classes("package m1pub; /** Class A */ public class A {}")
128                .classes("package m1pro; /** Class B */ public class B {}")
129                .write(src);
130
131        ModuleBuilder mb2 = new ModuleBuilder(tb, "m2");
132        mb2.comment("The second module.")
133                .exports("m2pub")
134                .classes("package m2pub; /** Class A */ public class A {}")
135                .classes("package m2pro; /** Class B */ public class B {}")
136                .write(src);
137        execTask("--module-source-path", src.toString(),
138            "--module", "m1",
139            "--module", "m2");
140        checkModulesSpecified("m1", "m2");
141        checkPackagesIncluded("m1pub", "m2pub");
142        checkTypesIncluded("m1pub.A", "m2pub.A");
143
144    }
145
146    @Test
147    public void testModulePathOption(Path base) throws Exception {
148        Path src = base.resolve("src");
149        Path modulePath = base.resolve("modules");
150
151        ModuleBuilder mb1 = new ModuleBuilder(tb, "m1");
152        mb1.comment("Module on module path.")
153                .exports("pkg1")
154                .classes("package pkg1; /** Class A */ public class A { }")
155                .build(modulePath);
156
157        ModuleBuilder mb2 = new ModuleBuilder(tb, "m2");
158        mb2.comment("The second module.")
159                .exports("pkg2")
160                .requires("m1")
161                .classes("package pkg2; /** Class B */ public class B { /** Field f */ public pkg1.A f; }")
162                .write(src);
163        execTask("--module-source-path", src.toString(),
164                "--module-path", modulePath.toString(),
165                "--module", "m2");
166        checkModulesSpecified("m2");
167        checkPackagesIncluded("pkg2");
168        checkMembersSelected("pkg2.B.f");
169
170        // module path option "-p"
171        execTask("--module-source-path", src.toString(),
172                "-p", modulePath.toString(),
173                "--module", "m2");
174        // no module path
175        execNegativeTask("--module-source-path", src.toString(),
176                "--module", "m2");
177        assertMessagePresent("error: module not found: m1");
178    }
179
180    @Test
181    public void testUpgradeModulePathOption(Path base) throws Exception {
182        Path src = base.resolve("src");
183        Path modulePath = base.resolve("modules");
184        Path upgradePath = base.resolve("upgrades");
185
186        ModuleBuilder mb1 = new ModuleBuilder(tb, "m1");
187        mb1.comment("Module on module path.")
188                .exports("pkg1")
189                .classes("package pkg1; /** Class A */ public class A { }")
190                .build(modulePath);
191
192        ModuleBuilder mbUpgrade = new ModuleBuilder(tb, "m1");
193        mbUpgrade.comment("Module on upgrade module path.")
194                .exports("pkg1")
195                .classes("package pkg1; /** Class C */ public class C { }")
196                .build(upgradePath);
197
198        ModuleBuilder mb2 = new ModuleBuilder(tb, "m2");
199        mb2.comment("The second module.")
200                .exports("pkg2")
201                .requires("m1")
202                .classes("package pkg2; /** Class B */ public class B { /** Field f */ public pkg1.C f; }")
203                .write(src);
204        execTask("--module-source-path", src.toString(),
205                "--module-path", modulePath.toString(),
206                "--upgrade-module-path", upgradePath.toString(),
207                "--module", "m2");
208        checkModulesSpecified("m2");
209        checkPackagesIncluded("pkg2");
210        checkMembersSelected("pkg2.B.f");
211
212        // no upgrade module path
213        execNegativeTask("--module-source-path", src.toString(),
214                "--module-path", modulePath.toString(),
215                "--module", "m2");
216        assertMessagePresent("error: cannot find symbol");
217
218        // dependency from module path
219        ModuleBuilder mb3 = new ModuleBuilder(tb, "m3");
220        mb3.comment("The third module.")
221                .exports("pkg3")
222                .requires("m1")
223                .classes("package pkg3; /** Class Z */ public class Z { /** Field f */ public pkg1.A f; }")
224                .write(src);
225        execNegativeTask("--module-source-path", src.toString(),
226                "--module-path", modulePath.toString(),
227                "--upgrade-module-path", upgradePath.toString(),
228                "--module", "m3");
229        assertMessagePresent("Z.java:1: error: cannot find symbol");
230    }
231
232    @Test
233    public void testAddModulesOption(Path base) throws Exception {
234        Path src = base.resolve("src");
235        Path modulePath = base.resolve("modules");
236
237        ModuleBuilder mb1 = new ModuleBuilder(tb, "m1");
238        mb1.comment("Module on module path.")
239                .exports("pkg1")
240                .classes("package pkg1; /** Class A */ public class A { }")
241                .build(modulePath);
242
243        ModuleBuilder mb2 = new ModuleBuilder(tb, "m2");
244        mb2.comment("The second module.")
245                .exports("pkg2")
246                .classes("package pkg2; /** @see pkg1.A */ public class B { }")
247                .write(src);
248
249        Path out = base.resolve("out-1");
250        Files.createDirectories(out);
251        String log = new JavadocTask(tb)
252                .outdir(out)
253                .options("--module-source-path", src.toString(),
254                        "--module-path", modulePath.toString(),
255                        "--module", "m2")
256                .run(Expect.FAIL)
257                .writeAll()
258                .getOutput(OutputKind.DIRECT);
259        if (!log.contains("B.java:1: error: reference not found")) {
260            throw new Exception("Error not found");
261        }
262
263        out = base.resolve("out-2");
264        Files.createDirectories(out);
265        new JavadocTask(tb)
266                .outdir(out)
267                .options("--module-source-path", src.toString(),
268                        "--module-path", modulePath.toString(),
269                        "--add-modules", "m1",
270                        "--module", "m2")
271                .run()
272                .writeAll();
273    }
274
275    @Test
276    public void testLimitModulesOption(Path base) throws Exception {
277        Path src = base.resolve("src");
278        Path modulePath = base.resolve("modules");
279
280        ModuleBuilder mb1 = new ModuleBuilder(tb, "m1");
281        mb1.comment("Module on module path.")
282                .build(modulePath);
283
284        ModuleBuilder mb2 = new ModuleBuilder(tb, "m2");
285        mb2.comment("The second module.")
286                .exports("pkg2")
287                .requires("m1")
288                .classes("package pkg2; /** Class B */ public class B { }")
289                .write(src);
290
291        execNegativeTask("--module-source-path", src.toString(),
292                "--module-path", modulePath.toString(),
293                "--limit-modules", "java.base",
294                "--module", "m2");
295        assertMessagePresent("error: module not found: m1");
296    }
297
298    @Test
299    public void testAddExportsOption(Path base) throws Exception {
300        Path src = base.resolve("src");
301        Path modulePath = base.resolve("modules");
302
303        ModuleBuilder mb1 = new ModuleBuilder(tb, "m1");
304        mb1.comment("Module on module path.")
305                .classes("package pkg1; /** Class A */ public class A { }")
306                .build(modulePath);
307
308        ModuleBuilder mb2 = new ModuleBuilder(tb, "m2");
309        mb2.comment("The second module.")
310                .exports("pkg2")
311                .requires("m1")
312                .classes("package pkg2; /** Class B */ public class B { /** Field f */ public pkg1.A f; }")
313                .write(src);
314        execTask("--module-source-path", src.toString(),
315                "--module-path", modulePath.toString(),
316                "--add-exports", "m1/pkg1=m2",
317                "--module", "m2");
318        checkModulesSpecified("m2");
319        checkPackagesIncluded("pkg2");
320        checkMembersSelected("pkg2.B.f");
321    }
322
323    @Test
324    public void testAddReadsOption(Path base) throws Exception {
325        Path src = base.resolve("src");
326        Path modulePath = base.resolve("modules");
327
328        ModuleBuilder mb1 = new ModuleBuilder(tb, "m1");
329        mb1.comment("Module on module path.")
330                .exports("pkg1")
331                .classes("package pkg1; /** Class A */ public class A {}")
332                .build(modulePath);
333
334        ModuleBuilder mb2 = new ModuleBuilder(tb, "m2");
335        mb2.comment("The second module.")
336                .exports("pkg2")
337                .classes("package pkg2; /** Class B */ public class B { /** Field f */ public pkg1.A f;}")
338                .write(src);
339        execTask("--module-source-path", src.toString(),
340                "--module-path", modulePath.toString(),
341                "--add-modules", "m1",
342                "--add-reads", "m2=m1",
343                "--module", "m2");
344        checkModulesSpecified("m2");
345        checkPackagesIncluded("pkg2");
346        checkMembersSelected("pkg2.B.f");
347    }
348
349    @Test
350    public void testModuleOptionsWithLegacy(Path base) throws Exception {
351        Files.createDirectory(base);
352        Path src = base.resolve("src");
353        Path classpath = base.resolve("classpath");
354        Path modulePath = base.resolve("modules");
355
356        tb.writeJavaFiles(classpath, "package pkg1; /** Class C */ public class C { }");
357        new JavacTask(tb)
358                .files(classpath.resolve("pkg1/C.java"))
359                .run();
360
361        ModuleBuilder mb = new ModuleBuilder(tb, "m1");
362        mb.comment("The first module.")
363                .exports("pub")
364                .classes("package pub; /** Class M */ public class M { }")
365                .build(modulePath);
366
367        tb.writeJavaFiles(src, "package pkg; /** Class L */ public class L { public pkg1.C f1; public pub.M f2; }");
368
369        execTask("--source-path", src.toString(),
370                "--class-path", classpath.toString(),
371                "--module-path", modulePath.toString(),
372                "--add-modules", "m1",
373                "pkg");
374        checkPackagesIncluded("pkg");
375        checkTypesIncluded("pkg.L");
376        checkMembersSelected("pkg.L.f1");
377        checkMembersSelected("pkg.L.f2");
378        assertAbsent("error", OutputKind.DIRECT);
379    }
380
381    /**
382     * Tests diamond graph, inspired by javac diamond tests.
383     *
384     *
385     * Module M : test module, with variable requires
386     *
387     * Module N :
388     *     requires transitive O  --->   Module O:
389     *                                   requires J   ---->   Module J:
390     *                                   exports openO          exports openJ
391     *
392     *
393     * Module L :
394     *     requires transitive P  --->   Module P:
395     *                                   exports openP
396     *
397     *
398     */
399
400    @Test
401    public void testExpandRequiresNone(Path base) throws Exception {
402        Path src = base.resolve("src");
403
404        createAuxiliaryModules(src);
405
406        new ModuleBuilder(tb, "M")
407                .comment("The M module.")
408                .requires("N", src)
409                .requires("L", src)
410                .requires("O", src)
411                .exports("p")
412                .classes("package p; public class Main { openO.O o; openN.N n; openL.L l; }")
413                .write(src);
414
415        execTask("--module-source-path", src.toString(),
416                "--module", "M");
417
418        checkModulesSpecified("M");
419        checkModulesIncluded("M");
420        checkPackagesIncluded("p");
421        checkTypesIncluded("p.Main");
422        checkPackagesNotIncluded(".*open.*");
423        assertMessageNotPresent("warning");
424    }
425
426    @Test
427    public void testExpandRequiresTransitive(Path base) throws Exception {
428        Path src = base.resolve("src");
429
430        createAuxiliaryModules(src);
431
432        new ModuleBuilder(tb, "M")
433                .comment("The M module.")
434                .requiresTransitive("N", src)
435                .requires("L", src)
436                .exports("p")
437                .classes("package p; public class Main { openO.O o; openN.N n; openL.L l; }")
438                .write(src);
439
440        execTask("--module-source-path", src.toString(),
441                "--module", "M",
442                "--expand-requires", "transitive");
443
444        checkModulesSpecified("M", "N", "O");
445        checkModulesNotSpecified("java.base");
446        checkModulesIncluded("M", "N", "O");
447        checkModulesNotIncluded("java.base");
448        checkPackagesIncluded("p", "openN", "openO");
449        checkTypesIncluded("p.Main", "openN.N", "openO.O");
450        assertMessageNotPresent("warning");
451    }
452
453    @Test
454    public void testExpandRequiresTransitiveWithMandated(Path base) throws Exception {
455        Path src = base.resolve("src");
456
457        createAuxiliaryModules(src);
458
459        Path patchSrc = Paths.get(src.toString(), "patch");
460
461        new ModuleBuilder(tb, "M")
462                .comment("The M module.")
463                .requiresTransitive("N", src)
464                .requires("L", src)
465                .exports("p")
466                .classes("package p; public class Main { openO.O o; openN.N n; openL.L l; }")
467                .write(src);
468
469        // build the patching module
470        tb.writeJavaFiles(patchSrc, "package pkg1;\n" +
471                "/** Class A */ public class A extends java.util.ArrayList { }");
472        tb.writeJavaFiles(patchSrc, "package pkg1;\n"
473                + "/** Class B */ public class B { }");
474
475        execTask("--module-source-path", src.toString(),
476                "--patch-module", "java.base=" + patchSrc.toString(),
477                "--module", "M",
478                "--expand-requires", "transitive");
479
480        checkModulesSpecified("java.base", "M", "N", "O");
481        checkModulesIncluded("java.base", "M", "N", "O");
482        checkPackagesIncluded("p", "openN", "openO");
483        checkTypesIncluded("p.Main", "openN.N", "openO.O");
484        assertMessageNotPresent("warning");
485    }
486
487    @Test
488    public void testExpandRequiresAll(Path base) throws Exception {
489        Path src = base.resolve("src");
490
491        createAuxiliaryModules(src);
492
493        new ModuleBuilder(tb, "M")
494                .comment("The M module.")
495                .requiresTransitive("N", src)
496                .requires("L", src)
497                .requires("O", src)
498                .exports("p")
499                .classes("package p; public class Main { openO.O o; openN.N n; openL.L l; }")
500                .write(src);
501
502        execTask("--module-source-path", src.toString(),
503                "--module", "M",
504                "--expand-requires", "all");
505
506        checkModulesSpecified("M", "N", "L", "O");
507        checkModulesIncluded("M", "N", "L", "O");
508        checkModulesNotIncluded("P", "J", "Q");
509        checkPackagesIncluded("p", "openN", "openL", "openO");
510        checkPackagesNotIncluded(".*openP.*", ".*openJ.*");
511        checkTypesIncluded("p.Main", "openN.N", "openL.L", "openO.O");
512        checkTypesNotIncluded(".*openP.*", ".*openJ.*");
513        assertMessageNotPresent("warning");
514    }
515
516    @Test
517    public void testMissingModule(Path base) throws Exception {
518        Path src = base.resolve("src");
519
520        createAuxiliaryModules(src);
521
522        new ModuleBuilder(tb, "M")
523                .comment("The M module.")
524                .requiresTransitive("N", src)
525                .requires("L", src)
526                .requires("O", src)
527                .exports("p")
528                .classes("package p; public class Main { openO.O o; openN.N n; openL.L l; }")
529                .write(src);
530
531        execNegativeTask("--module-source-path", src.toString(),
532                "--module", "MIA",
533                "--expand-requires", "all");
534
535        assertMessagePresent("javadoc: error - module MIA not found.");
536    }
537
538    @Test
539    public void testMissingModuleMultiModuleCmdline(Path base) throws Exception {
540        Path src = base.resolve("src");
541
542        createAuxiliaryModules(src);
543
544        new ModuleBuilder(tb, "M")
545                .comment("The M module.")
546                .requiresTransitive("N", src)
547                .requires("L", src)
548                .requires("O", src)
549                .exports("p")
550                .classes("package p; public class Main { openO.O o; openN.N n; openL.L l; }")
551                .write(src);
552
553        execNegativeTask("--module-source-path", src.toString(),
554                "--module", "M,N,L,MIA,O,P",
555                "--expand-requires", "all");
556
557        assertMessagePresent("javadoc: error - module MIA not found");
558    }
559
560    @Test
561    public void testSingleModuleOptionWithSourcePath(Path base) throws Exception {
562        Path src = base.resolve("src");
563        Path mod = createSimpleModule(src, "m1");
564        execTask("--source-path", mod.toString(),
565                 "--module", "m1");
566        checkModulesSpecified("m1");
567        checkPackagesIncluded("p");
568        checkTypesIncluded("p.C");
569    }
570
571    @Test
572    public void testSingleModuleOptionWithMissingModuleInSourcePath(Path base) throws Exception {
573        Path src = base.resolve("src");
574        Path mod = createSimpleModule(src, "m1");
575        execNegativeTask("--source-path", mod.toString(),
576                 "--module", "m2");
577        assertMessagePresent("source path does not contain module m2");
578    }
579
580    @Test
581    public void testMultipleModuleOptionWithSourcePath(Path base) throws Exception {
582        Path src = base.resolve("src");
583        Path mod = createSimpleModule(src, "m1");
584        execNegativeTask("--source-path", mod.toString(),
585                 "--module", "m1,m2,m3");
586        assertMessagePresent("cannot use source path for multiple modules m1, m2, m3");
587    }
588
589    @Test
590    public void testSingleModuleOptionWithNoModuleOnSourcePath(Path base) throws Exception {
591        Path src = base.resolve("src");
592        Path mod1 = Paths.get(src.toString(), "m1");
593        execNegativeTask("--source-path", mod1.toString(),
594                 "--module", "m1");
595        assertMessagePresent("module m1 not found on source path");
596    }
597
598    Path createSimpleModule(Path src, String mname) throws IOException {
599        Path mpath = Paths.get(src.toString(), mname);
600        tb.writeJavaFiles(mpath,
601                "module " + mname + " { exports p; }",
602                "package p; public class C { }");
603        return mpath;
604    }
605
606    void createAuxiliaryModules(Path src) throws IOException {
607
608        new ModuleBuilder(tb, "J")
609                .comment("The J module.")
610                .exports("openJ")
611                .classes("package openJ;  /** Class J open. */ public class J { }")
612                .classes("package closedJ; /** Class J closed. */ public class J  { }")
613                .write(src);
614
615        new ModuleBuilder(tb, "L")
616                .comment("The L module.")
617                .exports("openL")
618                .requiresTransitive("P")
619                .classes("package openL; /** Class L open */ public class L { }")
620                .classes("package closedL;  /** Class L closed */ public class L { }")
621                .write(src);
622
623        new ModuleBuilder(tb, "N")
624                .comment("The N module.")
625                .exports("openN")
626                .requiresTransitive("O")
627                .classes("package openN; /** Class N open */ public class N  { }")
628                .classes("package closedN; /** Class N closed */ public class N { }")
629                .write(src);
630
631        new ModuleBuilder(tb, "O")
632                .comment("The O module.")
633                .exports("openO")
634                .requires("J")
635                .classes("package openO; /** Class O open. */ public class O { openJ.J j; }")
636                .classes("package closedO;  /** Class O closed. */ public class O { }")
637                .write(src);
638
639        new ModuleBuilder(tb, "P")
640                .comment("The P module.")
641                .exports("openP")
642                .requires("J")
643                .classes("package openP; /** Class O open. */ public class O { openJ.J j; }")
644                .classes("package closedP;  /** Class O closed. */ public class O { }")
645                .write(src);
646
647        new ModuleBuilder(tb, "Q")
648                .comment("The Q module.")
649                .exports("openQ")
650                .requires("J")
651                .classes("package openQ; /** Class Q open. */ public class Q { openJ.J j; }")
652                .classes("package closedQ;  /** Class Q closed. */ public class Q { }")
653                .write(src);
654
655    }
656}
657