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 * @library /lib/testlibrary 27 * @build AutomaticModulesTest ModuleUtils JarUtils 28 * @run testng AutomaticModulesTest 29 * @summary Basic tests for automatic modules 30 */ 31 32 import java.io.IOException; 33 import java.lang.module.Configuration; 34 import java.lang.module.FindException; 35 import java.lang.module.ModuleDescriptor; 36 import java.lang.module.ModuleDescriptor.Exports; 37 import java.lang.module.ModuleDescriptor.Requires.Modifier; 38 import java.lang.module.ModuleFinder; 39 import java.lang.module.ModuleReference; 40 import java.lang.module.ResolvedModule; 41 import java.lang.reflect.Layer; 42 import java.lang.reflect.Module; 43 import java.nio.file.Files; 44 import java.nio.file.Path; 45 import java.nio.file.Paths; 46 import java.util.Optional; 47 import java.util.Set; 48 import java.util.jar.Attributes; 49 import java.util.jar.Manifest; 50 import java.util.stream.Collectors; 51 import java.util.stream.Stream; 52 53 import org.testng.annotations.DataProvider; 54 import org.testng.annotations.Test; 55 import static org.testng.Assert.*; 56 57 @Test 58 public class AutomaticModulesTest { 59 60 private static final Path USER_DIR 61 = Paths.get(System.getProperty("user.dir")); 62 63 @DataProvider(name = "names") 64 public Object[][] createNames() { 65 return new Object[][] { 66 67 // JAR file name module-name[/version] 68 69 { "foo.jar", "foo" }, 70 { "foo4j.jar", "foo4j", }, 71 72 { "foo1.jar", "foo" }, 73 { "foo1.2.jar", "foo" }, 74 { "foo1.2.3.jar", "foo" }, 75 76 { "foo10.jar", "foo" }, 77 { "foo10.20.jar", "foo" }, 78 { "foo10.20.30.jar", "foo" }, 79 80 { "foo-1.jar", "foo/1" }, 81 { "foo-1.2.jar", "foo/1.2" }, 82 { "foo-1.2.3.jar", "foo/1.2.3" }, 83 { "foo-1.2.3.4.jar", "foo/1.2.3.4" }, 84 85 { "foo-10.jar", "foo/10" }, 86 { "foo-10.20.jar", "foo/10.20" }, 87 { "foo-10.20.30.jar", "foo/10.20.30" }, 88 { "foo-10.20.30.40.jar", "foo/10.20.30.40" }, 89 90 { "foo-bar.jar", "foo.bar" }, 91 { "foo-bar-1.jar", "foo.bar/1" }, 92 { "foo-bar-1.2.jar", "foo.bar/1.2"}, 93 { "foo-bar-10.jar", "foo.bar/10" }, 94 { "foo-bar-10.20.jar", "foo.bar/10.20" }, 95 96 { "foo-1.2-SNAPSHOT.jar", "foo/1.2-SNAPSHOT" }, 97 { "foo-bar-1.2-SNAPSHOT.jar", "foo.bar/1.2-SNAPSHOT" }, 98 99 { "foo--bar-1.0.jar", "foo.bar/1.0" }, 100 { "-foo-bar-1.0.jar", "foo.bar/1.0" }, 101 { "foo-bar--1.0.jar", "foo.bar/1.0" }, 102 103 }; 104 } 105 106 // JAR file names that do not map to a legal module name 107 @DataProvider(name = "badnames") 108 public Object[][] createBadNames() { 109 return new Object[][]{ 110 111 { ".jar", null }, 112 { "_.jar", null } 113 114 }; 115 } 116 117 /** 118 * Test mapping of JAR file names to module names 119 */ 120 @Test(dataProvider = "names") 121 public void testNames(String fn, String mid) throws IOException { 122 String[] s = mid.split("/"); 123 String mn = s[0]; 124 String vs = (s.length == 2) ? s[1] : null; 125 126 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 127 Path jf = dir.resolve(fn); 128 129 // create empty JAR file 130 createDummyJarFile(jf); 131 132 // create a ModuleFinder to find modules in the directory 133 ModuleFinder finder = ModuleFinder.of(dir); 134 135 // a module with the expected name should be found 136 Optional<ModuleReference> mref = finder.find(mn); 137 assertTrue(mref.isPresent(), mn + " not found"); 138 139 ModuleDescriptor descriptor = mref.get().descriptor(); 140 assertEquals(descriptor.name(), mn); 141 if (vs == null) { 142 assertFalse(descriptor.version().isPresent()); 143 } else { 144 assertEquals(descriptor.version().get().toString(), vs); 145 } 146 } 147 148 149 /** 150 * Test impossible mapping of JAR files to modules names 151 */ 152 @Test(dataProvider = "badnames", expectedExceptions = FindException.class) 153 public void testBadNames(String fn, String ignore) throws IOException { 154 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 155 Path jf = dir.resolve(fn); 156 157 // create empty JAR file 158 createDummyJarFile(jf); 159 160 // should throw FindException 161 ModuleFinder.of(dir).findAll(); 162 } 163 164 165 /** 166 * Test all packages are exported 167 */ 168 public void testPackages() throws IOException { 169 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 170 createDummyJarFile(dir.resolve("m.jar"), 171 "p/C1.class", "p/C2.class", "q/C1.class"); 172 173 ModuleFinder finder = ModuleFinder.of(dir); 174 Optional<ModuleReference> mref = finder.find("m"); 175 assertTrue(mref.isPresent(), "m not found"); 176 177 ModuleDescriptor descriptor = mref.get().descriptor(); 178 179 assertTrue(descriptor.packages().size() == 2); 180 assertTrue(descriptor.packages().contains("p")); 181 assertTrue(descriptor.packages().contains("q")); 182 183 Set<String> exports = descriptor.exports().stream() 184 .map(Exports::source) 185 .collect(Collectors.toSet()); 186 assertTrue(exports.size() == 2); 187 assertTrue(exports.contains("p")); 188 assertTrue(exports.contains("q")); 189 } 190 191 /** 192 * Test class files in JAR file where the entry does not correspond to a 193 * legal package name. 194 */ 195 public void testBadPackage() throws IOException { 196 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 197 createDummyJarFile(dir.resolve("m.jar"), "p/C1.class", "p-/C2.class"); 198 199 ModuleFinder finder = ModuleFinder.of(dir); 200 Optional<ModuleReference> mref = finder.find("m"); 201 assertTrue(mref.isPresent(), "m not found"); 202 203 ModuleDescriptor descriptor = mref.get().descriptor(); 204 205 assertTrue(descriptor.packages().size() == 1); 206 assertTrue(descriptor.packages().contains("p")); 207 208 Set<String> exports = descriptor.exports().stream() 209 .map(Exports::source) 210 .collect(Collectors.toSet()); 211 assertTrue(exports.size() == 1); 212 assertTrue(exports.contains("p")); 213 } 214 215 /** 216 * Test non-class resources in a JAR file. 217 */ 218 public void testNonClassResources() throws IOException { 219 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 220 createDummyJarFile(dir.resolve("m.jar"), 221 "LICENSE", 222 "README", 223 "WEB-INF/tags", 224 "p/Type.class", 225 "p/resources/m.properties"); 226 227 ModuleFinder finder = ModuleFinder.of(dir); 228 Optional<ModuleReference> mref = finder.find("m"); 229 assertTrue(mref.isPresent(), "m not found"); 230 231 ModuleDescriptor descriptor = mref.get().descriptor(); 232 233 assertTrue(descriptor.packages().size() == 2); 234 assertTrue(descriptor.packages().contains("p")); 235 assertTrue(descriptor.packages().contains("p.resources")); 236 } 237 238 /** 239 * Test .class file in unnamed package (top-level directory) 240 */ 241 @Test(expectedExceptions = FindException.class) 242 public void testClassInUnnamedPackage() throws IOException { 243 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 244 createDummyJarFile(dir.resolve("m.jar"), "Mojo.class"); 245 ModuleFinder finder = ModuleFinder.of(dir); 246 finder.findAll(); 247 } 248 249 /** 250 * Test JAR file with META-INF/services configuration file 251 */ 252 public void testServicesConfiguration() throws IOException { 253 String service = "p.S"; 254 String provider = "p.S1"; 255 256 Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp"); 257 Path services = tmpdir.resolve("META-INF").resolve("services"); 258 Files.createDirectories(services); 259 Files.write(services.resolve(service), Set.of(provider)); 260 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 261 JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir); 262 263 ModuleFinder finder = ModuleFinder.of(dir); 264 265 Optional<ModuleReference> mref = finder.find("m"); 266 assertTrue(mref.isPresent(), "m not found"); 267 268 ModuleDescriptor descriptor = mref.get().descriptor(); 269 assertTrue(descriptor.provides().size() == 1); 270 ModuleDescriptor.Provides provides = descriptor.provides().iterator().next(); 271 assertEquals(provides.service(), service); 272 assertTrue(provides.providers().size() == 1); 273 assertTrue(provides.providers().contains((provider))); 274 } 275 276 277 // META-INF/services files that don't map to legal service names 278 @DataProvider(name = "badservices") 279 public Object[][] createBadServices() { 280 return new Object[][] { 281 282 // service type provider type 283 { "-", "p.S1" }, 284 { ".S", "p.S1" }, 285 }; 286 } 287 288 /** 289 * Test JAR file with META-INF/services configuration file with bad 290 * values or names. 291 */ 292 @Test(dataProvider = "badservices") 293 public void testBadServicesNames(String service, String provider) 294 throws IOException 295 { 296 Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp"); 297 Path services = tmpdir.resolve("META-INF").resolve("services"); 298 Files.createDirectories(services); 299 Files.write(services.resolve(service), Set.of(provider)); 300 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 301 JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir); 302 303 Optional<ModuleReference> omref = ModuleFinder.of(dir).find("m"); 304 assertTrue(omref.isPresent()); 305 ModuleDescriptor descriptor = omref.get().descriptor(); 306 assertTrue(descriptor.provides().isEmpty()); 307 } 308 309 310 // META-INF/services configuration file entries that are not legal 311 @DataProvider(name = "badproviders") 312 public Object[][] createBadProviders() { 313 return new Object[][] { 314 315 // service type provider type 316 { "p.S", "-" }, 317 { "p.S", ".S1" }, 318 { "p.S", "S1." }, 319 }; 320 } 321 322 /** 323 * Test JAR file with META-INF/services configuration file with bad 324 * values or names. 325 */ 326 @Test(dataProvider = "badproviders", expectedExceptions = FindException.class) 327 public void testBadProvideNames(String service, String provider) 328 throws IOException 329 { 330 Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp"); 331 Path services = tmpdir.resolve("META-INF").resolve("services"); 332 Files.createDirectories(services); 333 Files.write(services.resolve(service), Set.of(provider)); 334 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 335 JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir); 336 337 // should throw FindException 338 ModuleFinder.of(dir).findAll(); 339 } 340 341 342 /** 343 * Test that a JAR file with a Main-Class attribute results 344 * in a module with a main class. 345 */ 346 public void testMainClass() throws IOException { 347 String mainClass = "p.Main"; 348 349 Manifest man = new Manifest(); 350 Attributes attrs = man.getMainAttributes(); 351 attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0"); 352 attrs.put(Attributes.Name.MAIN_CLASS, mainClass); 353 354 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 355 createDummyJarFile(dir.resolve("m.jar"), man); 356 357 ModuleFinder finder = ModuleFinder.of(dir); 358 359 Configuration parent = Layer.boot().configuration(); 360 Configuration cf = resolve(parent, finder, "m"); 361 362 ModuleDescriptor descriptor = findDescriptor(cf, "m"); 363 364 assertTrue(descriptor.mainClass().isPresent()); 365 assertEquals(descriptor.mainClass().get(), mainClass); 366 } 367 368 369 // Main-Class files that do not map to a legal Java identifier 370 @DataProvider(name = "badmainclass") 371 public Object[][] createBadMainClass() { 372 return new Object[][]{ 373 374 { "p-.Main", null }, 375 { ".Main", null } 376 377 }; 378 } 379 380 /** 381 * Test that a JAR file with a Main-Class attribute that is not a valid 382 * Java identifier 383 */ 384 @Test(dataProvider = "badmainclass", expectedExceptions = FindException.class) 385 public void testBadMainClass(String mainClass, String ignore) throws IOException { 386 Manifest man = new Manifest(); 387 Attributes attrs = man.getMainAttributes(); 388 attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0"); 389 attrs.put(Attributes.Name.MAIN_CLASS, mainClass); 390 391 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 392 createDummyJarFile(dir.resolve("m.jar"), man); 393 394 // should throw FindException 395 ModuleFinder.of(dir).findAll(); 396 } 397 398 399 /** 400 * Basic test of a configuration created with automatic modules. 401 * a requires b* 402 * a requires c* 403 * b* 404 * c* 405 */ 406 public void testConfiguration1() throws Exception { 407 ModuleDescriptor descriptor1 408 = ModuleDescriptor.module("a") 409 .requires("b") 410 .requires("c") 411 .requires("java.base") 412 .build(); 413 414 // b and c are automatic modules 415 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 416 createDummyJarFile(dir.resolve("b.jar"), "p/T.class"); 417 createDummyJarFile(dir.resolve("c.jar"), "q/T.class"); 418 419 // module finder locates a and the modules in the directory 420 ModuleFinder finder 421 = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1), 422 ModuleFinder.of(dir)); 423 424 Configuration parent = Layer.boot().configuration(); 425 Configuration cf = resolve(parent, finder, "a"); 426 427 assertTrue(cf.modules().size() == 3); 428 assertTrue(cf.findModule("a").isPresent()); 429 assertTrue(cf.findModule("b").isPresent()); 430 assertTrue(cf.findModule("c").isPresent()); 431 432 ResolvedModule base = cf.findModule("java.base").get(); 433 assertTrue(base.configuration() == Layer.boot().configuration()); 434 ResolvedModule a = cf.findModule("a").get(); 435 ResolvedModule b = cf.findModule("b").get(); 436 ResolvedModule c = cf.findModule("c").get(); 437 438 // b && c only require java.base 439 assertTrue(b.reference().descriptor().requires().size() == 1); 440 assertTrue(c.reference().descriptor().requires().size() == 1); 441 442 // readability 443 444 assertTrue(a.reads().size() == 3); 445 assertTrue(a.reads().contains(base)); 446 assertTrue(a.reads().contains(b)); 447 assertTrue(a.reads().contains(c)); 448 449 assertTrue(b.reads().contains(a)); 450 assertTrue(b.reads().contains(c)); 451 testReadAllBootModules(cf, "b"); // b reads all modules in boot layer 452 453 assertTrue(c.reads().contains(a)); 454 assertTrue(c.reads().contains(b)); 455 testReadAllBootModules(cf, "c"); // c reads all modules in boot layer 456 457 } 458 459 /** 460 * Basic test of a configuration created with automatic modules 461 * a requires b 462 * b requires c* 463 * c* 464 * d* 465 */ 466 public void testInConfiguration2() throws IOException { 467 ModuleDescriptor descriptor1 468 = ModuleDescriptor.module("a") 469 .requires("b") 470 .requires("java.base") 471 .build(); 472 473 ModuleDescriptor descriptor2 474 = ModuleDescriptor.module("b") 475 .requires("c") 476 .requires("java.base") 477 .build(); 478 479 // c and d are automatic modules 480 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 481 createDummyJarFile(dir.resolve("c.jar"), "p/T.class"); 482 createDummyJarFile(dir.resolve("d.jar"), "q/T.class"); 483 484 // module finder locates a and the modules in the directory 485 ModuleFinder finder 486 = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1, descriptor2), 487 ModuleFinder.of(dir)); 488 489 Configuration parent = Layer.boot().configuration(); 490 Configuration cf = resolve(parent, finder, "a", "d"); 491 492 assertTrue(cf.modules().size() == 4); 493 assertTrue(cf.findModule("a").isPresent()); 494 assertTrue(cf.findModule("b").isPresent()); 495 assertTrue(cf.findModule("c").isPresent()); 496 assertTrue(cf.findModule("d").isPresent()); 497 498 // c && d should only require java.base 499 assertTrue(findDescriptor(cf, "c").requires().size() == 1); 500 assertTrue(findDescriptor(cf, "d").requires().size() == 1); 501 502 // readability 503 504 ResolvedModule base = cf.findModule("java.base").get(); 505 assertTrue(base.configuration() == Layer.boot().configuration()); 506 ResolvedModule a = cf.findModule("a").get(); 507 ResolvedModule b = cf.findModule("b").get(); 508 ResolvedModule c = cf.findModule("c").get(); 509 ResolvedModule d = cf.findModule("d").get(); 510 511 assertTrue(a.reads().size() == 2); 512 assertTrue(a.reads().contains(b)); 513 assertTrue(a.reads().contains(base)); 514 515 assertTrue(b.reads().size() == 3); 516 assertTrue(b.reads().contains(c)); 517 assertTrue(b.reads().contains(d)); 518 assertTrue(b.reads().contains(base)); 519 520 assertTrue(c.reads().contains(a)); 521 assertTrue(c.reads().contains(b)); 522 assertTrue(c.reads().contains(d)); 523 testReadAllBootModules(cf, "c"); // c reads all modules in boot layer 524 525 assertTrue(d.reads().contains(a)); 526 assertTrue(d.reads().contains(b)); 527 assertTrue(d.reads().contains(c)); 528 testReadAllBootModules(cf, "d"); // d reads all modules in boot layer 529 } 530 531 532 /** 533 * Basic test of a configuration created with automatic modules 534 * a requires b 535 * b requires transitive c* 536 * c* 537 * d* 538 */ 539 public void testInConfiguration3() throws IOException { 540 ModuleDescriptor descriptor1 541 = ModuleDescriptor.module("a") 542 .requires("b") 543 .requires("java.base") 544 .build(); 545 546 ModuleDescriptor descriptor2 547 = ModuleDescriptor.module("b") 548 .requires(Set.of(Modifier.TRANSITIVE), "c") 549 .requires("java.base") 550 .build(); 551 552 // c and d are automatic modules 553 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 554 createDummyJarFile(dir.resolve("c.jar"), "p/T.class"); 555 createDummyJarFile(dir.resolve("d.jar"), "q/T.class"); 556 557 // module finder locates a and the modules in the directory 558 ModuleFinder finder 559 = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1, descriptor2), 560 ModuleFinder.of(dir)); 561 562 Configuration parent = Layer.boot().configuration(); 563 Configuration cf = resolve(parent, finder, "a", "d"); 564 565 assertTrue(cf.modules().size() == 4); 566 assertTrue(cf.findModule("a").isPresent()); 567 assertTrue(cf.findModule("b").isPresent()); 568 assertTrue(cf.findModule("c").isPresent()); 569 assertTrue(cf.findModule("d").isPresent()); 570 571 ResolvedModule base = cf.findModule("java.base").get(); 572 assertTrue(base.configuration() == Layer.boot().configuration()); 573 ResolvedModule a = cf.findModule("a").get(); 574 ResolvedModule b = cf.findModule("b").get(); 575 ResolvedModule c = cf.findModule("c").get(); 576 ResolvedModule d = cf.findModule("d").get(); 577 578 // c && d should only require java.base 579 assertTrue(findDescriptor(cf, "c").requires().size() == 1); 580 assertTrue(findDescriptor(cf, "d").requires().size() == 1); 581 582 // readability 583 584 assertTrue(a.reads().size() == 4); 585 assertTrue(a.reads().contains(b)); 586 assertTrue(a.reads().contains(c)); 587 assertTrue(a.reads().contains(d)); 588 assertTrue(a.reads().contains(base)); 589 590 assertTrue(b.reads().size() == 3); 591 assertTrue(b.reads().contains(c)); 592 assertTrue(b.reads().contains(d)); 593 assertTrue(b.reads().contains(base)); 594 595 assertTrue(reads(cf, "b", "c")); 596 assertTrue(reads(cf, "b", "d")); 597 assertTrue(reads(cf, "b", "java.base")); 598 599 assertTrue(c.reads().contains(a)); 600 assertTrue(c.reads().contains(b)); 601 assertTrue(c.reads().contains(d)); 602 testReadAllBootModules(cf, "c"); // c reads all modules in boot layer 603 604 assertTrue(d.reads().contains(a)); 605 assertTrue(d.reads().contains(b)); 606 assertTrue(d.reads().contains(c)); 607 testReadAllBootModules(cf, "d"); // d reads all modules in boot layer 608 } 609 610 611 /** 612 * Basic test of Layer containing automatic modules 613 */ 614 public void testInLayer() throws IOException { 615 ModuleDescriptor descriptor 616 = ModuleDescriptor.module("a") 617 .requires("b") 618 .requires("c") 619 .build(); 620 621 // b and c are simple JAR files 622 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 623 createDummyJarFile(dir.resolve("b.jar"), "p/T.class"); 624 createDummyJarFile(dir.resolve("c.jar"), "q/T2.class"); 625 626 // module finder locates a and the modules in the directory 627 ModuleFinder finder 628 = ModuleFinder.compose(ModuleUtils.finderOf(descriptor), 629 ModuleFinder.of(dir)); 630 631 Configuration parent = Layer.boot().configuration(); 632 Configuration cf = resolve(parent, finder, "a"); 633 assertTrue(cf.modules().size() == 3); 634 635 // each module gets its own loader 636 Layer layer = Layer.boot().defineModules(cf, mn -> new ClassLoader() { }); 637 638 // an unnamed module 639 Module unnamed = (new ClassLoader() { }).getUnnamedModule(); 640 641 Module b = layer.findModule("b").get(); 642 assertTrue(b.isNamed()); 643 assertTrue(b.canRead(unnamed)); 644 testsReadsAll(b, layer); 645 646 Module c = layer.findModule("c").get(); 647 assertTrue(c.isNamed()); 648 assertTrue(b.canRead(unnamed)); 649 testsReadsAll(c, layer); 650 } 651 652 653 /** 654 * Test miscellaneous methods. 655 */ 656 public void testMisc() throws IOException { 657 Path dir = Files.createTempDirectory(USER_DIR, "mods"); 658 Path m_jar = createDummyJarFile(dir.resolve("m.jar"), "p/T.class"); 659 660 ModuleFinder finder = ModuleFinder.of(m_jar); 661 662 assertTrue(finder.find("m").isPresent()); 663 ModuleDescriptor m = finder.find("m").get().descriptor(); 664 665 // test miscellaneous methods 666 assertTrue(m.isAutomatic()); 667 assertFalse(m.isSynthetic()); 668 assertFalse(m.osName().isPresent()); 669 assertFalse(m.osArch().isPresent()); 670 assertFalse(m.osVersion().isPresent()); 671 } 672 673 674 /** 675 * Invokes parent.resolveRequires to resolve the given root modules. 676 */ 677 static Configuration resolve(Configuration parent, 678 ModuleFinder finder, 679 String... roots) { 680 return parent.resolveRequires(finder, ModuleFinder.of(), Set.of(roots)); 681 } 682 683 /** 684 * Finds a module in the given configuration or its parents, returning 685 * the module descriptor (or null if not found) 686 */ 687 static ModuleDescriptor findDescriptor(Configuration cf, String name) { 688 Optional<ResolvedModule> om = cf.findModule(name); 689 if (om.isPresent()) { 690 return om.get().reference().descriptor(); 691 } else { 692 return null; 693 } 694 } 695 696 /** 697 * Test that a module in a configuration reads all modules in the boot 698 * configuration. 699 */ 700 static void testReadAllBootModules(Configuration cf, String mn) { 701 702 Set<String> bootModules = Layer.boot().modules().stream() 703 .map(Module::getName) 704 .collect(Collectors.toSet()); 705 706 bootModules.forEach(other -> assertTrue(reads(cf, mn, other))); 707 708 } 709 710 /** 711 * Test that the given Module reads all module in the given Layer 712 * and its parent Layers. 713 */ 714 static void testsReadsAll(Module m, Layer layer) { 715 // check that m reads all modules in the layer 716 layer.configuration().modules().stream() 717 .map(ResolvedModule::name) 718 .map(layer::findModule) 719 .map(Optional::get) 720 .forEach(other -> assertTrue(m.canRead(other))); 721 722 // also check parent layers 723 layer.parents().forEach(l -> testsReadsAll(m, l)); 724 } 725 726 /** 727 * Returns {@code true} if the configuration contains module mn1 728 * that reads module mn2. 729 */ 730 static boolean reads(Configuration cf, String mn1, String mn2) { 731 Optional<ResolvedModule> om = cf.findModule(mn1); 732 if (!om.isPresent()) 733 return false; 734 735 return om.get().reads().stream() 736 .map(ResolvedModule::name) 737 .anyMatch(mn2::equals); 738 } 739 740 /** 741 * Creates a JAR file, optionally with a manifest, and with the given 742 * entries. The entries will be empty in the resulting JAR file. 743 */ 744 static Path createDummyJarFile(Path jarfile, Manifest man, String... entries) 745 throws IOException 746 { 747 Path dir = Files.createTempDirectory(USER_DIR, "tmp"); 748 749 for (String entry : entries) { 750 Path file = dir.resolve(entry); 751 Path parent = file.getParent(); 752 if (parent != null) 753 Files.createDirectories(parent); 754 Files.createFile(file); 755 } 756 757 Path[] paths = Stream.of(entries).map(Paths::get).toArray(Path[]::new); 758 JarUtils.createJarFile(jarfile, man, dir, paths); 759 return jarfile; 760 } 761 762 /** 763 * Creates a JAR file and with the given entries. The entries will be empty 764 * in the resulting JAR file. 765 */ 766 static Path createDummyJarFile(Path jarfile, String... entries) 767 throws IOException 768 { 769 return createDummyJarFile(jarfile, null, entries); 770 } 771 772 }