2476be4590
Reviewed-by: mchung
1200 lines
44 KiB
Java
1200 lines
44 KiB
Java
/*
|
|
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
/**
|
|
* @test
|
|
* @bug 8142968 8253751 8262944 8314986
|
|
* @library /test/lib
|
|
* @build AutomaticModulesTest
|
|
* jdk.test.lib.util.JarUtils
|
|
* jdk.test.lib.util.ModuleUtils
|
|
* @run junit AutomaticModulesTest
|
|
* @summary Basic tests for automatic modules
|
|
*/
|
|
|
|
import java.io.IOException;
|
|
import java.lang.module.Configuration;
|
|
import java.lang.module.FindException;
|
|
import java.lang.module.InvalidModuleDescriptorException;
|
|
import java.lang.module.ModuleDescriptor;
|
|
import java.lang.module.ModuleDescriptor.Requires.Modifier;
|
|
import java.lang.module.ModuleFinder;
|
|
import java.lang.module.ModuleReference;
|
|
import java.lang.module.ResolutionException;
|
|
import java.lang.module.ResolvedModule;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
import java.util.jar.Attributes;
|
|
import java.util.jar.Manifest;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Stream;
|
|
|
|
import jdk.test.lib.util.JarUtils;
|
|
import jdk.test.lib.util.ModuleUtils;
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
import org.junit.jupiter.params.ParameterizedTest;
|
|
import org.junit.jupiter.params.provider.Arguments;
|
|
import org.junit.jupiter.params.provider.MethodSource;
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
|
|
|
public class AutomaticModulesTest {
|
|
private static final Path USER_DIR = Path.of(System.getProperty("user.dir"));
|
|
|
|
// JAR file name to expected module name / version
|
|
static Stream<Arguments> jarNames() {
|
|
return Stream.of(
|
|
arguments( "foo.jar", "foo" ),
|
|
arguments( "foo4j.jar", "foo4j" ),
|
|
|
|
arguments( "foo1.jar", "foo1" ),
|
|
arguments( "foo10.jar", "foo10" ),
|
|
|
|
arguments( "foo-1.jar", "foo/1" ),
|
|
arguments( "foo-1.2.jar", "foo/1.2" ),
|
|
arguments( "foo-1.2.3.jar", "foo/1.2.3" ),
|
|
arguments( "foo-1.2.3.4.jar", "foo/1.2.3.4" ),
|
|
|
|
arguments( "foo-10.jar", "foo/10" ),
|
|
arguments( "foo-10.20.jar", "foo/10.20" ),
|
|
arguments( "foo-10.20.30.jar", "foo/10.20.30" ),
|
|
arguments( "foo-10.20.30.40.jar", "foo/10.20.30.40" ),
|
|
|
|
arguments( "foo-bar.jar", "foo.bar" ),
|
|
arguments( "foo-bar-1.jar", "foo.bar/1" ),
|
|
arguments( "foo-bar-1.2.jar", "foo.bar/1.2" ),
|
|
arguments( "foo-bar-10.jar", "foo.bar/10" ),
|
|
arguments( "foo-bar-10.20.jar", "foo.bar/10.20" ),
|
|
|
|
arguments("foo.bar1.jar", "foo.bar1" ),
|
|
arguments( "foo.bar10.jar", "foo.bar10" ),
|
|
|
|
arguments( "foo-1.2-SNAPSHOT.jar", "foo/1.2-SNAPSHOT" ),
|
|
arguments( "foo-bar-1.2-SNAPSHOT.jar", "foo.bar/1.2-SNAPSHOT" ),
|
|
|
|
arguments( "foo--bar-1.0.jar", "foo.bar/1.0" ),
|
|
arguments( "-foo-bar-1.0.jar", "foo.bar/1.0" ),
|
|
arguments( "foo-bar--1.0.jar", "foo.bar/1.0" )
|
|
);
|
|
}
|
|
|
|
// JAR file names that do not map to a legal module name
|
|
static Stream<String> barJarNames() {
|
|
return Stream.of(
|
|
".jar",
|
|
"_.jar",
|
|
"foo.1.jar",
|
|
"1foo.jar",
|
|
"foo.1bar.jar"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test mapping of JAR file names to module names
|
|
*/
|
|
@ParameterizedTest
|
|
@MethodSource("jarNames")
|
|
public void testNames(String fn, String mid) throws IOException {
|
|
String[] s = mid.split("/");
|
|
String mn = s[0];
|
|
String vs = (s.length == 2) ? s[1] : null;
|
|
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
Path jf = dir.resolve(fn);
|
|
|
|
// create empty JAR file
|
|
createDummyJarFile(jf);
|
|
|
|
// create a ModuleFinder to find modules in the directory
|
|
ModuleFinder finder = ModuleFinder.of(dir);
|
|
|
|
// a module with the expected name should be found
|
|
Optional<ModuleReference> mref = finder.find(mn);
|
|
assertTrue(mref.isPresent(), mn + " not found");
|
|
|
|
ModuleDescriptor descriptor = mref.get().descriptor();
|
|
assertTrue(descriptor.isAutomatic());
|
|
assertEquals(mn, descriptor.name());
|
|
if (vs == null) {
|
|
assertFalse(descriptor.version().isPresent());
|
|
} else {
|
|
assertEquals(vs, descriptor.version().get().toString());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test impossible mapping of JAR files to modules names
|
|
*/
|
|
@ParameterizedTest
|
|
@MethodSource("barJarNames")
|
|
public void testBadNames(String fn) throws IOException {
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
Path jf = dir.resolve(fn);
|
|
|
|
// create empty JAR file
|
|
createDummyJarFile(jf);
|
|
|
|
// should throw FindException
|
|
var finder = ModuleFinder.of(dir);
|
|
assertThrows(FindException.class, finder::findAll);
|
|
}
|
|
|
|
// Automatic-Module-Name attribute values and version in JAR file name
|
|
static Stream<Arguments> automaticModuleNames() {
|
|
return Stream.of(
|
|
arguments( "foo", null ),
|
|
arguments( "foo", "1.0" ),
|
|
arguments( "foo.bar", null ),
|
|
arguments( "foo.bar", "1.0" ),
|
|
arguments( "class_", null ),
|
|
arguments( "class_", "1.0" )
|
|
);
|
|
}
|
|
|
|
// Bad Automatic-Module-Name attribute values
|
|
static Stream<String> badAutomaticModuleNames() {
|
|
return Stream.of(
|
|
"",
|
|
"666",
|
|
"foo.class"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test JAR files with the Automatic-Module-Name attribute
|
|
*/
|
|
@ParameterizedTest
|
|
@MethodSource("automaticModuleNames")
|
|
public void testAutomaticModuleNameAttribute(String name, String vs)
|
|
throws IOException
|
|
{
|
|
Manifest man = new Manifest();
|
|
Attributes attrs = man.getMainAttributes();
|
|
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
|
|
attrs.put(new Attributes.Name("Automatic-Module-Name"), name);
|
|
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
String jar;
|
|
if (vs == null) {
|
|
jar = "m.jar";
|
|
} else {
|
|
jar = "m-" + vs + ".jar";
|
|
}
|
|
createDummyJarFile(dir.resolve(jar), man);
|
|
|
|
ModuleFinder finder = ModuleFinder.of(dir);
|
|
|
|
assertTrue(finder.findAll().size() == 1);
|
|
assertTrue(finder.find(name).isPresent());
|
|
|
|
ModuleReference mref = finder.find(name).get();
|
|
ModuleDescriptor descriptor = mref.descriptor();
|
|
assertEquals(name, descriptor.name());
|
|
assertEquals(vs, descriptor.version()
|
|
.map(ModuleDescriptor.Version::toString)
|
|
.orElse(null));
|
|
}
|
|
|
|
/**
|
|
* Test JAR files with the Automatic-Module-Name attribute with a value
|
|
* that is not a legal module name.
|
|
*/
|
|
@ParameterizedTest
|
|
@MethodSource("badAutomaticModuleNames")
|
|
public void testBadAutomaticModuleNameAttribute(String name) throws IOException {
|
|
assertThrows(FindException.class, () -> testAutomaticModuleNameAttribute(name, null));
|
|
}
|
|
|
|
/**
|
|
* Test all packages are exported
|
|
*/
|
|
@Test
|
|
public void testPackages() throws IOException {
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("m.jar"),
|
|
"p/C1.class", "p/C2.class", "q/C1.class");
|
|
|
|
ModuleFinder finder = ModuleFinder.of(dir);
|
|
Optional<ModuleReference> mref = finder.find("m");
|
|
assertTrue(mref.isPresent(), "m not found");
|
|
|
|
ModuleDescriptor descriptor = mref.get().descriptor();
|
|
assertTrue(descriptor.isAutomatic());
|
|
|
|
assertTrue(descriptor.packages().size() == 2);
|
|
assertTrue(descriptor.packages().contains("p"));
|
|
assertTrue(descriptor.packages().contains("q"));
|
|
|
|
assertTrue(descriptor.exports().isEmpty());
|
|
assertTrue(descriptor.opens().isEmpty());
|
|
}
|
|
|
|
/**
|
|
* Test class files in JAR file where the entry does not correspond to a
|
|
* legal package name.
|
|
*/
|
|
@Test
|
|
public void testBadPackage() throws IOException {
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("m.jar"), "p/C1.class", "p-/C2.class");
|
|
|
|
ModuleFinder finder = ModuleFinder.of(dir);
|
|
Optional<ModuleReference> mref = finder.find("m");
|
|
assertTrue(mref.isPresent(), "m not found");
|
|
|
|
ModuleDescriptor descriptor = mref.get().descriptor();
|
|
assertTrue(descriptor.isAutomatic());
|
|
|
|
assertTrue(descriptor.packages().size() == 1);
|
|
assertTrue(descriptor.packages().contains("p"));
|
|
|
|
assertTrue(descriptor.exports().isEmpty());
|
|
assertTrue(descriptor.opens().isEmpty());
|
|
}
|
|
|
|
/**
|
|
* Test non-class resources in a JAR file.
|
|
*/
|
|
@Test
|
|
public void testNonClassResources() throws IOException {
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("m.jar"),
|
|
"LICENSE",
|
|
"README",
|
|
"WEB-INF/tags",
|
|
"p/Type.class",
|
|
"p/resources/m.properties");
|
|
|
|
ModuleFinder finder = ModuleFinder.of(dir);
|
|
Optional<ModuleReference> mref = finder.find("m");
|
|
assertTrue(mref.isPresent(), "m not found");
|
|
|
|
ModuleDescriptor descriptor = mref.get().descriptor();
|
|
assertTrue(descriptor.isAutomatic());
|
|
|
|
assertTrue(descriptor.packages().size() == 1);
|
|
assertTrue(descriptor.packages().contains("p"));
|
|
}
|
|
|
|
/**
|
|
* Test .class file in unnamed package (top-level directory)
|
|
*/
|
|
@Test
|
|
public void testClassInUnnamedPackage() throws IOException {
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("m.jar"), "Mojo.class");
|
|
var finder = ModuleFinder.of(dir);
|
|
assertThrows(FindException.class, finder::findAll);
|
|
}
|
|
|
|
/**
|
|
* Test JAR file with META-INF/services configuration file
|
|
*/
|
|
@Test
|
|
public void testServicesConfiguration() throws IOException {
|
|
String service = "p.S";
|
|
String provider = "p.S1";
|
|
|
|
Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");
|
|
|
|
// provider class
|
|
Path providerClass = tmpdir.resolve(provider.replace('.', '/') + ".class");
|
|
Files.createDirectories(providerClass.getParent());
|
|
Files.createFile(providerClass);
|
|
|
|
// services configuration file
|
|
Path services = tmpdir.resolve("META-INF").resolve("services");
|
|
Files.createDirectories(services);
|
|
Files.write(services.resolve(service), Set.of(provider));
|
|
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir);
|
|
|
|
ModuleFinder finder = ModuleFinder.of(dir);
|
|
|
|
Optional<ModuleReference> mref = finder.find("m");
|
|
assertTrue(mref.isPresent(), "m not found");
|
|
|
|
ModuleDescriptor descriptor = mref.get().descriptor();
|
|
assertTrue(descriptor.provides().size() == 1);
|
|
ModuleDescriptor.Provides provides = descriptor.provides().iterator().next();
|
|
assertEquals(service, provides.service());
|
|
assertTrue(provides.providers().size() == 1);
|
|
assertTrue(provides.providers().contains((provider)));
|
|
}
|
|
|
|
// META-INF/services files that don't map to legal service names
|
|
static Stream<Arguments> badServices() {
|
|
return Stream.of(
|
|
arguments( "-", "p.S1" ),
|
|
arguments( ".S", "p.S1" )
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test JAR file with META-INF/services configuration file with bad
|
|
* values or names.
|
|
*/
|
|
@ParameterizedTest
|
|
@MethodSource("badServices")
|
|
public void testBadServicesNames(String service, String provider)
|
|
throws IOException
|
|
{
|
|
Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");
|
|
Path services = tmpdir.resolve("META-INF").resolve("services");
|
|
Files.createDirectories(services);
|
|
Files.write(services.resolve(service), Set.of(provider));
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir);
|
|
|
|
Optional<ModuleReference> omref = ModuleFinder.of(dir).find("m");
|
|
assertTrue(omref.isPresent());
|
|
ModuleDescriptor descriptor = omref.get().descriptor();
|
|
assertTrue(descriptor.provides().isEmpty());
|
|
}
|
|
|
|
// META-INF/services configuration file entries that are not legal
|
|
static Stream<Arguments> badProviders() {
|
|
return Stream.of(
|
|
arguments("p.S", "-"),
|
|
arguments("p.S", "p..S1"),
|
|
arguments("p.S", "S1.")
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test JAR file with META-INF/services configuration file with bad
|
|
* values or names.
|
|
*/
|
|
@ParameterizedTest
|
|
@MethodSource("badProviders")
|
|
public void testBadProviderNames(String service, String provider)
|
|
throws IOException
|
|
{
|
|
Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");
|
|
|
|
// provider class
|
|
Path providerClass = tmpdir.resolve(provider.replace('.', '/') + ".class");
|
|
Files.createDirectories(providerClass.getParent());
|
|
Files.createFile(providerClass);
|
|
|
|
// services configuration file
|
|
Path services = tmpdir.resolve("META-INF").resolve("services");
|
|
Files.createDirectories(services);
|
|
Files.write(services.resolve(service), Set.of(provider));
|
|
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir);
|
|
|
|
// should throw FindException
|
|
var finder = ModuleFinder.of(dir);
|
|
assertThrows(FindException.class, finder::findAll);
|
|
}
|
|
|
|
/**
|
|
* Test JAR file with META-INF/services configuration file listing a
|
|
* provider that is not in the module.
|
|
*/
|
|
@Test
|
|
public void testMissingProviderPackage() throws IOException {
|
|
Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");
|
|
|
|
// services configuration file
|
|
Path services = tmpdir.resolve("META-INF").resolve("services");
|
|
Files.createDirectories(services);
|
|
Files.write(services.resolve("p.S"), Set.of("q.P"));
|
|
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
Path jarfile = dir.resolve("m.jar");
|
|
JarUtils.createJarFile(jarfile, tmpdir);
|
|
|
|
// FindException should be thrown with InvalidModuleDescriptorException as cause
|
|
var finder = ModuleFinder.of(dir);
|
|
FindException ex = assertThrows(FindException.class, () -> finder.findAll());
|
|
Throwable cause = ex.getCause();
|
|
assertTrue(cause instanceof InvalidModuleDescriptorException);
|
|
var imde = (InvalidModuleDescriptorException) cause;
|
|
assertEquals("Provider class q.P not in JAR file " + jarfile.getFileName(), imde.getMessage());
|
|
}
|
|
|
|
/**
|
|
* Test that a JAR file with a Main-Class attribute results
|
|
* in a module with a main class.
|
|
*/
|
|
@Test
|
|
public void testMainClass() throws IOException {
|
|
String mainClass = "p.Main";
|
|
|
|
Manifest man = new Manifest();
|
|
Attributes attrs = man.getMainAttributes();
|
|
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
|
|
attrs.put(Attributes.Name.MAIN_CLASS, mainClass);
|
|
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
String entry = mainClass.replace('.', '/') + ".class";
|
|
createDummyJarFile(dir.resolve("m.jar"), man, entry);
|
|
|
|
ModuleFinder finder = ModuleFinder.of(dir);
|
|
|
|
Configuration parent = ModuleLayer.boot().configuration();
|
|
Configuration cf = resolve(parent, finder, "m");
|
|
|
|
ModuleDescriptor descriptor = findDescriptor(cf, "m");
|
|
assertEquals(mainClass, descriptor.mainClass().get());
|
|
}
|
|
|
|
// Main-Class attribute values that do not map to a legal qualified type name
|
|
static Stream<String> badMainClasses() {
|
|
return Stream.of(
|
|
"p..Main",
|
|
"p-.Main"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test that a JAR file with a Main-Class attribute that is not a qualified
|
|
* type name.
|
|
*/
|
|
@ParameterizedTest
|
|
@MethodSource("badMainClasses")
|
|
public void testBadMainClass(String mainClass) throws IOException {
|
|
Manifest man = new Manifest();
|
|
Attributes attrs = man.getMainAttributes();
|
|
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
|
|
attrs.put(Attributes.Name.MAIN_CLASS, mainClass);
|
|
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
String entry = mainClass.replace('.', '/') + ".class";
|
|
createDummyJarFile(dir.resolve("m.jar"), man, entry);
|
|
|
|
// bad Main-Class value should be ignored
|
|
Optional<ModuleReference> omref = ModuleFinder.of(dir).find("m");
|
|
assertTrue(omref.isPresent());
|
|
ModuleDescriptor descriptor = omref.get().descriptor();
|
|
assertFalse(descriptor.mainClass().isPresent());
|
|
}
|
|
|
|
/**
|
|
* Test that a JAR file with a Main-Class attribute that is not in the module
|
|
*/
|
|
@Test
|
|
public void testMissingMainClassPackage() throws IOException {
|
|
Manifest man = new Manifest();
|
|
Attributes attrs = man.getMainAttributes();
|
|
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
|
|
attrs.put(Attributes.Name.MAIN_CLASS, "p.Main");
|
|
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("m.jar"), man);
|
|
|
|
// Main-Class should be ignored because package p is not in module
|
|
Optional<ModuleReference> omref = ModuleFinder.of(dir).find("m");
|
|
assertTrue(omref.isPresent());
|
|
ModuleDescriptor descriptor = omref.get().descriptor();
|
|
assertFalse(descriptor.mainClass().isPresent());
|
|
}
|
|
|
|
/**
|
|
* Basic test of a configuration created with automatic modules.
|
|
* a requires b*
|
|
* a requires c*
|
|
* b*
|
|
* c*
|
|
*/
|
|
@Test
|
|
public void testConfiguration1() throws Exception {
|
|
ModuleDescriptor descriptor1
|
|
= ModuleDescriptor.newModule("a")
|
|
.requires("b")
|
|
.requires("c")
|
|
.requires("java.base")
|
|
.build();
|
|
|
|
// b and c are automatic modules
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("b.jar"), "p/T.class");
|
|
createDummyJarFile(dir.resolve("c.jar"), "q/T.class");
|
|
|
|
// module finder locates a and the modules in the directory
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
|
|
ModuleFinder finder2 = ModuleFinder.of(dir);
|
|
ModuleFinder finder = ModuleFinder.compose(finder1, finder2);
|
|
|
|
Configuration parent = ModuleLayer.boot().configuration();
|
|
Configuration cf = resolve(parent, finder, "a");
|
|
|
|
assertTrue(cf.modules().size() == 3);
|
|
assertTrue(cf.findModule("a").isPresent());
|
|
assertTrue(cf.findModule("b").isPresent());
|
|
assertTrue(cf.findModule("c").isPresent());
|
|
|
|
ResolvedModule base = cf.findModule("java.base").get();
|
|
assertTrue(base.configuration() == ModuleLayer.boot().configuration());
|
|
ResolvedModule a = cf.findModule("a").get();
|
|
ResolvedModule b = cf.findModule("b").get();
|
|
ResolvedModule c = cf.findModule("c").get();
|
|
|
|
// b && c only require java.base
|
|
assertTrue(b.reference().descriptor().requires().size() == 1);
|
|
assertTrue(c.reference().descriptor().requires().size() == 1);
|
|
|
|
// readability
|
|
|
|
assertTrue(a.reads().size() == 3);
|
|
assertTrue(a.reads().contains(base));
|
|
assertTrue(a.reads().contains(b));
|
|
assertTrue(a.reads().contains(c));
|
|
|
|
assertTrue(b.reads().contains(a));
|
|
assertFalse(b.reads().contains(b));
|
|
assertTrue(b.reads().contains(c));
|
|
testReadAllBootModules(cf, "b"); // b reads all modules in boot layer
|
|
|
|
assertTrue(c.reads().contains(a));
|
|
assertTrue(c.reads().contains(b));
|
|
assertFalse(c.reads().contains(c));
|
|
testReadAllBootModules(cf, "c"); // c reads all modules in boot layer
|
|
}
|
|
|
|
/**
|
|
* Basic test of a configuration created with automatic modules
|
|
* a requires b
|
|
* b requires c*
|
|
* c*
|
|
* d*
|
|
*/
|
|
@Test
|
|
public void testInConfiguration2() throws IOException {
|
|
ModuleDescriptor descriptor1
|
|
= ModuleDescriptor.newModule("a")
|
|
.requires("b")
|
|
.requires("java.base")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2
|
|
= ModuleDescriptor.newModule("b")
|
|
.requires("c")
|
|
.requires("java.base")
|
|
.build();
|
|
|
|
// c and d are automatic modules
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("c.jar"), "p/T.class");
|
|
createDummyJarFile(dir.resolve("d.jar"), "q/T.class");
|
|
|
|
// module finder locates a and the modules in the directory
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
ModuleFinder finder2 = ModuleFinder.of(dir);
|
|
ModuleFinder finder = ModuleFinder.compose(finder1, finder2);
|
|
|
|
Configuration parent = ModuleLayer.boot().configuration();
|
|
Configuration cf = resolve(parent, finder, "a", "d");
|
|
|
|
assertTrue(cf.modules().size() == 4);
|
|
assertTrue(cf.findModule("a").isPresent());
|
|
assertTrue(cf.findModule("b").isPresent());
|
|
assertTrue(cf.findModule("c").isPresent());
|
|
assertTrue(cf.findModule("d").isPresent());
|
|
|
|
// c && d should only require java.base
|
|
assertTrue(findDescriptor(cf, "c").requires().size() == 1);
|
|
assertTrue(findDescriptor(cf, "d").requires().size() == 1);
|
|
|
|
// readability
|
|
|
|
ResolvedModule base = cf.findModule("java.base").get();
|
|
assertTrue(base.configuration() == ModuleLayer.boot().configuration());
|
|
ResolvedModule a = cf.findModule("a").get();
|
|
ResolvedModule b = cf.findModule("b").get();
|
|
ResolvedModule c = cf.findModule("c").get();
|
|
ResolvedModule d = cf.findModule("d").get();
|
|
|
|
assertTrue(a.reads().size() == 2);
|
|
assertTrue(a.reads().contains(b));
|
|
assertTrue(a.reads().contains(base));
|
|
|
|
assertTrue(b.reads().size() == 3);
|
|
assertTrue(b.reads().contains(c));
|
|
assertTrue(b.reads().contains(d));
|
|
assertTrue(b.reads().contains(base));
|
|
|
|
assertTrue(c.reads().contains(a));
|
|
assertTrue(c.reads().contains(b));
|
|
assertFalse(c.reads().contains(c));
|
|
assertTrue(c.reads().contains(d));
|
|
testReadAllBootModules(cf, "c"); // c reads all modules in boot layer
|
|
|
|
assertTrue(d.reads().contains(a));
|
|
assertTrue(d.reads().contains(b));
|
|
assertTrue(d.reads().contains(c));
|
|
assertFalse(d.reads().contains(d));
|
|
testReadAllBootModules(cf, "d"); // d reads all modules in boot layer
|
|
}
|
|
|
|
/**
|
|
* Basic test of a configuration created with automatic modules
|
|
* a requires b
|
|
* b requires transitive c*
|
|
* c*
|
|
* d*
|
|
*/
|
|
@Test
|
|
public void testInConfiguration3() throws IOException {
|
|
ModuleDescriptor descriptor1
|
|
= ModuleDescriptor.newModule("a")
|
|
.requires("b")
|
|
.requires("java.base")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2
|
|
= ModuleDescriptor.newModule("b")
|
|
.requires(Set.of(Modifier.TRANSITIVE), "c")
|
|
.requires("java.base")
|
|
.build();
|
|
|
|
// c and d are automatic modules
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("c.jar"), "p/T.class");
|
|
createDummyJarFile(dir.resolve("d.jar"), "q/T.class");
|
|
|
|
// module finder locates a and the modules in the directory
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
ModuleFinder finder2 = ModuleFinder.of(dir);
|
|
ModuleFinder finder = ModuleFinder.compose(finder1, finder2);
|
|
|
|
Configuration parent = ModuleLayer.boot().configuration();
|
|
Configuration cf = resolve(parent, finder, "a", "d");
|
|
|
|
assertTrue(cf.modules().size() == 4);
|
|
assertTrue(cf.findModule("a").isPresent());
|
|
assertTrue(cf.findModule("b").isPresent());
|
|
assertTrue(cf.findModule("c").isPresent());
|
|
assertTrue(cf.findModule("d").isPresent());
|
|
|
|
ResolvedModule base = cf.findModule("java.base").get();
|
|
assertTrue(base.configuration() == ModuleLayer.boot().configuration());
|
|
ResolvedModule a = cf.findModule("a").get();
|
|
ResolvedModule b = cf.findModule("b").get();
|
|
ResolvedModule c = cf.findModule("c").get();
|
|
ResolvedModule d = cf.findModule("d").get();
|
|
|
|
// c && d should only require java.base
|
|
assertTrue(findDescriptor(cf, "c").requires().size() == 1);
|
|
assertTrue(findDescriptor(cf, "d").requires().size() == 1);
|
|
|
|
// readability
|
|
|
|
assertTrue(a.reads().size() == 4);
|
|
assertTrue(a.reads().contains(b));
|
|
assertTrue(a.reads().contains(c));
|
|
assertTrue(a.reads().contains(d));
|
|
assertTrue(a.reads().contains(base));
|
|
|
|
assertTrue(b.reads().size() == 3);
|
|
assertTrue(b.reads().contains(c));
|
|
assertTrue(b.reads().contains(d));
|
|
assertTrue(b.reads().contains(base));
|
|
|
|
assertTrue(c.reads().contains(a));
|
|
assertTrue(c.reads().contains(b));
|
|
assertFalse(c.reads().contains(c));
|
|
assertTrue(c.reads().contains(d));
|
|
testReadAllBootModules(cf, "c"); // c reads all modules in boot layer
|
|
|
|
assertTrue(d.reads().contains(a));
|
|
assertTrue(d.reads().contains(b));
|
|
assertTrue(d.reads().contains(c));
|
|
assertFalse(d.reads().contains(d));
|
|
testReadAllBootModules(cf, "d"); // d reads all modules in boot layer
|
|
}
|
|
|
|
/**
|
|
* Basic test to ensure that no automatic modules are resolved when
|
|
* an automatic module is not a root or required by other modules.
|
|
*/
|
|
@Test
|
|
public void testInConfiguration4() throws IOException {
|
|
ModuleDescriptor descriptor1
|
|
= ModuleDescriptor.newModule("m1")
|
|
.requires("java.base")
|
|
.build();
|
|
|
|
// automatic modules
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class");
|
|
createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class");
|
|
createDummyJarFile(dir.resolve("auto3.jar"), "p3/C.class");
|
|
|
|
// module finder locates m1 and the modules in the directory
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
|
|
ModuleFinder finder2 = ModuleFinder.of(dir);
|
|
ModuleFinder finder = ModuleFinder.compose(finder1, finder2);
|
|
|
|
Configuration parent = ModuleLayer.boot().configuration();
|
|
Configuration cf = resolve(parent, finder, "m1");
|
|
|
|
// ensure that no automatic module is resolved
|
|
assertTrue(cf.modules().size() == 1);
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
}
|
|
|
|
/**
|
|
* Basic test to ensure that if an automatic module is resolved then
|
|
* all observable automatic modules are resolved.
|
|
*/
|
|
@Test
|
|
public void testInConfiguration5() throws IOException {
|
|
// m1 requires m2
|
|
ModuleDescriptor descriptor1
|
|
= ModuleDescriptor.newModule("m1")
|
|
.requires("m2").build();
|
|
|
|
// m2 requires automatic module
|
|
ModuleDescriptor descriptor2
|
|
= ModuleDescriptor.newModule("m2")
|
|
.requires("auto1")
|
|
.build();
|
|
|
|
// automatic modules
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class");
|
|
createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class");
|
|
createDummyJarFile(dir.resolve("auto3.jar"), "p3/C.class");
|
|
|
|
// module finder locates m1, m2, and the modules in the directory
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
ModuleFinder finder2 = ModuleFinder.of(dir);
|
|
ModuleFinder finder = ModuleFinder.compose(finder1, finder2);
|
|
|
|
Configuration parent = ModuleLayer.boot().configuration();
|
|
Configuration cf = resolve(parent, finder, "m1");
|
|
|
|
// all automatic modules should be resolved
|
|
assertTrue(cf.modules().size() == 5);
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
assertTrue(cf.findModule("m2").isPresent());
|
|
assertTrue(cf.findModule("auto1").isPresent());
|
|
assertTrue(cf.findModule("auto2").isPresent());
|
|
assertTrue(cf.findModule("auto3").isPresent());
|
|
|
|
ResolvedModule base = parent.findModule("java.base")
|
|
.orElseThrow(() -> new RuntimeException());
|
|
ResolvedModule m1 = cf.findModule("m1").get();
|
|
ResolvedModule m2 = cf.findModule("m2").get();
|
|
ResolvedModule auto1 = cf.findModule("auto1").get();
|
|
ResolvedModule auto2 = cf.findModule("auto2").get();
|
|
ResolvedModule auto3 = cf.findModule("auto3").get();
|
|
|
|
// m1 does not read the automatic modules
|
|
assertTrue(m1.reads().size() == 2);
|
|
assertTrue(m1.reads().contains(m2));
|
|
assertTrue(m1.reads().contains(base));
|
|
|
|
// m2 should read all the automatic modules
|
|
assertTrue(m2.reads().size() == 4);
|
|
assertTrue(m2.reads().contains(auto1));
|
|
assertTrue(m2.reads().contains(auto2));
|
|
assertTrue(m2.reads().contains(auto3));
|
|
assertTrue(m2.reads().contains(base));
|
|
|
|
assertTrue(auto1.reads().contains(m1));
|
|
assertTrue(auto1.reads().contains(m2));
|
|
assertFalse(auto1.reads().contains(auto1));
|
|
assertTrue(auto1.reads().contains(auto2));
|
|
assertTrue(auto1.reads().contains(auto3));
|
|
assertTrue(auto1.reads().contains(base));
|
|
|
|
assertTrue(auto2.reads().contains(m1));
|
|
assertTrue(auto2.reads().contains(m2));
|
|
assertTrue(auto2.reads().contains(auto1));
|
|
assertFalse(auto2.reads().contains(auto2));
|
|
assertTrue(auto2.reads().contains(auto3));
|
|
assertTrue(auto2.reads().contains(base));
|
|
|
|
assertTrue(auto3.reads().contains(m1));
|
|
assertTrue(auto3.reads().contains(m2));
|
|
assertTrue(auto3.reads().contains(auto1));
|
|
assertTrue(auto3.reads().contains(auto2));
|
|
assertFalse(auto3.reads().contains(auto3));
|
|
assertTrue(auto3.reads().contains(base));
|
|
}
|
|
|
|
/**
|
|
* Basic test of automatic modules in a child configuration. All automatic
|
|
* modules that are found with the before finder should be resolved. The
|
|
* automatic modules that are found by the after finder and not shadowed
|
|
* by the before finder, or parent configurations, should also be resolved.
|
|
*/
|
|
@Test
|
|
public void testInConfiguration6() throws IOException {
|
|
// m1 requires auto1
|
|
ModuleDescriptor descriptor1
|
|
= ModuleDescriptor.newModule("m1")
|
|
.requires("auto1")
|
|
.build();
|
|
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class");
|
|
|
|
// module finder locates m1 and auto1
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
|
|
ModuleFinder finder2 = ModuleFinder.of(dir);
|
|
ModuleFinder finder = ModuleFinder.compose(finder1, finder2);
|
|
|
|
Configuration parent = ModuleLayer.boot().configuration();
|
|
Configuration cf1 = resolve(parent, finder, "m1");
|
|
|
|
assertTrue(cf1.modules().size() == 2);
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
assertTrue(cf1.findModule("auto1").isPresent());
|
|
|
|
ResolvedModule base = parent.findModule("java.base")
|
|
.orElseThrow(() -> new RuntimeException());
|
|
ResolvedModule m1 = cf1.findModule("m1").get();
|
|
ResolvedModule auto1 = cf1.findModule("auto1").get();
|
|
|
|
assertTrue(m1.reads().size() == 2);
|
|
assertTrue(m1.reads().contains(auto1));
|
|
assertTrue(m1.reads().contains(base));
|
|
|
|
assertTrue(auto1.reads().contains(m1));
|
|
assertTrue(auto1.reads().contains(base));
|
|
|
|
|
|
// create child configuration - the after finder locates auto1
|
|
|
|
dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class");
|
|
ModuleFinder beforeFinder = ModuleFinder.of(dir);
|
|
|
|
dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class");
|
|
createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class");
|
|
createDummyJarFile(dir.resolve("auto3.jar"), "p3/C.class");
|
|
ModuleFinder afterFinder = ModuleFinder.of(dir);
|
|
|
|
Configuration cf2 = cf1.resolve(beforeFinder, afterFinder, Set.of("auto2"));
|
|
|
|
// auto1 should be found in parent and should not be in cf2
|
|
assertTrue(cf2.modules().size() == 2);
|
|
assertTrue(cf2.findModule("auto2").isPresent());
|
|
assertTrue(cf2.findModule("auto3").isPresent());
|
|
|
|
ResolvedModule auto2 = cf2.findModule("auto2").get();
|
|
ResolvedModule auto3 = cf2.findModule("auto3").get();
|
|
|
|
assertTrue(auto2.reads().contains(m1));
|
|
assertTrue(auto2.reads().contains(auto1));
|
|
assertFalse(auto2.reads().contains(auto2));
|
|
assertTrue(auto2.reads().contains(auto3));
|
|
assertTrue(auto2.reads().contains(base));
|
|
|
|
assertTrue(auto3.reads().contains(m1));
|
|
assertTrue(auto3.reads().contains(auto1));
|
|
assertTrue(auto3.reads().contains(auto2));
|
|
assertFalse(auto3.reads().contains(auto3));
|
|
assertTrue(auto3.reads().contains(base));
|
|
}
|
|
|
|
/**
|
|
* Basic test for a module requiring an automatic module in a parent
|
|
* configuration. If an explicit module in a child configuration reads an
|
|
* automatic module in a parent configuration then it should read all
|
|
* automatic modules in the parent configuration.
|
|
*/
|
|
@Test
|
|
public void testInConfiguration7() throws Exception {
|
|
// m1 requires auto1
|
|
ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1")
|
|
.requires("auto1")
|
|
.build();
|
|
|
|
Path dir1 = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir1.resolve("auto1.jar"), "p1/C.class");
|
|
createDummyJarFile(dir1.resolve("auto2.jar"), "p2/C.class");
|
|
|
|
// module finder locates m1, auto1, and auto2
|
|
ModuleFinder finder1 = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1),
|
|
ModuleFinder.of(dir1));
|
|
|
|
Configuration parent = ModuleLayer.boot().configuration();
|
|
ResolvedModule base = parent.findModule("java.base").orElseThrow();
|
|
|
|
Configuration cf1 = resolve(parent, finder1, "m1");
|
|
assertTrue(cf1.modules().size() == 3);
|
|
|
|
ResolvedModule m1 = cf1.findModule("m1").orElseThrow();
|
|
ResolvedModule auto1 = cf1.findModule("auto1").orElseThrow();
|
|
ResolvedModule auto2 = cf1.findModule("auto2").orElseThrow();
|
|
|
|
assertTrue(m1.reads().size() == 3);
|
|
assertTrue(m1.reads().contains(base));
|
|
assertTrue(m1.reads().contains(auto1));
|
|
assertTrue(m1.reads().contains(auto2));
|
|
|
|
assertTrue(auto1.reads().contains(base));
|
|
assertTrue(auto1.reads().contains(m1));
|
|
assertFalse(auto1.reads().contains(auto1));
|
|
assertTrue(auto1.reads().contains(auto2));
|
|
|
|
assertTrue(auto2.reads().contains(base));
|
|
assertTrue(auto2.reads().contains(m1));
|
|
assertTrue(auto2.reads().contains(auto1));
|
|
assertFalse(auto2.reads().contains(auto2));
|
|
|
|
// m2 requires auto1
|
|
ModuleDescriptor descriptor2 = ModuleDescriptor.newModule("m2")
|
|
.requires("auto1")
|
|
.build();
|
|
|
|
Path dir2 = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir1.resolve("auto3.jar"), "p3/C.class");
|
|
|
|
// module finder locates m2 and auto3
|
|
ModuleFinder finder2 = ModuleFinder.compose(ModuleUtils.finderOf(descriptor2),
|
|
ModuleFinder.of(dir2));
|
|
|
|
Configuration cf2 = resolve(cf1, finder2, "m2");
|
|
assertTrue(cf2.modules().size() == 1); // auto3 should not be resolved
|
|
|
|
ResolvedModule m2 = cf2.findModule("m2").orElseThrow();
|
|
|
|
assertTrue(m2.reads().size() == 3);
|
|
assertTrue(m2.reads().contains(base));
|
|
assertTrue(m2.reads().contains(auto1));
|
|
assertTrue(m2.reads().contains(auto2));
|
|
}
|
|
|
|
/**
|
|
* Basic test of a configuration created with automatic modules
|
|
* a requires b* and c*
|
|
* b* contains p
|
|
* c* contains p
|
|
*/
|
|
@Test
|
|
public void testDuplicateSuppliers1() throws IOException {
|
|
ModuleDescriptor descriptor
|
|
= ModuleDescriptor.newModule("a")
|
|
.requires("b")
|
|
.requires("c")
|
|
.build();
|
|
|
|
// c and d are automatic modules with the same package
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("b.jar"), "p/T.class");
|
|
createDummyJarFile(dir.resolve("c.jar"), "p/T.class");
|
|
|
|
// module finder locates 'a' and the modules in the directory
|
|
ModuleFinder finder
|
|
= ModuleFinder.compose(ModuleUtils.finderOf(descriptor),
|
|
ModuleFinder.of(dir));
|
|
|
|
Configuration parent = ModuleLayer.boot().configuration();
|
|
assertThrows(ResolutionException.class, () -> resolve(parent, finder, "a"));
|
|
}
|
|
|
|
/**
|
|
* Basic test of a configuration created with automatic modules
|
|
* a contains p, requires b*
|
|
* b* contains p
|
|
*/
|
|
@Test
|
|
public void testDuplicateSuppliers2() throws IOException {
|
|
ModuleDescriptor descriptor
|
|
= ModuleDescriptor.newModule("a")
|
|
.packages(Set.of("p"))
|
|
.requires("b")
|
|
.build();
|
|
|
|
// c and d are automatic modules with the same package
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("b.jar"), "p/T.class");
|
|
|
|
// module finder locates 'a' and the modules in the directory
|
|
ModuleFinder finder
|
|
= ModuleFinder.compose(ModuleUtils.finderOf(descriptor),
|
|
ModuleFinder.of(dir));
|
|
|
|
Configuration parent = ModuleLayer.boot().configuration();
|
|
assertThrows(ResolutionException.class, () -> resolve(parent, finder, "a"));
|
|
}
|
|
|
|
/**
|
|
* Basic test of layer containing automatic modules
|
|
*/
|
|
@Test
|
|
public void testInLayer() throws IOException {
|
|
ModuleDescriptor descriptor
|
|
= ModuleDescriptor.newModule("a")
|
|
.requires("b")
|
|
.requires("c")
|
|
.build();
|
|
|
|
// b and c are simple JAR files
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
createDummyJarFile(dir.resolve("b.jar"), "p/T.class");
|
|
createDummyJarFile(dir.resolve("c.jar"), "q/T2.class");
|
|
|
|
// module finder locates a and the modules in the directory
|
|
ModuleFinder finder
|
|
= ModuleFinder.compose(ModuleUtils.finderOf(descriptor),
|
|
ModuleFinder.of(dir));
|
|
|
|
Configuration parent = ModuleLayer.boot().configuration();
|
|
Configuration cf = resolve(parent, finder, "a");
|
|
assertTrue(cf.modules().size() == 3);
|
|
|
|
// each module gets its own loader
|
|
ModuleLayer layer = ModuleLayer.boot().defineModules(cf, mn -> new ClassLoader() { });
|
|
|
|
// an unnamed module
|
|
Module unnamed = (new ClassLoader() { }).getUnnamedModule();
|
|
|
|
Module b = layer.findModule("b").get();
|
|
assertTrue(b.isNamed());
|
|
assertTrue(b.canRead(unnamed));
|
|
testsReadsAll(b, layer);
|
|
|
|
Module c = layer.findModule("c").get();
|
|
assertTrue(c.isNamed());
|
|
assertTrue(b.canRead(unnamed));
|
|
testsReadsAll(c, layer);
|
|
}
|
|
|
|
/**
|
|
* Test miscellaneous methods.
|
|
*/
|
|
@Test
|
|
public void testMisc() throws IOException {
|
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
|
Path m_jar = createDummyJarFile(dir.resolve("m.jar"), "p/T.class");
|
|
|
|
ModuleFinder finder = ModuleFinder.of(m_jar);
|
|
|
|
assertTrue(finder.find("m").isPresent());
|
|
ModuleDescriptor m = finder.find("m").get().descriptor();
|
|
|
|
// test miscellaneous methods
|
|
assertTrue(m.isAutomatic());
|
|
assertFalse(m.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC));
|
|
}
|
|
|
|
/**
|
|
* Invokes parent.resolve to resolve the given root modules.
|
|
*/
|
|
static Configuration resolve(Configuration parent,
|
|
ModuleFinder finder,
|
|
String... roots) {
|
|
return parent.resolve(finder, ModuleFinder.of(), Set.of(roots));
|
|
}
|
|
|
|
/**
|
|
* Finds a module in the given configuration or its parents, returning
|
|
* the module descriptor (or null if not found)
|
|
*/
|
|
static ModuleDescriptor findDescriptor(Configuration cf, String name) {
|
|
Optional<ResolvedModule> om = cf.findModule(name);
|
|
if (om.isPresent()) {
|
|
return om.get().reference().descriptor();
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test that a module in a configuration reads all modules in the boot
|
|
* configuration.
|
|
*/
|
|
static void testReadAllBootModules(Configuration cf, String mn) {
|
|
Set<String> bootModules = ModuleLayer.boot().modules().stream()
|
|
.map(Module::getName)
|
|
.collect(Collectors.toSet());
|
|
bootModules.forEach(other -> assertTrue(reads(cf, mn, other)));
|
|
}
|
|
|
|
/**
|
|
* Test that the given Module reads all module in the given layer
|
|
* and its parent layers.
|
|
*/
|
|
static void testsReadsAll(Module m, ModuleLayer layer) {
|
|
// check that m reads all modules in the layer
|
|
layer.configuration().modules().stream()
|
|
.map(ResolvedModule::name)
|
|
.map(layer::findModule)
|
|
.map(Optional::get)
|
|
.forEach(other -> assertTrue(m.canRead(other)));
|
|
|
|
// also check parent layers
|
|
layer.parents().forEach(l -> testsReadsAll(m, l));
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if the configuration contains module mn1
|
|
* that reads module mn2.
|
|
*/
|
|
static boolean reads(Configuration cf, String mn1, String mn2) {
|
|
Optional<ResolvedModule> om = cf.findModule(mn1);
|
|
if (!om.isPresent())
|
|
return false;
|
|
|
|
return om.get().reads().stream()
|
|
.map(ResolvedModule::name)
|
|
.anyMatch(mn2::equals);
|
|
}
|
|
|
|
/**
|
|
* Creates a JAR file, optionally with a manifest, and with the given
|
|
* entries. The entries will be empty in the resulting JAR file.
|
|
*/
|
|
static Path createDummyJarFile(Path jarfile, Manifest man, String... entries)
|
|
throws IOException
|
|
{
|
|
Path dir = Files.createTempDirectory(USER_DIR, "tmp");
|
|
|
|
for (String entry : entries) {
|
|
Path file = dir.resolve(entry);
|
|
Path parent = file.getParent();
|
|
if (parent != null)
|
|
Files.createDirectories(parent);
|
|
Files.createFile(file);
|
|
}
|
|
|
|
Path[] paths = Stream.of(entries).map(Path::of).toArray(Path[]::new);
|
|
JarUtils.createJarFile(jarfile, man, dir, paths);
|
|
return jarfile;
|
|
}
|
|
|
|
/**
|
|
* Creates a JAR file and with the given entries. The entries will be empty
|
|
* in the resulting JAR file.
|
|
*/
|
|
static Path createDummyJarFile(Path jarfile, String... entries)
|
|
throws IOException
|
|
{
|
|
return createDummyJarFile(jarfile, null, entries);
|
|
}
|
|
}
|