AddReadsTest.java revision 3822:d8766c39123a
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 * @summary Test the --add-reads option
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.javap
31 *          java.desktop
32 * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask toolbox.JavapTask ModuleTestBase
33 * @run main AddReadsTest
34 */
35
36import java.nio.file.Files;
37import java.nio.file.Path;
38import java.util.Set;
39
40import javax.annotation.processing.AbstractProcessor;
41import javax.annotation.processing.RoundEnvironment;
42import javax.annotation.processing.SupportedAnnotationTypes;
43import javax.lang.model.SourceVersion;
44import javax.lang.model.element.ModuleElement;
45import javax.lang.model.element.ModuleElement.RequiresDirective;
46import javax.lang.model.element.TypeElement;
47import javax.lang.model.util.ElementFilter;
48
49import toolbox.JarTask;
50import toolbox.JavacTask;
51import toolbox.JavapTask;
52import toolbox.Task;
53
54public class AddReadsTest extends ModuleTestBase {
55
56    public static void main(String... args) throws Exception {
57        new AddReadsTest().runTests();
58    }
59
60    @Test
61    public void testAddReads(Path base) throws Exception {
62        Path src = base.resolve("src");
63        Path src_m1 = src.resolve("m1x");
64        tb.writeJavaFiles(src_m1,
65                          "module m1x { exports api; }",
66                          "package api; public class Api { }");
67        Path src_m2 = src.resolve("m2x");
68        tb.writeJavaFiles(src_m2,
69                          "module m2x { }",
70                          "package test; public class Test extends api.Api { }");
71        Path classes = base.resolve("classes");
72        tb.createDirectories(classes);
73
74        String log = new JavacTask(tb)
75                .options("-XDrawDiagnostics",
76                         "--module-source-path", src.toString())
77                .outdir(classes)
78                .files(findJavaFiles(src))
79                .run(Task.Expect.FAIL)
80                .writeAll()
81                .getOutput(Task.OutputKind.DIRECT);
82
83        checkOutputContains(log,
84            "Test.java:1:44: compiler.err.not.def.access.package.cant.access: api.Api, api");
85
86        //test add dependencies:
87        new JavacTask(tb)
88                .options("--add-reads", "m2x=m1x",
89                         "--module-source-path", src.toString(),
90                         "-processor", VerifyRequires.class.getName())
91                .outdir(classes)
92                .files(findJavaFiles(src))
93                .run()
94                .writeAll();
95
96        String decompiled = new JavapTask(tb)
97                .options("-verbose",
98                        classes.resolve("m2x").resolve("module-info.class").toString())
99                .run()
100                .getOutput(Task.OutputKind.DIRECT);
101
102        if (decompiled.contains("m1x")) {
103            throw new Exception("Incorrectly refers to m1x module.");
104        }
105
106        //cyclic dependencies OK when created through addReads:
107        new JavacTask(tb)
108                .options("--add-reads", "m2x=m1x",
109                         "--add-reads", "m1x=m2x",
110                         "--module-source-path", src.toString())
111                .outdir(classes)
112                .files(findJavaFiles(src))
113                .run()
114                .writeAll();
115
116        tb.writeJavaFiles(src_m2,
117                          "module m2x { requires m1x; }");
118
119        new JavacTask(tb)
120                .options("--add-reads", "m1x=m2x",
121                         "--module-source-path", src.toString())
122                .outdir(classes)
123                .files(findJavaFiles(src))
124                .run()
125                .writeAll();
126    }
127
128    @SupportedAnnotationTypes("*")
129    public static final class VerifyRequires extends AbstractProcessor {
130
131        @Override
132        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
133            ModuleElement m2Module = processingEnv.getElementUtils().getModuleElement("m2x");
134            if (m2Module == null) {
135                throw new AssertionError("Cannot find the m2x module!");
136            }
137            boolean foundM1 = false;
138            for (RequiresDirective rd : ElementFilter.requiresIn(m2Module.getDirectives())) {
139                foundM1 |= rd.getDependency().getSimpleName().contentEquals("m1x");
140            }
141            if (!foundM1) {
142                throw new AssertionError("Cannot find the dependency on m1x module!");
143            }
144            return false;
145        }
146
147        @Override
148        public SourceVersion getSupportedSourceVersion() {
149            return SourceVersion.latest();
150        }
151
152    }
153
154    @Test
155    public void testAddReadsUnnamedModule(Path base) throws Exception {
156        Path jar = prepareTestJar(base);
157
158        Path moduleSrc = base.resolve("module-src");
159        Path m1 = moduleSrc.resolve("m1x");
160
161        Path classes = base.resolve("classes");
162
163        Files.createDirectories(classes);
164
165        tb.writeJavaFiles(m1,
166                          "module m1x { }",
167                          "package impl; public class Impl { api.Api api; }");
168
169        new JavacTask(tb)
170          .options("--class-path", jar.toString(),
171                   "--add-reads", "m1x=ALL-UNNAMED",
172                   "-XDrawDiagnostics")
173          .outdir(classes)
174          .files(findJavaFiles(moduleSrc))
175          .run()
176          .writeAll();
177    }
178
179    @Test
180    public void testAddReadsUnnamedModulePackageConflict(Path base) throws Exception {
181        Path jar = prepareTestJar(base);
182
183        Path moduleSrc = base.resolve("module-src");
184        Path m1 = moduleSrc.resolve("m1x");
185
186        Path classes = base.resolve("classes");
187
188        Files.createDirectories(classes);
189
190        tb.writeJavaFiles(m1,
191                          "module m1x { }",
192                          "package api; public class Api { public static void test() { } }",
193                          "package impl; public class Impl { { api.Api.test(); } }");
194
195        new JavacTask(tb)
196          .options("--class-path", jar.toString(),
197                   "--module-source-path", moduleSrc.toString(),
198                   "--add-reads", "m1x=ALL-UNNAMED",
199                   "-XDrawDiagnostics")
200          .outdir(classes)
201          .files(m1.resolve("impl").resolve("Impl.java"))
202          .run()
203          .writeAll();
204    }
205
206    @Test
207    public void testAddReadsUnnamedToJavaBase(Path base) throws Exception {
208        Path jar = prepareTestJar(base);
209        Path src = base.resolve("src");
210        Path classes = base.resolve("classes");
211
212        Files.createDirectories(classes);
213
214        tb.writeJavaFiles(src,
215                          "package impl; public class Impl { api.Api a; }");
216
217        new JavacTask(tb)
218          .options("--class-path", jar.toString(),
219                   "--add-reads", "java.base=ALL-UNNAMED",
220                   "-Xmodule:java.base")
221          .outdir(classes)
222          .files(src.resolve("impl").resolve("Impl.java"))
223          .run()
224          .writeAll();
225    }
226
227    @Test
228    public void testAddReadsToJavaBase(Path base) throws Exception {
229        Path src = base.resolve("src");
230        Path classes = base.resolve("classes");
231
232        Files.createDirectories(classes);
233
234        tb.writeJavaFiles(src,
235                          "package impl; public class Impl { javax.swing.JButton b; }");
236
237        new JavacTask(tb)
238          .options("--add-modules", "java.desktop",
239                   "--add-reads", "java.base=java.desktop",
240                   "-Xmodule:java.base")
241          .outdir(classes)
242          .files(findJavaFiles(src))
243          .run()
244          .writeAll();
245    }
246
247    private Path prepareTestJar(Path base) throws Exception {
248        Path legacySrc = base.resolve("legacy-src");
249        tb.writeJavaFiles(legacySrc,
250                          "package api; public abstract class Api {}");
251        Path legacyClasses = base.resolve("legacy-classes");
252        Files.createDirectories(legacyClasses);
253
254        String log = new JavacTask(tb)
255                .options()
256                .outdir(legacyClasses)
257                .files(findJavaFiles(legacySrc))
258                .run()
259                .writeAll()
260                .getOutput(Task.OutputKind.DIRECT);
261
262        if (!log.isEmpty()) {
263            throw new Exception("unexpected output: " + log);
264        }
265
266        Path lib = base.resolve("lib");
267
268        Files.createDirectories(lib);
269
270        Path jar = lib.resolve("test-api-1.0.jar");
271
272        new JarTask(tb, jar)
273          .baseDir(legacyClasses)
274          .files("api/Api.class")
275          .run();
276
277        return jar;
278    }
279
280    @Test
281    public void testX(Path base) throws Exception {
282        Path src = base.resolve("src");
283        Path src_m1 = src.resolve("m1x");
284        tb.writeJavaFiles(src_m1,
285                          "module m1x { provides java.lang.Runnable with impl.Impl; }",
286                          "package impl; public class Impl implements Runnable { public void run() { } }");
287        Path classes = base.resolve("classes");
288        tb.createDirectories(classes);
289
290        new JavacTask(tb)
291                .options("--module-source-path", src.toString())
292                .outdir(classes)
293                .files(findJavaFiles(src))
294                .run()
295                .writeAll();
296
297        Path unnamedSrc = base.resolve("unnamed-src");
298        Path unnamedClasses = base.resolve("unnamed-classes");
299
300        Files.createDirectories(unnamedClasses);
301
302        tb.writeJavaFiles(unnamedSrc,
303                          "package impl; public class Impl { }");
304
305        new JavacTask(tb)
306          .options("--add-reads", "m1x=ALL-UNNAMED",
307                   "-Xmodule:m1x",
308                   "--module-path", classes.toString())
309          .outdir(unnamedClasses)
310          .files(findJavaFiles(unnamedSrc))
311          .run()
312          .writeAll();
313    }
314
315    @Test
316    public void testAddSelf(Path base) throws Exception {
317        Path src = base.resolve("src");
318        Path src_m1 = src.resolve("m1x");
319        tb.writeJavaFiles(src_m1,
320                          "module m1x { exports p1; }",
321                          "package p1; public class C1 { }");
322        Path classes = base.resolve("classes");
323        tb.createDirectories(classes);
324
325        new JavacTask(tb)
326                .options("--module-source-path", src.toString(),
327                         "--add-reads", "m1x=m1x")
328                .outdir(classes)
329                .files(findJavaFiles(src))
330                .run()
331                .writeAll();
332    }
333
334    @Test
335    public void testEmpty(Path base) throws Exception {
336        Path src = base.resolve("src");
337        tb.writeJavaFiles(src, "class Dummy { }");
338        Path classes = base.resolve("classes");
339        tb.createDirectories(classes);
340
341        testEmpty(src, classes, "--add-reads", "");
342        testEmpty(src, classes, "--add-reads=");
343    }
344
345    private void testEmpty(Path src, Path classes, String... options) throws Exception {
346        String log = new JavacTask(tb, Task.Mode.CMDLINE)
347                .options(options)
348                .outdir(classes)
349                .files(findJavaFiles(src))
350                .run(Task.Expect.FAIL)
351                .writeAll()
352                .getOutput(Task.OutputKind.DIRECT);
353
354        checkOutputContains(log,
355            "javac: no value for --add-reads option");
356    }
357
358    @Test
359    public void testEmptyItem(Path base) throws Exception {
360        Path src = base.resolve("src");
361        Path src_m1 = src.resolve("m1x");
362        tb.writeJavaFiles(src_m1,
363                          "module m1x { exports p1; }",
364                          "package p1; public class C1 { }");
365        Path src_m2 = src.resolve("m2x");
366        tb.writeJavaFiles(src_m2,
367                          "module m2x { }",
368                          "package p2; class C2 { }");
369        Path src_m3 = src.resolve("m3x");
370        tb.writeJavaFiles(src_m3,
371                          "module m3x { }",
372                          "package p3; class C3 { p1.C1 c1; }");
373        Path classes = base.resolve("classes");
374        tb.createDirectories(classes);
375
376        testEmptyItem(src, classes, "m3x=,m1x");
377        testEmptyItem(src, classes, "m3x=m1x,,m2x");
378        testEmptyItem(src, classes, "m3x=m1x,");
379    }
380
381    private void testEmptyItem(Path src, Path classes, String option) throws Exception {
382        new JavacTask(tb)
383                .options("--module-source-path", src.toString(),
384                         "--add-reads", option)
385                .outdir(classes)
386                .files(findJavaFiles(src))
387                .run()
388                .writeAll();
389    }
390
391    @Test
392    public void testEmptyList(Path base) throws Exception {
393        Path src = base.resolve("src");
394        Path src_m1 = src.resolve("m1x");
395        tb.writeJavaFiles(src_m1,
396                          "module m1x { exports p1; }",
397                          "package p1; public class C1 { }");
398        Path src_m2 = src.resolve("m2x");
399        tb.writeJavaFiles(src_m2,
400                          "module m2x { }",
401                          "package p2; class C2 { }");
402        Path src_m3 = src.resolve("m3x");
403        tb.writeJavaFiles(src_m3,
404                          "module m3x { }",
405                          "package p3; class C3 { p1.C1 c1; }");
406        Path classes = base.resolve("classes");
407        tb.createDirectories(classes);
408
409        testEmptyList(src, classes, "m3x=");
410        testEmptyList(src, classes, "m3x=,");
411    }
412
413    private void testEmptyList(Path src, Path classes, String option) throws Exception {
414        String log = new JavacTask(tb, Task.Mode.CMDLINE)
415                .options("--module-source-path", src.toString(),
416                         "--add-reads", option)
417                .outdir(classes)
418                .files(findJavaFiles(src))
419                .run(Task.Expect.FAIL)
420                .writeAll()
421                .getOutput(Task.OutputKind.DIRECT);
422
423        checkOutputContains(log,
424            "javac: bad value for --add-reads option: '" + option + "'");
425    }
426
427    @Test
428    public void testMultipleAddReads_DifferentModules(Path base) throws Exception {
429        Path src = base.resolve("src");
430        Path src_m1 = src.resolve("m1x");
431        tb.writeJavaFiles(src_m1,
432                          "module m1x { exports p1; }",
433                          "package p1; public class C1 { }");
434        Path src_m2 = src.resolve("m2x");
435        tb.writeJavaFiles(src_m2,
436                          "module m2x { }",
437                          "package p2; class C2 { p1.C1 c1; }");
438        Path src_m3 = src.resolve("m3x");
439        tb.writeJavaFiles(src_m3,
440                          "module m3x { }",
441                          "package p3; class C3 { p1.C1 c1; }");
442        Path classes = base.resolve("classes");
443        tb.createDirectories(classes);
444
445        new JavacTask(tb)
446                .options("--module-source-path", src.toString(),
447                         "--add-reads", "m2x=m1x",
448                         "--add-reads", "m3x=m1x")
449                .outdir(classes)
450                .files(findJavaFiles(src))
451                .run()
452                .writeAll();
453    }
454
455    @Test
456    public void testMultipleAddReads_SameModule(Path base) throws Exception {
457        Path src = base.resolve("src");
458        Path src_m1 = src.resolve("m1x");
459        tb.writeJavaFiles(src_m1,
460                          "module m1x { exports p1; }",
461                          "package p1; public class C1 { }");
462        Path src_m2 = src.resolve("m2x");
463        tb.writeJavaFiles(src_m2,
464                          "module m2x { exports p2; }",
465                          "package p2; public class C2 { }");
466        Path src_m3 = src.resolve("m3x");
467        tb.writeJavaFiles(src_m3,
468                          "module m3x { }",
469                          "package p3; class C3 { p1.C1 c1; p2.C2 c2; }");
470        Path classes = base.resolve("classes");
471        tb.createDirectories(classes);
472
473        new JavacTask(tb)
474                .options("--module-source-path", src.toString(),
475                         "--add-reads", "m3x=m1x",
476                         "--add-reads", "m3x=m2x")
477                .outdir(classes)
478                .files(findJavaFiles(src))
479                .run()
480                .writeAll();
481    }
482
483    @Test
484    public void testDuplicateAddReads_SameOption(Path base) throws Exception {
485        Path src = base.resolve("src");
486        Path src_m1 = src.resolve("m1x");
487        tb.writeJavaFiles(src_m1,
488                          "module m1x { exports p1; }",
489                          "package p1; public class C1 { }");
490        Path src_m2 = src.resolve("m2x");
491        tb.writeJavaFiles(src_m2,
492                          "module m2x { exports p2; }",
493                          "package p2; class C2 { p1.C1 c1; }");
494        Path classes = base.resolve("classes");
495        tb.createDirectories(classes);
496
497        new JavacTask(tb)
498                .options("--module-source-path", src.toString(),
499                         "--add-reads", "m2x=m1x,m1x")
500                .outdir(classes)
501                .files(findJavaFiles(src))
502                .run()
503                .writeAll();
504    }
505
506    @Test
507    public void testDuplicateAddReads_MultipleOptions(Path base) throws Exception {
508        Path src = base.resolve("src");
509        Path src_m1 = src.resolve("m1x");
510        tb.writeJavaFiles(src_m1,
511                          "module m1x { exports p1; }",
512                          "package p1; public class C1 { }");
513        Path src_m2 = src.resolve("m2x");
514        tb.writeJavaFiles(src_m2,
515                          "module m2x { }",
516                          "package p2; class C2 { p1.C1 c1; }");
517        Path classes = base.resolve("classes");
518        tb.createDirectories(classes);
519
520        new JavacTask(tb)
521                .options("--module-source-path", src.toString(),
522                         "--add-reads", "m2x=m1x",
523                         "--add-reads", "m2x=m1x")
524                .outdir(classes)
525                .files(findJavaFiles(src))
526                .run()
527                .writeAll();
528    }
529
530    @Test
531    public void testRepeatedAddReads(Path base) throws Exception {
532        Path src = base.resolve("src");
533        Path src_m1 = src.resolve("m1x");
534        tb.writeJavaFiles(src_m1,
535                          "module m1x { exports p1; }",
536                          "package p1; public class C1 { }");
537        Path src_m2 = src.resolve("m2x");
538        tb.writeJavaFiles(src_m2,
539                          "module m2x { exports p2; }",
540                          "package p2; public class C2 { }");
541        Path src_m3 = src.resolve("m3x");
542        tb.writeJavaFiles(src_m3,
543                          "module m3x { }",
544                          "package p3; class C3 { p1.C1 c1; p2.C2 c2; }");
545        Path classes = base.resolve("classes");
546        tb.createDirectories(classes);
547
548        new JavacTask(tb)
549                .options("--module-source-path", src.toString(),
550                         "--add-reads", "m3x=m1x",
551                         "--add-reads", "m3x=m2x")
552                .outdir(classes)
553                .files(findJavaFiles(src))
554                .run()
555                .writeAll();
556    }
557
558    @Test
559    public void testNoEquals(Path base) throws Exception {
560        Path src = base.resolve("src");
561        tb.writeJavaFiles(src, "class Dummy { }");
562        Path classes = base.resolve("classes");
563        tb.createDirectories(classes);
564
565        String log = new JavacTask(tb, Task.Mode.CMDLINE)
566                .options("-XDrawDiagnostics",
567                         "--add-reads", "m1x:m2x")
568                .outdir(classes)
569                .files(findJavaFiles(src))
570                .run(Task.Expect.FAIL)
571                .writeAll()
572                .getOutput(Task.OutputKind.DIRECT);
573
574        checkOutputContains(log,
575            "javac: bad value for --add-reads option: 'm1x:m2x'");
576    }
577
578    @Test
579    public void testBadSourceName(Path base) throws Exception {
580        Path src = base.resolve("src");
581        tb.writeJavaFiles(src, "class Dummy { }");
582        Path classes = base.resolve("classes");
583        tb.createDirectories(classes);
584
585        String log = new JavacTask(tb)
586                .options("-XDrawDiagnostics",
587                         "--add-reads", "bad*Source=m2x")
588                .outdir(classes)
589                .files(findJavaFiles(src))
590                .run()
591                .writeAll()
592                .getOutput(Task.OutputKind.DIRECT);
593
594        checkOutputContains(log,
595            "- compiler.warn.bad.name.for.option: --add-reads, bad*Source");
596    }
597
598    @Test
599    public void testBadTargetName(Path base) throws Exception {
600        Path src = base.resolve("src");
601        Path src_m1 = src.resolve("m1x");
602        tb.writeJavaFiles(src_m1,
603                          "module m1x { }",
604                          "package p1; class C1 { }");
605        Path classes = base.resolve("classes");
606        tb.createDirectories(classes);
607
608        String log = new JavacTask(tb)
609                .options("-XDrawDiagnostics",
610                         "--add-reads", "m1x=badTarget!")
611                .outdir(classes)
612                .files(findJavaFiles(src))
613                .run()
614                .writeAll()
615                .getOutput(Task.OutputKind.DIRECT);
616
617        checkOutputContains(log,
618            "- compiler.warn.bad.name.for.option: --add-reads, badTarget!");
619    }
620
621    @Test
622    public void testSourceNameNotFound(Path base) throws Exception {
623        Path src = base.resolve("src");
624        Path src_m1 = src.resolve("m1x");
625        tb.writeJavaFiles(src_m1,
626                          "module m1x { exports p1; }",
627                          "package p1; public class C1 { }");
628        Path classes = base.resolve("classes");
629        tb.createDirectories(classes);
630
631        String log = new JavacTask(tb)
632                .options("-XDrawDiagnostics",
633                         "--add-reads", "missingSource=m")
634                .outdir(classes)
635                .files(findJavaFiles(src))
636                .run()
637                .writeAll()
638                .getOutput(Task.OutputKind.DIRECT);
639
640        checkOutputContains(log,
641            "- compiler.warn.module.for.option.not.found: --add-reads, missingSource");
642    }
643
644    @Test
645    public void testTargetNameNotFound(Path base) throws Exception {
646        Path src = base.resolve("src");
647        Path src_m1 = src.resolve("m1x");
648        tb.writeJavaFiles(src_m1,
649                          "module m1x { exports p1; }",
650                          "package p1; public class C1 { }");
651        Path classes = base.resolve("classes");
652        tb.createDirectories(classes);
653
654        String log = new JavacTask(tb)
655                .options("-XDrawDiagnostics",
656                         "--add-reads", "m1x=missingTarget")
657                .outdir(classes)
658                .files(findJavaFiles(src))
659                .run()
660                .writeAll()
661                .getOutput(Task.OutputKind.DIRECT);
662
663        checkOutputContains(log,
664            "- compiler.warn.module.for.option.not.found: --add-reads, missingTarget");
665    }
666}
667