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 
  36 import java.nio.file.Files;
  37 import java.nio.file.Path;
  38 import java.util.Set;
  39 
  40 import javax.annotation.processing.AbstractProcessor;
  41 import javax.annotation.processing.RoundEnvironment;
  42 import javax.annotation.processing.SupportedAnnotationTypes;
  43 import javax.lang.model.SourceVersion;
  44 import javax.lang.model.element.ModuleElement;
  45 import javax.lang.model.element.ModuleElement.RequiresDirective;
  46 import javax.lang.model.element.TypeElement;
  47 import javax.lang.model.util.ElementFilter;
  48 
  49 import toolbox.JarTask;
  50 import toolbox.JavacTask;
  51 import toolbox.JavapTask;
  52 import toolbox.Task;
  53 
  54 public 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:41: compiler.err.package.not.visible: api, (compiler.misc.not.def.access.does.not.read: m2x, api, m1x)");
  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                    "--patch-module", "java.base=" + src.toString())
 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                    "--patch-module", "java.base=" + src)
 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                    "--patch-module", "m1x=" + unnamedSrc.toString(),
 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 }