Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
2292 lines
76 KiB
Java
2292 lines
76 KiB
Java
/*
|
|
* Copyright (c) 2014, 2025, 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 8299504
|
|
* @modules java.base/jdk.internal.access
|
|
* java.base/jdk.internal.module
|
|
* @library /test/lib
|
|
* @build ConfigurationTest
|
|
* jdk.test.lib.util.ModuleInfoWriter
|
|
* jdk.test.lib.util.ModuleUtils
|
|
* @run junit ConfigurationTest
|
|
* @summary Basic tests for java.lang.module.Configuration
|
|
*/
|
|
|
|
import java.io.IOException;
|
|
import java.io.OutputStream;
|
|
import java.lang.module.Configuration;
|
|
import java.lang.module.FindException;
|
|
import java.lang.module.ModuleDescriptor;
|
|
import java.lang.module.ModuleDescriptor.Requires;
|
|
import java.lang.module.ModuleFinder;
|
|
import java.lang.module.ResolutionException;
|
|
import java.lang.module.ResolvedModule;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.nio.file.Paths;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.stream.Stream;
|
|
import jdk.internal.access.SharedSecrets;
|
|
import jdk.internal.module.ModuleTarget;
|
|
|
|
import jdk.test.lib.util.ModuleInfoWriter;
|
|
import jdk.test.lib.util.ModuleUtils;
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
import org.junit.jupiter.params.ParameterizedTest;
|
|
import org.junit.jupiter.params.provider.MethodSource;
|
|
import org.junit.jupiter.params.provider.CsvSource;
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|
|
|
class ConfigurationTest {
|
|
|
|
/**
|
|
* Creates a "non-strict" builder for building a module. This allows the
|
|
* test the create ModuleDescriptor objects that do not require java.base.
|
|
*/
|
|
private static ModuleDescriptor.Builder newBuilder(String mn) {
|
|
return SharedSecrets.getJavaLangModuleAccess()
|
|
.newModuleBuilder(mn, false, Set.of());
|
|
}
|
|
|
|
/**
|
|
* Basic test of resolver
|
|
* m1 requires m2, m2 requires m3
|
|
*/
|
|
@Test
|
|
void testBasic() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires("m2")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires("m3")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.build();
|
|
|
|
ModuleFinder finder
|
|
= ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
|
|
|
|
Configuration cf = resolve(finder, "m1");
|
|
|
|
assertTrue(cf.modules().size() == 3);
|
|
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
assertTrue(cf.findModule("m2").isPresent());
|
|
assertTrue(cf.findModule("m3").isPresent());
|
|
|
|
assertTrue(cf.parents().size() == 1);
|
|
assertTrue(cf.parents().get(0) == Configuration.empty());
|
|
|
|
ResolvedModule m1 = cf.findModule("m1").get();
|
|
ResolvedModule m2 = cf.findModule("m2").get();
|
|
ResolvedModule m3 = cf.findModule("m3").get();
|
|
|
|
// m1 reads m2
|
|
assertTrue(m1.reads().size() == 1);
|
|
assertTrue(m1.reads().contains(m2));
|
|
|
|
// m2 reads m3
|
|
assertTrue(m2.reads().size() == 1);
|
|
assertTrue(m2.reads().contains(m3));
|
|
|
|
// m3 reads nothing
|
|
assertTrue(m3.reads().size() == 0);
|
|
|
|
// toString
|
|
assertTrue(cf.toString().contains("m1"));
|
|
assertTrue(cf.toString().contains("m2"));
|
|
assertTrue(cf.toString().contains("m3"));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of "requires transitive":
|
|
* m1 requires m2, m2 requires transitive m3
|
|
*/
|
|
@Test
|
|
void testRequiresTransitive1() {
|
|
// m1 requires m2, m2 requires transitive m3
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires("m2")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires(Set.of(Requires.Modifier.TRANSITIVE), "m3")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.build();
|
|
|
|
ModuleFinder finder
|
|
= ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
|
|
|
|
Configuration cf = resolve(finder, "m1");
|
|
|
|
assertTrue(cf.modules().size() == 3);
|
|
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
assertTrue(cf.findModule("m2").isPresent());
|
|
assertTrue(cf.findModule("m3").isPresent());
|
|
|
|
assertTrue(cf.parents().size() == 1);
|
|
assertTrue(cf.parents().get(0) == Configuration.empty());
|
|
|
|
ResolvedModule m1 = cf.findModule("m1").get();
|
|
ResolvedModule m2 = cf.findModule("m2").get();
|
|
ResolvedModule m3 = cf.findModule("m3").get();
|
|
|
|
// m1 reads m2 and m3
|
|
assertTrue(m1.reads().size() == 2);
|
|
assertTrue(m1.reads().contains(m2));
|
|
assertTrue(m1.reads().contains(m3));
|
|
|
|
// m2 reads m3
|
|
assertTrue(m2.reads().size() == 1);
|
|
assertTrue(m2.reads().contains(m3));
|
|
|
|
// m3 reads nothing
|
|
assertTrue(m3.reads().size() == 0);
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of "requires transitive" with configurations.
|
|
*
|
|
* The test consists of three configurations:
|
|
* - Configuration cf1: m1, m2 requires transitive m1
|
|
* - Configuration cf2: m3 requires m2
|
|
*/
|
|
@Test
|
|
void testRequiresTransitive2() {
|
|
|
|
// cf1: m1 and m2, m2 requires transitive m1
|
|
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
|
|
.build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
|
|
Configuration cf1 = resolve(finder1, "m2");
|
|
|
|
assertTrue(cf1.modules().size() == 2);
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
assertTrue(cf1.findModule("m2").isPresent());
|
|
assertTrue(cf1.parents().size() == 1);
|
|
assertTrue(cf1.parents().get(0) == Configuration.empty());
|
|
|
|
ResolvedModule m1 = cf1.findModule("m1").get();
|
|
ResolvedModule m2 = cf1.findModule("m2").get();
|
|
|
|
assertTrue(m1.reads().size() == 0);
|
|
assertTrue(m2.reads().size() == 1);
|
|
assertTrue(m2.reads().contains(m1));
|
|
|
|
|
|
// cf2: m3, m3 requires m2
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires("m2")
|
|
.build();
|
|
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
|
|
|
|
Configuration cf2 = resolve(cf1, finder2, "m3");
|
|
|
|
assertTrue(cf2.modules().size() == 1);
|
|
assertTrue(cf2.findModule("m1").isPresent()); // in parent
|
|
assertTrue(cf2.findModule("m2").isPresent()); // in parent
|
|
assertTrue(cf2.findModule("m3").isPresent());
|
|
assertTrue(cf2.parents().size() == 1);
|
|
assertTrue(cf2.parents().get(0) == cf1);
|
|
|
|
ResolvedModule m3 = cf2.findModule("m3").get();
|
|
assertTrue(m3.configuration() == cf2);
|
|
assertTrue(m3.reads().size() == 2);
|
|
assertTrue(m3.reads().contains(m1));
|
|
assertTrue(m3.reads().contains(m2));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of "requires transitive" with configurations.
|
|
*
|
|
* The test consists of three configurations:
|
|
* - Configuration cf1: m1
|
|
* - Configuration cf2: m2 requires transitive m1, m3 requires m2
|
|
*/
|
|
@Test
|
|
void testRequiresTransitive3() {
|
|
|
|
// cf1: m1
|
|
|
|
ModuleDescriptor descriptor1 = newBuilder("m1").build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
|
|
|
|
Configuration cf1 = resolve(finder1, "m1");
|
|
|
|
assertTrue(cf1.modules().size() == 1);
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
assertTrue(cf1.parents().size() == 1);
|
|
assertTrue(cf1.parents().get(0) == Configuration.empty());
|
|
|
|
ResolvedModule m1 = cf1.findModule("m1").get();
|
|
assertTrue(m1.reads().size() == 0);
|
|
|
|
|
|
// cf2: m2, m3: m2 requires transitive m1, m3 requires m2
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires("m2")
|
|
.build();
|
|
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2, descriptor3);
|
|
|
|
Configuration cf2 = resolve(cf1, finder2, "m3");
|
|
|
|
assertTrue(cf2.modules().size() == 2);
|
|
assertTrue(cf2.findModule("m1").isPresent()); // in parent
|
|
assertTrue(cf2.findModule("m2").isPresent());
|
|
assertTrue(cf2.findModule("m3").isPresent());
|
|
assertTrue(cf2.parents().size() == 1);
|
|
assertTrue(cf2.parents().get(0) == cf1);
|
|
|
|
ResolvedModule m2 = cf2.findModule("m2").get();
|
|
ResolvedModule m3 = cf2.findModule("m3").get();
|
|
|
|
assertTrue(m2.configuration() == cf2);
|
|
assertTrue(m2.reads().size() == 1);
|
|
assertTrue(m2.reads().contains(m1));
|
|
|
|
assertTrue(m3.configuration() == cf2);
|
|
assertTrue(m3.reads().size() == 2);
|
|
assertTrue(m3.reads().contains(m1));
|
|
assertTrue(m3.reads().contains(m2));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of "requires transitive" with configurations.
|
|
*
|
|
* The test consists of three configurations:
|
|
* - Configuration cf1: m1
|
|
* - Configuration cf2: m2 requires transitive m1
|
|
* - Configuraiton cf3: m3 requires m2
|
|
*/
|
|
@Test
|
|
void testRequiresTransitive4() {
|
|
|
|
// cf1: m1
|
|
|
|
ModuleDescriptor descriptor1 = newBuilder("m1").build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
|
|
|
|
Configuration cf1 = resolve(finder1, "m1");
|
|
|
|
assertTrue(cf1.modules().size() == 1);
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
assertTrue(cf1.parents().size() == 1);
|
|
assertTrue(cf1.parents().get(0) == Configuration.empty());
|
|
|
|
ResolvedModule m1 = cf1.findModule("m1").get();
|
|
assertTrue(m1.reads().size() == 0);
|
|
|
|
|
|
// cf2: m2 requires transitive m1
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
|
|
.build();
|
|
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
|
|
|
|
Configuration cf2 = resolve(cf1, finder2, "m2");
|
|
|
|
assertTrue(cf2.modules().size() == 1);
|
|
assertTrue(cf2.findModule("m1").isPresent()); // in parent
|
|
assertTrue(cf2.findModule("m2").isPresent());
|
|
assertTrue(cf2.parents().size() == 1);
|
|
assertTrue(cf2.parents().get(0) == cf1);
|
|
|
|
ResolvedModule m2 = cf2.findModule("m2").get();
|
|
|
|
assertTrue(m2.configuration() == cf2);
|
|
assertTrue(m2.reads().size() == 1);
|
|
assertTrue(m2.reads().contains(m1));
|
|
|
|
|
|
// cf3: m3 requires m2
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires("m2")
|
|
.build();
|
|
|
|
ModuleFinder finder3 = ModuleUtils.finderOf(descriptor3);
|
|
|
|
Configuration cf3 = resolve(cf2, finder3, "m3");
|
|
|
|
assertTrue(cf3.modules().size() == 1);
|
|
assertTrue(cf3.findModule("m1").isPresent()); // in parent
|
|
assertTrue(cf3.findModule("m2").isPresent()); // in parent
|
|
assertTrue(cf3.findModule("m3").isPresent());
|
|
assertTrue(cf3.parents().size() == 1);
|
|
assertTrue(cf3.parents().get(0) == cf2);
|
|
|
|
ResolvedModule m3 = cf3.findModule("m3").get();
|
|
|
|
assertTrue(m3.configuration() == cf3);
|
|
assertTrue(m3.reads().size() == 2);
|
|
assertTrue(m3.reads().contains(m1));
|
|
assertTrue(m3.reads().contains(m2));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of "requires transitive" with configurations.
|
|
*
|
|
* The test consists of two configurations:
|
|
* - Configuration cf1: m1, m2 requires transitive m1
|
|
* - Configuration cf2: m3 requires transitive m2, m4 requires m3
|
|
*/
|
|
@Test
|
|
void testRequiresTransitive5() {
|
|
|
|
// cf1: m1, m2 requires transitive m1
|
|
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
|
|
.build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
|
|
Configuration cf1 = resolve(finder1, "m2");
|
|
|
|
assertTrue(cf1.modules().size() == 2);
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
assertTrue(cf1.findModule("m2").isPresent());
|
|
assertTrue(cf1.parents().size() == 1);
|
|
assertTrue(cf1.parents().get(0) == Configuration.empty());
|
|
|
|
ResolvedModule m1 = cf1.findModule("m1").get();
|
|
ResolvedModule m2 = cf1.findModule("m2").get();
|
|
|
|
assertTrue(m1.configuration() == cf1);
|
|
assertTrue(m1.reads().size() == 0);
|
|
|
|
assertTrue(m2.configuration() == cf1);
|
|
assertTrue(m2.reads().size() == 1);
|
|
assertTrue(m2.reads().contains(m1));
|
|
|
|
|
|
// cf2: m3 requires transitive m2, m4 requires m3
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires(Set.of(Requires.Modifier.TRANSITIVE), "m2")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor4 = newBuilder("m4")
|
|
.requires("m3")
|
|
.build();
|
|
|
|
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4);
|
|
|
|
Configuration cf2 = resolve(cf1, finder2, "m3", "m4");
|
|
|
|
assertTrue(cf2.modules().size() == 2);
|
|
assertTrue(cf2.findModule("m1").isPresent()); // in parent
|
|
assertTrue(cf2.findModule("m2").isPresent()); // in parent
|
|
assertTrue(cf2.findModule("m3").isPresent());
|
|
assertTrue(cf2.findModule("m4").isPresent());
|
|
assertTrue(cf2.parents().size() == 1);
|
|
assertTrue(cf2.parents().get(0) == cf1);
|
|
|
|
ResolvedModule m3 = cf2.findModule("m3").get();
|
|
ResolvedModule m4 = cf2.findModule("m4").get();
|
|
|
|
assertTrue(m3.configuration() == cf2);
|
|
assertTrue(m3.reads().size() == 2);
|
|
assertTrue(m3.reads().contains(m1));
|
|
assertTrue(m3.reads().contains(m2));
|
|
|
|
assertTrue(m4.configuration() == cf2);
|
|
assertTrue(m4.reads().size() == 3);
|
|
assertTrue(m4.reads().contains(m1));
|
|
assertTrue(m4.reads().contains(m2));
|
|
assertTrue(m4.reads().contains(m3));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of "requires static":
|
|
* m1 requires static m2
|
|
* m2 is not observable
|
|
* resolve m1
|
|
*/
|
|
@Test
|
|
void testRequiresStatic1() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires(Set.of(Requires.Modifier.STATIC), "m2")
|
|
.build();
|
|
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
|
|
|
|
Configuration cf = resolve(finder, "m1");
|
|
|
|
assertTrue(cf.modules().size() == 1);
|
|
|
|
ResolvedModule m1 = cf.findModule("m1").get();
|
|
assertTrue(m1.reads().size() == 0);
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of "requires static":
|
|
* m1 requires static m2
|
|
* m2
|
|
* resolve m1
|
|
*/
|
|
@Test
|
|
void testRequiresStatic2() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires(Set.of(Requires.Modifier.STATIC), "m2")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.build();
|
|
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
|
|
Configuration cf = resolve(finder, "m1");
|
|
|
|
assertTrue(cf.modules().size() == 1);
|
|
|
|
ResolvedModule m1 = cf.findModule("m1").get();
|
|
assertTrue(m1.reads().size() == 0);
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of "requires static":
|
|
* m1 requires static m2
|
|
* m2
|
|
* resolve m1, m2
|
|
*/
|
|
@Test
|
|
void testRequiresStatic3() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires(Set.of(Requires.Modifier.STATIC), "m2")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.build();
|
|
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
|
|
Configuration cf = resolve(finder, "m1", "m2");
|
|
|
|
assertTrue(cf.modules().size() == 2);
|
|
|
|
ResolvedModule m1 = cf.findModule("m1").get();
|
|
ResolvedModule m2 = cf.findModule("m2").get();
|
|
|
|
assertTrue(m1.reads().size() == 1);
|
|
assertTrue(m1.reads().contains(m2));
|
|
|
|
assertTrue(m2.reads().size() == 0);
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of "requires static":
|
|
* m1 requires m2, m3
|
|
* m2 requires static m2
|
|
* m3
|
|
*/
|
|
@Test
|
|
void testRequiresStatic4() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires("m2")
|
|
.requires("m3")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires(Set.of(Requires.Modifier.STATIC), "m3")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.build();
|
|
|
|
ModuleFinder finder
|
|
= ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
|
|
|
|
Configuration cf = resolve(finder, "m1");
|
|
|
|
assertTrue(cf.modules().size() == 3);
|
|
|
|
ResolvedModule m1 = cf.findModule("m1").get();
|
|
ResolvedModule m2 = cf.findModule("m2").get();
|
|
ResolvedModule m3 = cf.findModule("m3").get();
|
|
|
|
assertTrue(m1.reads().size() == 2);
|
|
assertTrue(m1.reads().contains(m2));
|
|
assertTrue(m1.reads().contains(m3));
|
|
|
|
assertTrue(m2.reads().size() == 1);
|
|
assertTrue(m2.reads().contains(m3));
|
|
|
|
assertTrue(m3.reads().size() == 0);
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of "requires static":
|
|
* The test consists of three configurations:
|
|
* - Configuration cf1: m1, m2
|
|
* - Configuration cf2: m3 requires m1, requires static m2
|
|
*/
|
|
@Test
|
|
void testRequiresStatic5() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
|
|
Configuration cf1 = resolve(finder1, "m1", "m2");
|
|
|
|
assertTrue(cf1.modules().size() == 2);
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
assertTrue(cf1.findModule("m2").isPresent());
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires("m1")
|
|
.requires(Set.of(Requires.Modifier.STATIC), "m2")
|
|
.build();
|
|
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
|
|
|
|
Configuration cf2 = resolve(cf1, finder2, "m3");
|
|
|
|
assertTrue(cf2.modules().size() == 1);
|
|
assertTrue(cf2.findModule("m3").isPresent());
|
|
|
|
ResolvedModule m1 = cf1.findModule("m1").get();
|
|
ResolvedModule m2 = cf1.findModule("m2").get();
|
|
ResolvedModule m3 = cf2.findModule("m3").get();
|
|
|
|
assertTrue(m3.reads().size() == 2);
|
|
assertTrue(m3.reads().contains(m1));
|
|
assertTrue(m3.reads().contains(m2));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of "requires static":
|
|
* The test consists of three configurations:
|
|
* - Configuration cf1: m1
|
|
* - Configuration cf2: m3 requires m1, requires static m2
|
|
*/
|
|
@Test
|
|
void testRequiresStatic6() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
|
|
|
|
Configuration cf1 = resolve(finder1, "m1");
|
|
|
|
assertTrue(cf1.modules().size() == 1);
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires("m1")
|
|
.requires(Set.of(Requires.Modifier.STATIC), "m2")
|
|
.build();
|
|
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
|
|
|
|
Configuration cf2 = resolve(cf1, finder2, "m3");
|
|
|
|
assertTrue(cf2.modules().size() == 1);
|
|
assertTrue(cf2.findModule("m3").isPresent());
|
|
|
|
ResolvedModule m1 = cf1.findModule("m1").get();
|
|
ResolvedModule m3 = cf2.findModule("m3").get();
|
|
|
|
assertTrue(m3.reads().size() == 1);
|
|
assertTrue(m3.reads().contains(m1));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of "requires static":
|
|
* (m1 not observable)
|
|
* m2 requires transitive static m1
|
|
* m3 requires m2
|
|
*/
|
|
@Test
|
|
void testRequiresStatic7() {
|
|
ModuleDescriptor descriptor1 = null; // not observable
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires(Set.of(Requires.Modifier.TRANSITIVE,
|
|
Requires.Modifier.STATIC),
|
|
"m1")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires("m2")
|
|
.build();
|
|
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor2, descriptor3);
|
|
|
|
Configuration cf = resolve(finder, "m3");
|
|
|
|
assertTrue(cf.modules().size() == 2);
|
|
assertTrue(cf.findModule("m2").isPresent());
|
|
assertTrue(cf.findModule("m3").isPresent());
|
|
ResolvedModule m2 = cf.findModule("m2").get();
|
|
ResolvedModule m3 = cf.findModule("m3").get();
|
|
assertTrue(m2.reads().isEmpty());
|
|
assertTrue(m3.reads().size() == 1);
|
|
assertTrue(m3.reads().contains(m2));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of "requires static":
|
|
* - Configuration cf1: m2 requires transitive static m1
|
|
* - Configuration cf2: m3 requires m2
|
|
*/
|
|
@Test
|
|
void testRequiresStatic8() {
|
|
ModuleDescriptor descriptor1 = null; // not observable
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires(Set.of(Requires.Modifier.TRANSITIVE,
|
|
Requires.Modifier.STATIC),
|
|
"m1")
|
|
.build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor2);
|
|
|
|
Configuration cf1 = resolve(finder1, "m2");
|
|
|
|
assertTrue(cf1.modules().size() == 1);
|
|
assertTrue(cf1.findModule("m2").isPresent());
|
|
ResolvedModule m2 = cf1.findModule("m2").get();
|
|
assertTrue(m2.reads().isEmpty());
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires("m2")
|
|
.build();
|
|
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
|
|
|
|
Configuration cf2 = resolve(cf1, finder2, "m3");
|
|
|
|
assertTrue(cf2.modules().size() == 1);
|
|
assertTrue(cf2.findModule("m3").isPresent());
|
|
ResolvedModule m3 = cf2.findModule("m3").get();
|
|
assertTrue(m3.reads().size() == 1);
|
|
assertTrue(m3.reads().contains(m2));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of binding services
|
|
* m1 uses p.S
|
|
* m2 provides p.S
|
|
*/
|
|
@Test
|
|
void testServiceBinding1() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.exports("p")
|
|
.uses("p.S")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires("m1")
|
|
.provides("p.S", List.of("q.T"))
|
|
.build();
|
|
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
|
|
Configuration cf = resolveAndBind(finder, "m1");
|
|
|
|
assertTrue(cf.modules().size() == 2);
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
assertTrue(cf.findModule("m2").isPresent());
|
|
assertTrue(cf.parents().size() == 1);
|
|
assertTrue(cf.parents().get(0) == Configuration.empty());
|
|
|
|
ResolvedModule m1 = cf.findModule("m1").get();
|
|
ResolvedModule m2 = cf.findModule("m2").get();
|
|
|
|
assertTrue(m1.configuration() == cf);
|
|
assertTrue(m1.reads().size() == 0);
|
|
|
|
assertTrue(m2.configuration() == cf);
|
|
assertTrue(m2.reads().size() == 1);
|
|
assertTrue(m2.reads().contains(m1));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of binding services
|
|
* m1 uses p.S1
|
|
* m2 provides p.S1, m2 uses p.S2
|
|
* m3 provides p.S2
|
|
*/
|
|
@Test
|
|
void testServiceBinding2() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.exports("p")
|
|
.uses("p.S1")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires("m1")
|
|
.uses("p.S2")
|
|
.provides("p.S1", List.of("q.Service1Impl"))
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires("m1")
|
|
.provides("p.S2", List.of("q.Service2Impl"))
|
|
.build();
|
|
|
|
ModuleFinder finder
|
|
= ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
|
|
|
|
Configuration cf = resolveAndBind(finder, "m1");
|
|
|
|
assertTrue(cf.modules().size() == 3);
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
assertTrue(cf.findModule("m2").isPresent());
|
|
assertTrue(cf.findModule("m3").isPresent());
|
|
assertTrue(cf.parents().size() == 1);
|
|
assertTrue(cf.parents().get(0) == Configuration.empty());
|
|
|
|
ResolvedModule m1 = cf.findModule("m1").get();
|
|
ResolvedModule m2 = cf.findModule("m2").get();
|
|
ResolvedModule m3 = cf.findModule("m3").get();
|
|
|
|
assertTrue(m1.configuration() == cf);
|
|
assertTrue(m1.reads().size() == 0);
|
|
|
|
assertTrue(m2.configuration() == cf);
|
|
assertTrue(m2.reads().size() == 1);
|
|
assertTrue(m2.reads().contains(m1));
|
|
|
|
assertTrue(m3.configuration() == cf);
|
|
assertTrue(m3.reads().size() == 1);
|
|
assertTrue(m3.reads().contains(m1));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of binding services with configurations.
|
|
*
|
|
* The test consists of two configurations:
|
|
* - Configuration cf1: m1 uses p.S
|
|
* - Configuration cf2: m2 provides p.S
|
|
*/
|
|
@Test
|
|
void testServiceBindingWithConfigurations1() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.exports("p")
|
|
.uses("p.S")
|
|
.build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
|
|
|
|
Configuration cf1 = resolve(finder1, "m1");
|
|
|
|
assertTrue(cf1.modules().size() == 1);
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires("m1")
|
|
.provides("p.S", List.of("q.T"))
|
|
.build();
|
|
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
|
|
|
|
Configuration cf2 = resolveAndBind(cf1, finder2); // no roots
|
|
|
|
assertTrue(cf2.parents().size() == 1);
|
|
assertTrue(cf2.parents().get(0) == cf1);
|
|
|
|
assertTrue(cf2.modules().size() == 1);
|
|
assertTrue(cf2.findModule("m2").isPresent());
|
|
|
|
ResolvedModule m1 = cf1.findModule("m1").get();
|
|
ResolvedModule m2 = cf2.findModule("m2").get();
|
|
|
|
assertTrue(m2.reads().size() == 1);
|
|
assertTrue(m2.reads().contains(m1));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of binding services with configurations.
|
|
*
|
|
* The test consists of two configurations:
|
|
* - Configuration cf1: m1 uses p.S && provides p.S,
|
|
* m2 provides p.S
|
|
* - Configuration cf2: m3 provides p.S
|
|
* m4 provides p.S
|
|
*/
|
|
@Test
|
|
void testServiceBindingWithConfigurations2() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.exports("p")
|
|
.uses("p.S")
|
|
.provides("p.S", List.of("p1.ServiceImpl"))
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires("m1")
|
|
.provides("p.S", List.of("p2.ServiceImpl"))
|
|
.build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
|
|
Configuration cf1 = resolveAndBind(finder1, "m1");
|
|
|
|
assertTrue(cf1.modules().size() == 2);
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
assertTrue(cf1.findModule("m2").isPresent());
|
|
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires("m1")
|
|
.provides("p.S", List.of("p3.ServiceImpl"))
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor4 = newBuilder("m4")
|
|
.requires("m1")
|
|
.provides("p.S", List.of("p4.ServiceImpl"))
|
|
.build();
|
|
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4);
|
|
|
|
Configuration cf2 = resolveAndBind(cf1, finder2); // no roots
|
|
|
|
assertTrue(cf2.parents().size() == 1);
|
|
assertTrue(cf2.parents().get(0) == cf1);
|
|
|
|
assertTrue(cf2.modules().size() == 2);
|
|
assertTrue(cf2.findModule("m3").isPresent());
|
|
assertTrue(cf2.findModule("m4").isPresent());
|
|
|
|
ResolvedModule m1 = cf2.findModule("m1").get(); // should find in parent
|
|
ResolvedModule m2 = cf2.findModule("m2").get();
|
|
ResolvedModule m3 = cf2.findModule("m3").get();
|
|
ResolvedModule m4 = cf2.findModule("m4").get();
|
|
|
|
assertTrue(m1.reads().size() == 0);
|
|
|
|
assertTrue(m2.reads().size() == 1);
|
|
assertTrue(m2.reads().contains(m1));
|
|
|
|
assertTrue(m3.reads().size() == 1);
|
|
assertTrue(m3.reads().contains(m1));
|
|
|
|
assertTrue(m4.reads().size() == 1);
|
|
assertTrue(m4.reads().contains(m1));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of binding services with configurations.
|
|
*
|
|
* Configuration cf1: p@1.0 provides p.S
|
|
* Test configuration cf2: m1 uses p.S, p@2.0 provides p.S
|
|
* Test configuration cf2: m1 uses p.S
|
|
*/
|
|
@Test
|
|
void testServiceBindingWithConfigurations3() {
|
|
ModuleDescriptor service = newBuilder("s")
|
|
.exports("p")
|
|
.build();
|
|
|
|
ModuleDescriptor provider_v1 = newBuilder("p")
|
|
.version("1.0")
|
|
.requires("s")
|
|
.provides("p.S", List.of("q.T"))
|
|
.build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(service, provider_v1);
|
|
|
|
Configuration cf1 = resolve(finder1, "p");
|
|
|
|
assertTrue(cf1.modules().size() == 2);
|
|
assertTrue(cf1.findModule("s").isPresent());
|
|
assertTrue(cf1.findModule("p").isPresent());
|
|
|
|
// p@1.0 in cf1
|
|
ResolvedModule p = cf1.findModule("p").get();
|
|
assertEquals(provider_v1, p.reference().descriptor());
|
|
|
|
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires("s")
|
|
.uses("p.S")
|
|
.build();
|
|
|
|
ModuleDescriptor provider_v2 = newBuilder("p")
|
|
.version("2.0")
|
|
.requires("s")
|
|
.provides("p.S", List.of("q.T"))
|
|
.build();
|
|
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, provider_v2);
|
|
|
|
|
|
// finder2 is the before ModuleFinder and so p@2.0 should be located
|
|
|
|
Configuration cf2 = resolveAndBind(cf1, finder2, "m1");
|
|
|
|
assertTrue(cf2.parents().size() == 1);
|
|
assertTrue(cf2.parents().get(0) == cf1);
|
|
assertTrue(cf2.modules().size() == 2);
|
|
|
|
// p should be found in cf2
|
|
p = cf2.findModule("p").get();
|
|
assertTrue(p.configuration() == cf2);
|
|
assertEquals(provider_v2, p.reference().descriptor());
|
|
|
|
|
|
// finder2 is the after ModuleFinder and so p@2.0 should not be located
|
|
// as module p is in parent configuration.
|
|
|
|
cf2 = resolveAndBind(cf1, ModuleFinder.of(), finder2, "m1");
|
|
|
|
assertTrue(cf2.parents().size() == 1);
|
|
assertTrue(cf2.parents().get(0) == cf1);
|
|
assertTrue(cf2.modules().size() == 1);
|
|
|
|
// p should be found in cf1
|
|
p = cf2.findModule("p").get();
|
|
assertTrue(p.configuration() == cf1);
|
|
assertEquals(provider_v1, p.reference().descriptor());
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test with two module finders.
|
|
*
|
|
* Module m2 can be found by both the before and after finders.
|
|
*/
|
|
@Test
|
|
void testWithTwoFinders1() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires("m2")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2_v1 = newBuilder("m2")
|
|
.version("1.0")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2_v2 = newBuilder("m2")
|
|
.version("2.0")
|
|
.build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor2_v1);
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor2_v2);
|
|
|
|
Configuration cf = resolve(finder1, finder2, "m1");
|
|
|
|
assertTrue(cf.modules().size() == 2);
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
assertTrue(cf.findModule("m2").isPresent());
|
|
|
|
ResolvedModule m1 = cf.findModule("m1").get();
|
|
ResolvedModule m2 = cf.findModule("m2").get();
|
|
|
|
assertEquals(descriptor1, m1.reference().descriptor());
|
|
assertEquals(descriptor2_v1, m2.reference().descriptor());
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test with two modules finders and service binding.
|
|
*
|
|
* The before and after ModuleFinders both locate a service provider module
|
|
* named "m2" that provide implementations of the same service type.
|
|
*/
|
|
@Test
|
|
void testWithTwoFinders2() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.exports("p")
|
|
.uses("p.S")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2_v1 = newBuilder("m2")
|
|
.requires("m1")
|
|
.provides("p.S", List.of("q.T"))
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2_v2 = newBuilder("m2")
|
|
.requires("m1")
|
|
.provides("p.S", List.of("q.T"))
|
|
.build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2_v1);
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2_v2);
|
|
|
|
Configuration cf = resolveAndBind(finder1, finder2, "m1");
|
|
|
|
assertTrue(cf.modules().size() == 2);
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
assertTrue(cf.findModule("m2").isPresent());
|
|
|
|
ResolvedModule m1 = cf.findModule("m1").get();
|
|
ResolvedModule m2 = cf.findModule("m2").get();
|
|
|
|
assertEquals(descriptor1, m1.reference().descriptor());
|
|
assertEquals(descriptor2_v1, m2.reference().descriptor());
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test for resolving a module that is located in the parent
|
|
* configuration.
|
|
*/
|
|
@Test
|
|
void testResolvedInParent1() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.build();
|
|
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
|
|
|
|
Configuration cf1 = resolve(finder, "m1");
|
|
|
|
assertTrue(cf1.modules().size() == 1);
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
|
|
Configuration cf2 = resolve(cf1, finder, "m1");
|
|
|
|
assertTrue(cf2.modules().size() == 1);
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test for resolving a module that has a dependency on a module
|
|
* in the parent configuration.
|
|
*/
|
|
@Test
|
|
void testResolvedInParent2() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1").build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
|
|
|
|
Configuration cf1 = resolve(finder1, "m1");
|
|
|
|
assertTrue(cf1.modules().size() == 1);
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires("m1")
|
|
.build();
|
|
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
|
|
|
|
Configuration cf2 = resolve(cf1, ModuleFinder.of(), finder2, "m2");
|
|
|
|
assertTrue(cf2.modules().size() == 1);
|
|
assertTrue(cf2.findModule("m2").isPresent());
|
|
|
|
ResolvedModule m1 = cf2.findModule("m1").get(); // find in parent
|
|
ResolvedModule m2 = cf2.findModule("m2").get();
|
|
|
|
assertTrue(m1.reads().size() == 0);
|
|
assertTrue(m2.reads().size() == 1);
|
|
assertTrue(m2.reads().contains(m1));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of resolving a module that depends on modules in two parent
|
|
* configurations.
|
|
*
|
|
* The test consists of three configurations:
|
|
* - Configuration cf1: m1
|
|
* - Configuration cf2: m2
|
|
* - Configuration cf3(cf1,cf2): m3 requires m1, m2
|
|
*/
|
|
@Test
|
|
void testResolvedInMultipleParents1() {
|
|
// Configuration cf1: m1
|
|
ModuleDescriptor descriptor1 = newBuilder("m1").build();
|
|
Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1");
|
|
assertEquals(List.of(Configuration.empty()), cf1.parents());
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
ResolvedModule m1 = cf1.findModule("m1").get();
|
|
assertTrue(m1.configuration() == cf1);
|
|
|
|
// Configuration cf2: m2
|
|
ModuleDescriptor descriptor2 = newBuilder("m2").build();
|
|
Configuration cf2 = resolve(ModuleUtils.finderOf(descriptor2), "m2");
|
|
assertEquals(List.of(Configuration.empty()), cf2.parents());
|
|
assertTrue(cf2.findModule("m2").isPresent());
|
|
ResolvedModule m2 = cf2.findModule("m2").get();
|
|
assertTrue(m2.configuration() == cf2);
|
|
|
|
// Configuration cf3(cf1,cf2): m3 requires m1 and m2
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires("m1")
|
|
.requires("m2")
|
|
.build();
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor3);
|
|
Configuration cf3 = Configuration.resolve(
|
|
finder,
|
|
List.of(cf1, cf2), // parents
|
|
ModuleFinder.of(),
|
|
Set.of("m3"));
|
|
assertEquals(List.of(cf1, cf2), cf3.parents());
|
|
assertTrue(cf3.findModule("m3").isPresent());
|
|
ResolvedModule m3 = cf3.findModule("m3").get();
|
|
assertTrue(m3.configuration() == cf3);
|
|
|
|
// check readability
|
|
assertTrue(m1.reads().isEmpty());
|
|
assertTrue(m2.reads().isEmpty());
|
|
assertEquals(Set.of(m1, m2), m3.reads());
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of resolving a module that depends on modules in three parent
|
|
* configurations arranged in a diamond (two direct parents).
|
|
*
|
|
* The test consists of four configurations:
|
|
* - Configuration cf1: m1
|
|
* - Configuration cf2(cf1): m2 requires m1
|
|
* - Configuration cf3(cf3): m3 requires m1
|
|
* - Configuration cf4(cf2,cf3): m4 requires m1,m2,m3
|
|
*/
|
|
@Test
|
|
void testResolvedInMultipleParents2() {
|
|
// Configuration cf1: m1
|
|
ModuleDescriptor descriptor1 = newBuilder("m1").build();
|
|
Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1");
|
|
assertEquals( List.of(Configuration.empty()), cf1.parents());
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
ResolvedModule m1 = cf1.findModule("m1").get();
|
|
assertTrue(m1.configuration() == cf1);
|
|
|
|
// Configuration cf2(cf1): m2 requires m1
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires("m1")
|
|
.build();
|
|
Configuration cf2 = Configuration.resolve(
|
|
ModuleUtils.finderOf(descriptor2),
|
|
List.of(cf1), // parents
|
|
ModuleFinder.of(),
|
|
Set.of("m2"));
|
|
assertEquals(List.of(cf1), cf2.parents());
|
|
assertTrue(cf2.findModule("m2").isPresent());
|
|
ResolvedModule m2 = cf2.findModule("m2").get();
|
|
assertTrue(m2.configuration() == cf2);
|
|
|
|
// Configuration cf3(cf1): m3 requires m1
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires("m1")
|
|
.build();
|
|
Configuration cf3 = Configuration.resolve(
|
|
ModuleUtils.finderOf(descriptor3),
|
|
List.of(cf1), // parents
|
|
ModuleFinder.of(),
|
|
Set.of("m3"));
|
|
assertEquals(List.of(cf1), cf3.parents());
|
|
assertTrue(cf3.findModule("m3").isPresent());
|
|
ResolvedModule m3 = cf3.findModule("m3").get();
|
|
assertTrue(m3.configuration() == cf3);
|
|
|
|
// Configuration cf4(cf2,cf3): m4 requires m1,m2,m3
|
|
ModuleDescriptor descriptor4 = newBuilder("m4")
|
|
.requires("m1")
|
|
.requires("m2")
|
|
.requires("m3")
|
|
.build();
|
|
Configuration cf4 = Configuration.resolve(
|
|
ModuleUtils.finderOf(descriptor4),
|
|
List.of(cf2, cf3), // parents
|
|
ModuleFinder.of(),
|
|
Set.of("m4"));
|
|
assertEquals(List.of(cf2, cf3), cf4.parents());
|
|
assertTrue(cf4.findModule("m4").isPresent());
|
|
ResolvedModule m4 = cf4.findModule("m4").get();
|
|
assertTrue(m4.configuration() == cf4);
|
|
|
|
// check readability
|
|
assertTrue(m1.reads().isEmpty());
|
|
assertEquals(Set.of(m1), m2.reads());
|
|
assertEquals(Set.of(m1), m3.reads());
|
|
assertEquals(Set.of(m1, m2, m3), m4.reads());
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of resolving a module that depends on modules in three parent
|
|
* configurations arranged in a diamond (two direct parents).
|
|
*
|
|
* The test consists of four configurations:
|
|
* - Configuration cf1: m1@1
|
|
* - Configuration cf2: m1@2, m2@2
|
|
* - Configuration cf3: m1@3, m2@3, m3@3
|
|
* - Configuration cf4(cf1,cf2,cf3): m4 requires m1,m2,m3
|
|
*/
|
|
@Test
|
|
void testResolvedInMultipleParents3() {
|
|
ModuleDescriptor descriptor1, descriptor2, descriptor3;
|
|
|
|
// Configuration cf1: m1@1
|
|
descriptor1 = newBuilder("m1").version("1").build();
|
|
Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1");
|
|
assertEquals(List.of(Configuration.empty()), cf1.parents());
|
|
|
|
// Configuration cf2: m1@2, m2@2
|
|
descriptor1 = newBuilder("m1").version("2").build();
|
|
descriptor2 = newBuilder("m2").version("2").build();
|
|
Configuration cf2 = resolve(
|
|
ModuleUtils.finderOf(descriptor1, descriptor2),
|
|
"m1", "m2");
|
|
assertEquals(List.of(Configuration.empty()), cf2.parents());
|
|
|
|
// Configuration cf3: m1@3, m2@3, m3@3
|
|
descriptor1 = newBuilder("m1").version("3").build();
|
|
descriptor2 = newBuilder("m2").version("3").build();
|
|
descriptor3 = newBuilder("m3").version("3").build();
|
|
Configuration cf3 = resolve(
|
|
ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3),
|
|
"m1", "m2", "m3");
|
|
assertEquals(List.of(Configuration.empty()), cf3.parents());
|
|
|
|
// Configuration cf4(cf1,cf2,cf3): m4 requires m1,m2,m3
|
|
ModuleDescriptor descriptor4 = newBuilder("m4")
|
|
.requires("m1")
|
|
.requires("m2")
|
|
.requires("m3")
|
|
.build();
|
|
Configuration cf4 = Configuration.resolve(
|
|
ModuleUtils.finderOf(descriptor4),
|
|
List.of(cf1, cf2, cf3), // parents
|
|
ModuleFinder.of(),
|
|
Set.of("m4"));
|
|
assertEquals(List.of(cf1, cf2, cf3), cf4.parents());
|
|
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
assertTrue(cf2.findModule("m1").isPresent());
|
|
assertTrue(cf2.findModule("m2").isPresent());
|
|
assertTrue(cf3.findModule("m1").isPresent());
|
|
assertTrue(cf3.findModule("m2").isPresent());
|
|
assertTrue(cf3.findModule("m3").isPresent());
|
|
assertTrue(cf4.findModule("m4").isPresent());
|
|
|
|
ResolvedModule m1_1 = cf1.findModule("m1").get();
|
|
ResolvedModule m1_2 = cf2.findModule("m1").get();
|
|
ResolvedModule m2_2 = cf2.findModule("m2").get();
|
|
ResolvedModule m1_3 = cf3.findModule("m1").get();
|
|
ResolvedModule m2_3 = cf3.findModule("m2").get();
|
|
ResolvedModule m3_3 = cf3.findModule("m3").get();
|
|
ResolvedModule m4 = cf4.findModule("m4").get();
|
|
|
|
assertTrue(m1_1.configuration() == cf1);
|
|
assertTrue(m1_2.configuration() == cf2);
|
|
assertTrue(m2_2.configuration() == cf2);
|
|
assertTrue(m1_3.configuration() == cf3);
|
|
assertTrue(m2_3.configuration() == cf3);
|
|
assertTrue(m3_3.configuration() == cf3);
|
|
assertTrue(m4.configuration() == cf4);
|
|
|
|
// check readability
|
|
assertTrue(m1_1.reads().isEmpty());
|
|
assertTrue(m1_2.reads().isEmpty());
|
|
assertTrue(m2_2.reads().isEmpty());
|
|
assertTrue(m1_3.reads().isEmpty());
|
|
assertTrue(m2_3.reads().isEmpty());
|
|
assertTrue(m3_3.reads().isEmpty());
|
|
assertEquals(Set.of(m1_1, m2_2, m3_3), m4.reads());
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of using the beforeFinder to override a module in a parent
|
|
* configuration.
|
|
*/
|
|
@Test
|
|
void testOverriding1() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1").build();
|
|
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
|
|
|
|
Configuration cf1 = resolve(finder, "m1");
|
|
assertTrue(cf1.modules().size() == 1);
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
|
|
Configuration cf2 = resolve(cf1, finder, "m1");
|
|
assertTrue(cf2.modules().size() == 1);
|
|
assertTrue(cf2.findModule("m1").isPresent());
|
|
}
|
|
|
|
/**
|
|
* Basic test of using the beforeFinder to override a module in a parent
|
|
* configuration.
|
|
*/
|
|
@Test
|
|
void testOverriding2() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1").build();
|
|
Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1");
|
|
assertTrue(cf1.modules().size() == 1);
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2").build();
|
|
Configuration cf2 = resolve(ModuleUtils.finderOf(descriptor2), "m2");
|
|
assertTrue(cf2.modules().size() == 1);
|
|
assertTrue(cf2.findModule("m2").isPresent());
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3").build();
|
|
Configuration cf3 = resolve(ModuleUtils.finderOf(descriptor3), "m3");
|
|
assertTrue(cf3.modules().size() == 1);
|
|
assertTrue(cf3.findModule("m3").isPresent());
|
|
|
|
// override m2, m1 and m3 should be found in parent configurations
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor2);
|
|
Configuration cf4 = Configuration.resolve(
|
|
finder,
|
|
List.of(cf1, cf2, cf3),
|
|
ModuleFinder.of(),
|
|
Set.of("m1", "m2", "m3"));
|
|
assertTrue(cf4.modules().size() == 1);
|
|
assertTrue(cf4.findModule("m2").isPresent());
|
|
ResolvedModule m2 = cf4.findModule("m2").get();
|
|
assertTrue(m2.configuration() == cf4);
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test of using the beforeFinder to override a module in the parent
|
|
* configuration but where implied readability in the picture so that the
|
|
* module in the parent is read.
|
|
*
|
|
* The test consists of two configurations:
|
|
* - Configuration cf1: m1, m2 requires transitive m1
|
|
* - Configuration cf2: m1, m3 requires m2
|
|
*/
|
|
@Test
|
|
void testOverriding3() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
|
|
.build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
|
|
Configuration cf1 = resolve(finder1, "m2");
|
|
|
|
assertTrue(cf1.modules().size() == 2);
|
|
assertTrue(cf1.findModule("m1").isPresent());
|
|
assertTrue(cf1.findModule("m2").isPresent());
|
|
|
|
// cf2: m3 requires m2, m1
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires("m2")
|
|
.build();
|
|
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3);
|
|
|
|
Configuration cf2 = resolve(cf1, finder2, "m1", "m3");
|
|
|
|
assertTrue(cf2.parents().size() == 1);
|
|
assertTrue(cf2.parents().get(0) == cf1);
|
|
|
|
assertTrue(cf2.modules().size() == 2);
|
|
assertTrue(cf2.findModule("m1").isPresent());
|
|
assertTrue(cf2.findModule("m3").isPresent());
|
|
|
|
ResolvedModule m1_1 = cf1.findModule("m1").get();
|
|
ResolvedModule m1_2 = cf2.findModule("m1").get();
|
|
ResolvedModule m2 = cf1.findModule("m2").get();
|
|
ResolvedModule m3 = cf2.findModule("m3").get();
|
|
|
|
assertTrue(m1_1.configuration() == cf1);
|
|
assertTrue(m1_2.configuration() == cf2);
|
|
assertTrue(m3.configuration() == cf2);
|
|
|
|
|
|
// check that m3 reads cf1/m1 and cf2/m2
|
|
assertTrue(m3.reads().size() == 2);
|
|
assertTrue(m3.reads().contains(m1_1));
|
|
assertTrue(m3.reads().contains(m2));
|
|
}
|
|
|
|
|
|
/**
|
|
* Root module not found
|
|
*/
|
|
@Test
|
|
void testRootNotFound() {
|
|
assertThrows(FindException.class, () -> resolve(ModuleFinder.of(), "m1"));
|
|
}
|
|
|
|
|
|
/**
|
|
* Direct dependency not found
|
|
*/
|
|
@Test
|
|
void testDirectDependencyNotFound() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1").requires("m2").build();
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
|
|
assertThrows(FindException.class, () -> resolve(finder, "m1"));
|
|
}
|
|
|
|
|
|
/**
|
|
* Transitive dependency not found
|
|
*/
|
|
@Test
|
|
void testTransitiveDependencyNotFound() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1").requires("m2").build();
|
|
ModuleDescriptor descriptor2 = newBuilder("m2").requires("m3").build();
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
assertThrows(FindException.class, () -> resolve(finder, "m1"));
|
|
}
|
|
|
|
|
|
/**
|
|
* Service provider dependency not found
|
|
*/
|
|
@Test
|
|
void testServiceProviderDependencyNotFound() {
|
|
|
|
// service provider dependency (on m3) not found
|
|
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.exports("p")
|
|
.uses("p.S")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires("m1")
|
|
.requires("m3")
|
|
.provides("p.S", List.of("q.T"))
|
|
.build();
|
|
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
|
|
// should throw ResolutionException because m3 is not found
|
|
assertThrows(FindException.class, () -> resolveAndBind(finder, "m1"));
|
|
}
|
|
|
|
|
|
/**
|
|
* Simple cycle.
|
|
*/
|
|
@Test
|
|
void testSimpleCycle() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1").requires("m2").build();
|
|
ModuleDescriptor descriptor2 = newBuilder("m2").requires("m3").build();
|
|
ModuleDescriptor descriptor3 = newBuilder("m3").requires("m1").build();
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
|
|
assertThrows(ResolutionException.class, () -> resolve(finder, "m1"));
|
|
}
|
|
|
|
/**
|
|
* Basic test for detecting cycles involving a service provider module
|
|
*/
|
|
@Test
|
|
void testCycleInProvider() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.exports("p")
|
|
.uses("p.S")
|
|
.build();
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires("m1")
|
|
.requires("m3")
|
|
.provides("p.S", List.of("q.T"))
|
|
.build();
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires("m2")
|
|
.build();
|
|
|
|
ModuleFinder finder
|
|
= ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
|
|
|
|
// should throw ResolutionException because of the m2 <--> m3 cycle
|
|
assertThrows(ResolutionException.class, () -> resolveAndBind(finder, "m1"));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test to detect reading a module with the same name as itself
|
|
*
|
|
* The test consists of three configurations:
|
|
* - Configuration cf1: m1, m2 requires transitive m1
|
|
* - Configuration cf2: m1 requires m2
|
|
*/
|
|
@Test
|
|
void testReadModuleWithSameNameAsSelf() {
|
|
ModuleDescriptor descriptor1_v1 = newBuilder("m1")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor1_v2 = newBuilder("m1")
|
|
.requires("m2")
|
|
.build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1_v1, descriptor2);
|
|
Configuration cf1 = resolve(finder1, "m2");
|
|
assertTrue(cf1.modules().size() == 2);
|
|
|
|
// resolve should throw ResolutionException
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1_v2);
|
|
assertThrows(ResolutionException.class, () -> resolve(cf1, finder2, "m1"));
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic test to detect reading two modules with the same name
|
|
*
|
|
* The test consists of three configurations:
|
|
* - Configuration cf1: m1, m2 requires transitive m1
|
|
* - Configuration cf2: m1, m3 requires transitive m1
|
|
* - Configuration cf3(cf1,cf2): m4 requires m2, m3
|
|
*/
|
|
@Test
|
|
void testReadTwoModuleWithSameName() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor4 = newBuilder("m4")
|
|
.requires("m2")
|
|
.requires("m3")
|
|
.build();
|
|
|
|
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
Configuration cf1 = resolve(finder1, "m2");
|
|
assertTrue(cf1.modules().size() == 2);
|
|
|
|
ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3);
|
|
Configuration cf2 = resolve(finder2, "m3");
|
|
assertTrue(cf2.modules().size() == 2);
|
|
|
|
// should throw ResolutionException as m4 will read modules named "m1".
|
|
ModuleFinder finder3 = ModuleUtils.finderOf(descriptor4);
|
|
assertThrows(ResolutionException.class,
|
|
() -> Configuration.resolve(finder3,
|
|
List.of(cf1, cf2),
|
|
ModuleFinder.of(),
|
|
Set.of("m4")));
|
|
}
|
|
|
|
|
|
/**
|
|
* Test two modules exporting package p to a module that reads both.
|
|
*/
|
|
@Test
|
|
void testPackageSuppliedByTwoOthers() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires("m2")
|
|
.requires("m3")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.exports("p")
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.exports("p", Set.of("m1"))
|
|
.build();
|
|
|
|
ModuleFinder finder
|
|
= ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
|
|
|
|
// m2 and m3 export package p to module m1
|
|
assertThrows(ResolutionException.class, () -> resolve(finder, "m1"));
|
|
}
|
|
|
|
|
|
/**
|
|
* Test the scenario where a module contains a package p and reads
|
|
* a module that exports package p.
|
|
*/
|
|
@Test
|
|
void testPackageSuppliedBySelfAndOther() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires("m2")
|
|
.packages(Set.of("p"))
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.exports("p")
|
|
.build();
|
|
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
|
|
// m1 contains package p, module m2 exports package p to m1
|
|
assertThrows(ResolutionException.class, () -> resolve(finder, "m1"));
|
|
}
|
|
|
|
|
|
/**
|
|
* Test the scenario where a module contains a package p and reads
|
|
* a module that also contains a package p.
|
|
*/
|
|
@Test
|
|
void testContainsPackageInSelfAndOther() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires("m2")
|
|
.packages(Set.of("p"))
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.packages(Set.of("p"))
|
|
.build();
|
|
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
|
|
Configuration cf = resolve(finder, "m1");
|
|
|
|
assertTrue(cf.modules().size() == 2);
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
assertTrue(cf.findModule("m2").isPresent());
|
|
|
|
// m1 reads m2, m2 reads nothing
|
|
ResolvedModule m1 = cf.findModule("m1").get();
|
|
ResolvedModule m2 = cf.findModule("m2").get();
|
|
assertTrue(m1.reads().size() == 1);
|
|
assertTrue(m1.reads().contains(m2));
|
|
assertTrue(m2.reads().size() == 0);
|
|
}
|
|
|
|
|
|
/**
|
|
* Test the scenario where a module that exports a package that is also
|
|
* exported by a module that it reads in a parent layer.
|
|
*/
|
|
@Test
|
|
void testExportSamePackageAsBootLayer() {
|
|
ModuleDescriptor descriptor = newBuilder("m1")
|
|
.requires("java.base")
|
|
.exports("java.lang")
|
|
.build();
|
|
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor);
|
|
|
|
Configuration bootConfiguration = ModuleLayer.boot().configuration();
|
|
|
|
// m1 contains package java.lang, java.base exports package java.lang to m1
|
|
assertThrows(ResolutionException.class, () -> resolve(bootConfiguration, finder, "m1"));
|
|
}
|
|
|
|
|
|
/**
|
|
* Test "uses p.S" where p is contained in the same module.
|
|
*/
|
|
@Test
|
|
void testContainsService1() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.packages(Set.of("p"))
|
|
.uses("p.S")
|
|
.build();
|
|
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
|
|
|
|
Configuration cf = resolve(finder, "m1");
|
|
|
|
assertTrue(cf.modules().size() == 1);
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
}
|
|
|
|
|
|
/**
|
|
* Test "uses p.S" where p is contained in a different module.
|
|
*/
|
|
@Test
|
|
void testContainsService2() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.packages(Set.of("p"))
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires("m1")
|
|
.uses("p.S")
|
|
.build();
|
|
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
|
|
// m2 does not read a module that exports p
|
|
assertThrows(ResolutionException.class, () -> resolve(finder, "m2"));
|
|
}
|
|
|
|
|
|
/**
|
|
* Test "provides p.S" where p is contained in the same module.
|
|
*/
|
|
@Test
|
|
void testContainsService3() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.packages(Set.of("p", "q"))
|
|
.provides("p.S", List.of("q.S1"))
|
|
.build();
|
|
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
|
|
|
|
Configuration cf = resolve(finder, "m1");
|
|
|
|
assertTrue(cf.modules().size() == 1);
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
}
|
|
|
|
|
|
/**
|
|
* Test "provides p.S" where p is contained in a different module.
|
|
*/
|
|
@Test
|
|
void testContainsService4() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.packages(Set.of("p"))
|
|
.build();
|
|
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires("m1")
|
|
.provides("p.S", List.of("q.S1"))
|
|
.build();
|
|
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
|
|
// m2 does not read a module that exports p
|
|
assertThrows(ResolutionException.class, () -> resolve(finder, "m2"));
|
|
}
|
|
|
|
/**
|
|
* Test uses optional service.
|
|
*
|
|
* module m1 { requires static m2; uses p.S; }
|
|
*/
|
|
@Test
|
|
void testUsesOptionalService1() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires(Set.of(Requires.Modifier.STATIC), "m2")
|
|
.uses("p.S")
|
|
.build();
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
|
|
Configuration cf = resolve(finder, "m1");
|
|
assertTrue(cf.modules().size() == 1);
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
}
|
|
|
|
/**
|
|
* Test uses optional service.
|
|
*
|
|
* module m1 { requires m2; uses p.S; }
|
|
* module m2 { requires static transitive m3; }
|
|
*/
|
|
@Test
|
|
void testUsesOptionalService2() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires("m2")
|
|
.uses("p.S")
|
|
.build();
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires(Set.of(Requires.Modifier.STATIC, Requires.Modifier.TRANSITIVE), "m3")
|
|
.build();
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
Configuration cf = resolve(finder, "m1");
|
|
assertTrue(cf.modules().size() == 2);
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
assertTrue(cf.findModule("m2").isPresent());
|
|
}
|
|
|
|
/**
|
|
* Test uses optional service.
|
|
*
|
|
* module m1 { requires m2; uses p.S; }
|
|
* module m2 { requires transitive m3; }
|
|
* module m3 { requires static transitive m4; }
|
|
*/
|
|
@Test
|
|
void testUsesOptionalService3() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires("m2")
|
|
.uses("p.S")
|
|
.build();
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires(Set.of(Requires.Modifier.TRANSITIVE), "m3")
|
|
.build();
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires(Set.of(Requires.Modifier.STATIC, Requires.Modifier.TRANSITIVE), "m4")
|
|
.build();
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
|
|
Configuration cf = resolve(finder, "m1");
|
|
assertTrue(cf.modules().size() == 3);
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
assertTrue(cf.findModule("m2").isPresent());
|
|
assertTrue(cf.findModule("m3").isPresent());
|
|
}
|
|
|
|
/**
|
|
* Test provides optional service.
|
|
*
|
|
* module m1 { requires static m2; provides p.S with q.P; }
|
|
*/
|
|
@Test
|
|
void testProvidesOptionalService1() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires(Set.of(Requires.Modifier.STATIC), "m2")
|
|
.provides("p.S", List.of("q.P"))
|
|
.build();
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
|
|
Configuration cf = resolve(finder, "m1");
|
|
assertTrue(cf.modules().size() == 1);
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
}
|
|
|
|
/**
|
|
* Test provides optional service.
|
|
*
|
|
* module m1 { requires m2; provides p.S with q.P; }
|
|
* module m2 { requires static transitive m3; }
|
|
*/
|
|
@Test
|
|
void testProvidesOptionalService2() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires("m2")
|
|
.provides("p.S", List.of("q.P"))
|
|
.build();
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires(Set.of(Requires.Modifier.STATIC, Requires.Modifier.TRANSITIVE), "m3")
|
|
.build();
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
Configuration cf = resolve(finder, "m1");
|
|
assertTrue(cf.modules().size() == 2);
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
assertTrue(cf.findModule("m2").isPresent());
|
|
}
|
|
|
|
/**
|
|
* Test provides optional service.
|
|
*
|
|
* module m1 { requires m2; provides p.S with q.P; }
|
|
* module m2 { requires transitive m3; }
|
|
* module m3 { requires static transitive m4; }
|
|
*/
|
|
@Test
|
|
void testProvidesOptionalService3() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires("m2")
|
|
.provides("p.S", List.of("q.P"))
|
|
.build();
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.requires(Set.of(Requires.Modifier.TRANSITIVE), "m3")
|
|
.build();
|
|
ModuleDescriptor descriptor3 = newBuilder("m3")
|
|
.requires(Set.of(Requires.Modifier.STATIC, Requires.Modifier.TRANSITIVE), "m4")
|
|
.build();
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
|
|
Configuration cf = resolve(finder, "m1");
|
|
assertTrue(cf.modules().size() == 3);
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
assertTrue(cf.findModule("m2").isPresent());
|
|
assertTrue(cf.findModule("m3").isPresent());
|
|
}
|
|
|
|
/**
|
|
* Test "uses p.S" where p is not exported to the module.
|
|
*/
|
|
@Test
|
|
void testServiceTypePackageNotExported1() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.uses("p.S")
|
|
.build();
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
|
|
|
|
// m1 does not read a module that exports p to m1
|
|
assertThrows(ResolutionException.class, () -> resolve(finder, "m1"));
|
|
}
|
|
|
|
/**
|
|
* Test "uses p.S" where p is not exported to the module.
|
|
*
|
|
* module m1 { requires m2; uses p.S; }
|
|
* module m2 { contains p; }
|
|
*/
|
|
@Test
|
|
void testServiceTypePackageNotExported2() {
|
|
ModuleDescriptor descriptor1 = newBuilder("m1")
|
|
.requires("m2")
|
|
.uses("p.S")
|
|
.build();
|
|
ModuleDescriptor descriptor2 = newBuilder("m2")
|
|
.packages(Set.of("p"))
|
|
.build();
|
|
ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
|
|
|
|
// m1 does not read a module that exports p to m1
|
|
assertThrows(ResolutionException.class, () -> resolve(finder, "m1"));
|
|
}
|
|
|
|
|
|
/**
|
|
* Test the empty configuration.
|
|
*/
|
|
@Test
|
|
void testEmptyConfiguration() {
|
|
Configuration cf = Configuration.empty();
|
|
|
|
assertTrue(cf.parents().isEmpty());
|
|
|
|
assertTrue(cf.modules().isEmpty());
|
|
assertFalse(cf.findModule("java.base").isPresent());
|
|
}
|
|
|
|
/**
|
|
* Test creating a configuration containing platform specific modules.
|
|
*/
|
|
@ParameterizedTest
|
|
@CsvSource({",", "linux-aarch64,", "linux-aarch64,linux-aarch64"})
|
|
void testPlatformMatch(String targetPlatform1, String targetPlatform2) throws IOException {
|
|
ModuleDescriptor base = ModuleDescriptor.newModule("java.base").build();
|
|
Path system = writeModule(base, null);
|
|
|
|
ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1")
|
|
.requires("m2")
|
|
.build();
|
|
Path dir1 = writeModule(descriptor1, targetPlatform1);
|
|
|
|
ModuleDescriptor descriptor2 = ModuleDescriptor.newModule("m2").build();
|
|
Path dir2 = writeModule(descriptor2, targetPlatform2);
|
|
|
|
ModuleFinder finder = ModuleFinder.of(system, dir1, dir2);
|
|
|
|
Configuration cf = resolve(finder, "m1");
|
|
|
|
assertTrue(cf.modules().size() == 3);
|
|
assertTrue(cf.findModule("java.base").isPresent());
|
|
assertTrue(cf.findModule("m1").isPresent());
|
|
assertTrue(cf.findModule("m2").isPresent());
|
|
}
|
|
|
|
/**
|
|
* Test attempting to create a configuration with modules for different platforms.
|
|
*/
|
|
@ParameterizedTest
|
|
@CsvSource({"linux-x64,linux-aarch64", "linux-x64,windows-x64"})
|
|
void testPlatformMisMatch(String targetPlatform1, String targetPlatform2) throws IOException {
|
|
assertThrows(FindException.class,
|
|
() -> testPlatformMatch(targetPlatform1, targetPlatform2));
|
|
}
|
|
|
|
// no parents
|
|
|
|
@Test
|
|
void testResolveRequiresWithNoParents() {
|
|
ModuleFinder empty = ModuleFinder.of();
|
|
assertThrows(IllegalArgumentException.class,
|
|
() -> Configuration.resolve(empty, List.of(), empty, Set.of()));
|
|
}
|
|
|
|
@Test
|
|
void testResolveRequiresAndUsesWithNoParents() {
|
|
ModuleFinder empty = ModuleFinder.of();
|
|
assertThrows(IllegalArgumentException.class,
|
|
() -> Configuration.resolveAndBind(empty, List.of(), empty, Set.of()));
|
|
}
|
|
|
|
|
|
// parents with modules for specific platforms
|
|
@ParameterizedTest
|
|
@CsvSource({",", "linux-aarch64,", "linux-aarch64,linux-aarch64"})
|
|
void testResolveRequiresWithCompatibleParents(String targetPlatform1,
|
|
String targetPlatform2) throws IOException {
|
|
ModuleDescriptor base = ModuleDescriptor.newModule("java.base").build();
|
|
Path system = writeModule(base, null);
|
|
|
|
ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1").build();
|
|
Path dir1 = writeModule(descriptor1, targetPlatform1);
|
|
|
|
ModuleDescriptor descriptor2 = ModuleDescriptor.newModule("m2").build();
|
|
Path dir2 = writeModule(descriptor2, targetPlatform2);
|
|
|
|
ModuleFinder finder1 = ModuleFinder.of(system, dir1);
|
|
Configuration cf1 = resolve(finder1, "m1");
|
|
|
|
ModuleFinder finder2 = ModuleFinder.of(system, dir2);
|
|
Configuration cf2 = resolve(finder2, "m2");
|
|
|
|
Configuration cf3 = Configuration.resolve(ModuleFinder.of(),
|
|
List.of(cf1, cf2),
|
|
ModuleFinder.of(),
|
|
Set.of());
|
|
assertTrue(cf3.parents().size() == 2);
|
|
}
|
|
|
|
|
|
@ParameterizedTest
|
|
@CsvSource({"linux-x64,linux-aarch64", "linux-x64,windows-x64"})
|
|
void testResolveRequiresWithConflictingParents(String targetPlatform1,
|
|
String targetPlatform2) throws IOException {
|
|
assertThrows(IllegalArgumentException.class,
|
|
() -> testResolveRequiresWithCompatibleParents(targetPlatform1, targetPlatform2));
|
|
}
|
|
|
|
|
|
// null handling
|
|
|
|
@Test
|
|
void testResolveRequiresWithNull1() {
|
|
assertThrows(NullPointerException.class,
|
|
() -> resolve((ModuleFinder) null, ModuleFinder.of()));
|
|
}
|
|
|
|
@Test
|
|
void testResolveRequiresWithNull2() {
|
|
assertThrows(NullPointerException.class,
|
|
() -> resolve(ModuleFinder.of(), (ModuleFinder) null));
|
|
}
|
|
|
|
@Test
|
|
void testResolveRequiresWithNull3() {
|
|
Configuration empty = Configuration.empty();
|
|
assertThrows(NullPointerException.class,
|
|
() -> Configuration.resolve(null, List.of(empty), ModuleFinder.of(), Set.of()));
|
|
}
|
|
|
|
@Test
|
|
void testResolveRequiresWithNull4() {
|
|
ModuleFinder empty = ModuleFinder.of();
|
|
assertThrows(NullPointerException.class,
|
|
() -> Configuration.resolve(empty, null, empty, Set.of()));
|
|
}
|
|
|
|
@Test
|
|
void testResolveRequiresWithNull5() {
|
|
Configuration cf = ModuleLayer.boot().configuration();
|
|
assertThrows(NullPointerException.class,
|
|
() -> Configuration.resolve(ModuleFinder.of(), List.of(cf), null, Set.of()));
|
|
}
|
|
|
|
@Test
|
|
void testResolveRequiresWithNull6() {
|
|
ModuleFinder empty = ModuleFinder.of();
|
|
Configuration cf = ModuleLayer.boot().configuration();
|
|
assertThrows(NullPointerException.class,
|
|
() -> Configuration.resolve(empty, List.of(cf), empty, null));
|
|
}
|
|
|
|
@Test
|
|
void testResolveRequiresAndUsesWithNull1() {
|
|
assertThrows(NullPointerException.class,
|
|
() -> resolveAndBind((ModuleFinder) null, ModuleFinder.of()));
|
|
}
|
|
|
|
@Test
|
|
void testResolveRequiresAndUsesWithNull2() {
|
|
assertThrows(NullPointerException.class,
|
|
() -> resolveAndBind(ModuleFinder.of(), (ModuleFinder) null));
|
|
}
|
|
|
|
@Test
|
|
void testResolveRequiresAndUsesWithNull3() {
|
|
Configuration empty = Configuration.empty();
|
|
assertThrows(NullPointerException.class,
|
|
() -> Configuration.resolveAndBind(null, List.of(empty), ModuleFinder.of(), Set.of()));
|
|
}
|
|
|
|
@Test
|
|
void testResolveRequiresAndUsesWithNull4() {
|
|
ModuleFinder empty = ModuleFinder.of();
|
|
assertThrows(NullPointerException.class,
|
|
() -> Configuration.resolveAndBind(empty, null, empty, Set.of()));
|
|
}
|
|
|
|
@Test
|
|
void testResolveRequiresAndUsesWithNull5() {
|
|
Configuration cf = ModuleLayer.boot().configuration();
|
|
assertThrows(NullPointerException.class,
|
|
() -> Configuration.resolveAndBind(ModuleFinder.of(), List.of(cf), null, Set.of()));
|
|
}
|
|
|
|
@Test
|
|
void testResolveRequiresAndUsesWithNull6() {
|
|
ModuleFinder empty = ModuleFinder.of();
|
|
Configuration cf = ModuleLayer.boot().configuration();
|
|
assertThrows(NullPointerException.class,
|
|
() -> Configuration.resolveAndBind(empty, List.of(cf), empty, null));
|
|
}
|
|
|
|
@Test
|
|
void testFindModuleWithNull() {
|
|
assertThrows(NullPointerException.class, () -> Configuration.empty().findModule(null));
|
|
}
|
|
|
|
// unmodifiable collections
|
|
|
|
static Stream<Configuration> configurations() {
|
|
return Stream.of(
|
|
Configuration.empty(),
|
|
ModuleLayer.boot().configuration(),
|
|
resolve(ModuleFinder.of())
|
|
);
|
|
}
|
|
|
|
@ParameterizedTest
|
|
@MethodSource("configurations")
|
|
void testUnmodifiableParents(Configuration cf) {
|
|
assertThrows(UnsupportedOperationException.class,
|
|
() -> cf.parents().add(Configuration.empty()));
|
|
assertThrows(UnsupportedOperationException.class,
|
|
() -> cf.parents().remove(Configuration.empty()));
|
|
}
|
|
|
|
@ParameterizedTest
|
|
@MethodSource("configurations")
|
|
void testUnmodifiableModules(Configuration cf) {
|
|
ResolvedModule module = ModuleLayer.boot()
|
|
.configuration()
|
|
.findModule("java.base")
|
|
.orElseThrow();
|
|
assertThrows(UnsupportedOperationException.class,
|
|
() -> cf.modules().add(module));
|
|
assertThrows(UnsupportedOperationException.class,
|
|
() -> cf.modules().remove(module));
|
|
}
|
|
|
|
/**
|
|
* Invokes parent.resolve(...)
|
|
*/
|
|
private static Configuration resolve(Configuration parent,
|
|
ModuleFinder before,
|
|
ModuleFinder after,
|
|
String... roots) {
|
|
return parent.resolve(before, after, Set.of(roots));
|
|
}
|
|
|
|
private static Configuration resolve(Configuration parent,
|
|
ModuleFinder before,
|
|
String... roots) {
|
|
return resolve(parent, before, ModuleFinder.of(), roots);
|
|
}
|
|
|
|
private static Configuration resolve(ModuleFinder before,
|
|
ModuleFinder after,
|
|
String... roots) {
|
|
return resolve(Configuration.empty(), before, after, roots);
|
|
}
|
|
|
|
private static Configuration resolve(ModuleFinder before,
|
|
String... roots) {
|
|
return resolve(Configuration.empty(), before, roots);
|
|
}
|
|
|
|
|
|
/**
|
|
* Invokes parent.resolveAndBind(...)
|
|
*/
|
|
private static Configuration resolveAndBind(Configuration parent,
|
|
ModuleFinder before,
|
|
ModuleFinder after,
|
|
String... roots) {
|
|
return parent.resolveAndBind(before, after, Set.of(roots));
|
|
}
|
|
|
|
private static Configuration resolveAndBind(Configuration parent,
|
|
ModuleFinder before,
|
|
String... roots) {
|
|
return resolveAndBind(parent, before, ModuleFinder.of(), roots);
|
|
}
|
|
|
|
private static Configuration resolveAndBind(ModuleFinder before,
|
|
ModuleFinder after,
|
|
String... roots) {
|
|
return resolveAndBind(Configuration.empty(), before, after, roots);
|
|
}
|
|
|
|
private static Configuration resolveAndBind(ModuleFinder before,
|
|
String... roots) {
|
|
return resolveAndBind(Configuration.empty(), before, roots);
|
|
}
|
|
|
|
|
|
/**
|
|
* Writes a module-info.class. If {@code targetPlatform} is not null then
|
|
* it includes the ModuleTarget class file attribute with the target platform.
|
|
*/
|
|
private static Path writeModule(ModuleDescriptor descriptor, String targetPlatform)
|
|
throws IOException
|
|
{
|
|
ModuleTarget target;
|
|
if (targetPlatform != null) {
|
|
target = new ModuleTarget(targetPlatform);
|
|
} else {
|
|
target = null;
|
|
}
|
|
String name = descriptor.name();
|
|
Path dir = Files.createTempDirectory(Paths.get(""), name);
|
|
Path mi = dir.resolve("module-info.class");
|
|
try (OutputStream out = Files.newOutputStream(mi)) {
|
|
ModuleInfoWriter.write(descriptor, target, out);
|
|
}
|
|
return dir;
|
|
}
|
|
}
|