| /* | |
| * Copyright (c) 2013, 2024, 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 8158456 8298875 | |
| * @modules java.base/jdk.internal.access | |
| * java.base/jdk.internal.module | |
| * @library /test/lib | |
| * @build jdk.test.lib.util.ModuleInfoWriter | |
| * @run testng ModuleDescriptorTest | |
| * @summary Basic test for java.lang.module.ModuleDescriptor and its builder | |
| */ | |
| import java.io.ByteArrayOutputStream; | |
| import java.io.IOException; | |
| import java.io.InputStream; | |
| import java.lang.module.InvalidModuleDescriptorException; | |
| import java.lang.module.ModuleDescriptor; | |
| import java.lang.module.ModuleDescriptor.Builder; | |
| import java.lang.module.ModuleDescriptor.Exports; | |
| import java.lang.module.ModuleDescriptor.Opens; | |
| import java.lang.module.ModuleDescriptor.Requires; | |
| import java.lang.module.ModuleDescriptor.Provides; | |
| import java.lang.module.ModuleDescriptor.Requires.Modifier; | |
| import java.lang.module.ModuleDescriptor.Version; | |
| import java.nio.ByteBuffer; | |
| import java.util.ArrayList; | |
| import java.util.Collections; | |
| import java.util.EnumSet; | |
| import java.util.HashSet; | |
| import java.util.Iterator; | |
| import java.util.List; | |
| import java.util.Objects; | |
| import java.util.Set; | |
| import java.util.stream.Collectors; | |
| import static java.lang.module.ModuleDescriptor.Requires.Modifier.*; | |
| import jdk.internal.access.JavaLangModuleAccess; | |
| import jdk.internal.access.SharedSecrets; | |
| import java.lang.classfile.ClassFile; | |
| import java.lang.classfile.ClassFileVersion; | |
| import java.lang.classfile.ClassTransform; | |
| import java.lang.classfile.attribute.ModuleAttribute; | |
| import java.lang.constant.PackageDesc; | |
| import java.lang.constant.ModuleDesc; | |
| import jdk.test.lib.util.ModuleInfoWriter; | |
| import org.testng.annotations.DataProvider; | |
| import org.testng.annotations.Test; | |
| import static org.testng.Assert.*; | |
| @Test | |
| public class ModuleDescriptorTest { | |
| private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess(); | |
| @DataProvider(name = "invalidNames") | |
| public Object[][] invalidNames() { | |
| return new Object[][]{ | |
| { null, null }, | |
| { "1", null }, | |
| { "1foo", null }, | |
| { ".foo", null }, | |
| { "foo.", null }, | |
| { "[foo]", null }, | |
| { "foo.1", null }, | |
| { "1foo.bar", null }, | |
| { "foo.1bar", null }, | |
| { "foo.[bar]", null }, | |
| { "foo..bar", null }, | |
| { "foo.bar.1", null }, | |
| { "foo.bar.1gus", null }, | |
| { "foo.bar.[gus]", null }, | |
| { "class", null }, | |
| { "interface", null }, | |
| { "true", null }, | |
| { "false", null }, | |
| { "null", null }, | |
| { "x.class", null }, | |
| { "x.interface", null }, | |
| { "x.true", null }, | |
| { "x.false", null }, | |
| { "x.null", null }, | |
| { "class.x", null }, | |
| { "interface.x", null }, | |
| { "true.x", null }, | |
| { "false.x", null }, | |
| { "null.x", null }, | |
| { "x.class.x", null }, | |
| { "x.interface.x", null }, | |
| { "x.true.x", null }, | |
| { "x.false.x", null }, | |
| { "x.null.x", null }, | |
| { "_", null }, | |
| }; | |
| } | |
| // requires | |
| private Requires requires(Set<Modifier> mods, String mn) { | |
| return requires(mods, mn, null); | |
| } | |
| private Requires requires(Set<Modifier> mods, String mn, Version v) { | |
| Builder builder = ModuleDescriptor.newModule("m"); | |
| if (v == null) { | |
| builder.requires(mods, mn); | |
| } else { | |
| builder.requires(mods, mn, v); | |
| } | |
| Set<Requires> requires = builder.build().requires(); | |
| assertTrue(requires.size() == 2); | |
| Iterator<Requires> iterator = requires.iterator(); | |
| Requires r = iterator.next(); | |
| if (r.name().equals("java.base")) { | |
| r = iterator.next(); | |
| } else { | |
| Requires other = iterator.next(); | |
| assertEquals(other.name(), "java.base"); | |
| } | |
| return r; | |
| } | |
| private Requires requires(String mn) { | |
| return requires(Collections.emptySet(), mn); | |
| } | |
| public void testRequiresWithRequires() { | |
| Requires r1 = requires("foo"); | |
| ModuleDescriptor descriptor = ModuleDescriptor.newModule("m").requires(r1).build(); | |
| assertEquals(descriptor.requires().size(), 2); | |
| var iterator = descriptor.requires().iterator(); | |
| Requires r2 = iterator.next(); | |
| if (r2.name().equals("java.base")) { | |
| r2 = iterator.next(); | |
| } | |
| assertEquals(r1, r2); | |
| } | |
| public void testRequiresWithNoModifiers() { | |
| Requires r = requires(EnumSet.noneOf(Requires.Modifier.class), "foo"); | |
| assertEquals(r, r); | |
| assertTrue(r.compareTo(r) == 0); | |
| assertTrue(r.modifiers().isEmpty()); | |
| assertEquals(r.name(), "foo"); | |
| assertFalse(r.compiledVersion().isPresent()); | |
| } | |
| public void testRequiresWithOneModifier() { | |
| Requires r = requires(EnumSet.of(TRANSITIVE), "foo"); | |
| assertEquals(r, r); | |
| assertTrue(r.compareTo(r) == 0); | |
| assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE)); | |
| assertEquals(r.name(), "foo"); | |
| assertFalse(r.compiledVersion().isPresent()); | |
| } | |
| public void testRequiresWithTwoModifiers() { | |
| Requires r = requires(EnumSet.of(TRANSITIVE, SYNTHETIC), "foo"); | |
| assertEquals(r, r); | |
| assertTrue(r.compareTo(r) == 0); | |
| assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, SYNTHETIC)); | |
| assertEquals(r.name(), "foo"); | |
| assertFalse(r.compiledVersion().isPresent()); | |
| } | |
| public void testRequiresWithAllModifiers() { | |
| Requires r = requires(EnumSet.allOf(Modifier.class), "foo"); | |
| assertEquals(r, r); | |
| assertTrue(r.compareTo(r) == 0); | |
| assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, STATIC, SYNTHETIC, MANDATED)); | |
| assertEquals(r.name(), "foo"); | |
| assertFalse(r.compiledVersion().isPresent()); | |
| } | |
| public void testRequiresWithCompiledVersion() { | |
| Version v = Version.parse("1.0"); | |
| Requires r = requires(Set.of(), "foo", v); | |
| assertEquals(r, r); | |
| assertTrue(r.compareTo(r) == 0); | |
| assertEquals(r.modifiers(), Set.of()); | |
| assertEquals(r.name(), "foo"); | |
| assertTrue(r.compiledVersion().isPresent()); | |
| assertEquals(r.compiledVersion().get().toString(), "1.0"); | |
| } | |
| @Test(expectedExceptions = IllegalStateException.class) | |
| public void testRequiresWithDuplicatesRequires() { | |
| Requires r = requires("foo"); | |
| ModuleDescriptor.newModule("m").requires(r).requires(r); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testRequiresSelfWithRequires() { | |
| Requires r = requires("foo"); | |
| ModuleDescriptor.newModule("foo").requires(r); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testRequiresSelfWithNoModifier() { | |
| ModuleDescriptor.newModule("m").requires("m"); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testRequiresSelfWithOneModifier() { | |
| ModuleDescriptor.newModule("m").requires(Set.of(TRANSITIVE), "m"); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testRequiresSelfWithAllModifiers() { | |
| ModuleDescriptor.newModule("m").requires(EnumSet.allOf(Modifier.class), "m"); | |
| } | |
| @Test(dataProvider = "invalidNames", | |
| expectedExceptions = IllegalArgumentException.class ) | |
| public void testRequiresWithBadModuleName(String mn, String ignore) { | |
| requires(EnumSet.noneOf(Modifier.class), mn); | |
| } | |
| @Test(expectedExceptions = NullPointerException.class) | |
| public void testRequiresWithNullRequires() { | |
| ModuleDescriptor.newModule("m").requires((Requires) null); | |
| } | |
| @Test(expectedExceptions = NullPointerException.class) | |
| public void testRequiresWithNullModifiers() { | |
| ModuleDescriptor.newModule("m").requires(null, "foo"); | |
| } | |
| @Test(expectedExceptions = NullPointerException.class) | |
| public void testRequiresWithNullVersion() { | |
| ModuleDescriptor.newModule("m").requires(Set.of(), "foo", null); | |
| } | |
| public void testRequiresCompare() { | |
| Requires r1 = requires(EnumSet.noneOf(Modifier.class), "foo"); | |
| Requires r2 = requires(EnumSet.noneOf(Modifier.class), "bar"); | |
| int n = "foo".compareTo("bar"); | |
| assertTrue(r1.compareTo(r2) == n); | |
| assertTrue(r2.compareTo(r1) == -n); | |
| } | |
| public void testRequiresCompareWithDifferentModifiers() { | |
| Requires r1 = requires(EnumSet.of(TRANSITIVE), "foo"); | |
| Requires r2 = requires(EnumSet.of(SYNTHETIC), "foo"); | |
| int n = Integer.compare(1 << TRANSITIVE.ordinal(), 1 << SYNTHETIC.ordinal()); | |
| assertTrue(r1.compareTo(r2) == n); | |
| assertTrue(r2.compareTo(r1) == -n); | |
| } | |
| public void testRequiresCompareWithSameModifiers() { | |
| Requires r1 = requires(EnumSet.of(SYNTHETIC), "foo"); | |
| Requires r2 = requires(EnumSet.of(SYNTHETIC), "foo"); | |
| assertTrue(r1.compareTo(r2) == 0); | |
| assertTrue(r2.compareTo(r1) == 0); | |
| } | |
| public void testRequiresCompareWithSameCompiledVersion() { | |
| Requires r1 = requires(Set.of(), "foo", Version.parse("2.0")); | |
| Requires r2 = requires(Set.of(), "foo", Version.parse("2.0")); | |
| assertTrue(r1.compareTo(r2) == 0); | |
| assertTrue(r2.compareTo(r1) == 0); | |
| } | |
| public void testRequiresCompareWithDifferentCompiledVersion() { | |
| Requires r1 = requires(Set.of(), "foo", Version.parse("1.0")); | |
| Requires r2 = requires(Set.of(), "foo", Version.parse("2.0")); | |
| assertTrue(r1.compareTo(r2) < 0); | |
| assertTrue(r2.compareTo(r1) > 0); | |
| } | |
| public void testRequiresEqualsAndHashCode() { | |
| Requires r1 = requires("foo"); | |
| Requires r2 = requires("foo"); | |
| assertEquals(r1, r2); | |
| assertTrue(r1.hashCode() == r2.hashCode()); | |
| r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo"); | |
| r2 = requires(EnumSet.allOf(Requires.Modifier.class), "foo"); | |
| assertEquals(r1, r2); | |
| assertTrue(r1.hashCode() == r2.hashCode()); | |
| r1 = requires("foo"); | |
| r2 = requires("bar"); | |
| assertNotEquals(r1, r2); | |
| r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo"); | |
| r2 = requires(Set.of(), "foo"); | |
| assertNotEquals(r1, r2); | |
| Version v1 = Version.parse("1.0"); | |
| r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v1); | |
| r2 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v1); | |
| assertEquals(r1, r2); | |
| assertTrue(r1.hashCode() == r2.hashCode()); | |
| Version v2 = Version.parse("2.0"); | |
| r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v1); | |
| r2 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v2); | |
| assertNotEquals(r1, r2); | |
| } | |
| public void testRequiresToString() { | |
| Requires r = requires(EnumSet.noneOf(Modifier.class), "foo"); | |
| assertTrue(r.toString().contains("foo")); | |
| } | |
| // exports | |
| private Exports exports(Set<Exports.Modifier> mods, String pn) { | |
| return ModuleDescriptor.newModule("foo") | |
| .exports(mods, pn) | |
| .build() | |
| .exports() | |
| .iterator() | |
| .next(); | |
| } | |
| private Exports exports(String pn) { | |
| return exports(Set.of(), pn); | |
| } | |
| private Exports exports(Set<Exports.Modifier> mods, String pn, String target) { | |
| return ModuleDescriptor.newModule("foo") | |
| .exports(mods, pn, Set.of(target)) | |
| .build() | |
| .exports() | |
| .iterator() | |
| .next(); | |
| } | |
| private Exports exports(String pn, String target) { | |
| return exports(Set.of(), pn, target); | |
| } | |
| public void testExportsExports() { | |
| Exports e1 = exports("p"); | |
| ModuleDescriptor descriptor = ModuleDescriptor.newModule("m").exports(e1).build(); | |
| Exports e2 = descriptor.exports().iterator().next(); | |
| assertEquals(e1, e2); | |
| } | |
| public void testExportsToAll() { | |
| Exports e = exports("p"); | |
| assertEquals(e, e); | |
| assertTrue(e.modifiers().isEmpty()); | |
| assertEquals(e.source(), "p"); | |
| assertFalse(e.isQualified()); | |
| assertTrue(e.targets().isEmpty()); | |
| } | |
| public void testExportsToTarget() { | |
| Exports e = exports("p", "bar"); | |
| assertEquals(e, e); | |
| assertTrue(e.modifiers().isEmpty()); | |
| assertEquals(e.source(), "p"); | |
| assertTrue(e.isQualified()); | |
| assertTrue(e.targets().size() == 1); | |
| assertTrue(e.targets().contains("bar")); | |
| } | |
| public void testExportsToTargets() { | |
| Set<String> targets = new HashSet<>(); | |
| targets.add("bar"); | |
| targets.add("gus"); | |
| Exports e | |
| = ModuleDescriptor.newModule("foo") | |
| .exports("p", targets) | |
| .build() | |
| .exports() | |
| .iterator() | |
| .next(); | |
| assertEquals(e, e); | |
| assertTrue(e.modifiers().isEmpty()); | |
| assertEquals(e.source(), "p"); | |
| assertTrue(e.isQualified()); | |
| assertTrue(e.targets().size() == 2); | |
| assertTrue(e.targets().contains("bar")); | |
| assertTrue(e.targets().contains("gus")); | |
| } | |
| public void testExportsToAllWithModifier() { | |
| Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); | |
| assertEquals(e, e); | |
| assertTrue(e.modifiers().size() == 1); | |
| assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC)); | |
| assertEquals(e.source(), "p"); | |
| assertFalse(e.isQualified()); | |
| assertTrue(e.targets().isEmpty()); | |
| } | |
| public void testExportsToTargetWithModifier() { | |
| Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p", "bar"); | |
| assertEquals(e, e); | |
| assertTrue(e.modifiers().size() == 1); | |
| assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC)); | |
| assertEquals(e.source(), "p"); | |
| assertTrue(e.isQualified()); | |
| assertTrue(e.targets().size() == 1); | |
| assertTrue(e.targets().contains("bar")); | |
| } | |
| @Test(expectedExceptions = IllegalStateException.class) | |
| public void testExportsWithDuplicate1() { | |
| Exports e = exports("p"); | |
| ModuleDescriptor.newModule("foo").exports(e).exports(e); | |
| } | |
| @Test(expectedExceptions = IllegalStateException.class) | |
| public void testExportsWithDuplicate2() { | |
| ModuleDescriptor.newModule("foo").exports("p").exports("p"); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class ) | |
| public void testExportsWithEmptySet() { | |
| ModuleDescriptor.newModule("foo").exports("p", Collections.emptySet()); | |
| } | |
| @Test(dataProvider = "invalidNames", | |
| expectedExceptions = IllegalArgumentException.class ) | |
| public void testExportsWithBadName(String pn, String ignore) { | |
| ModuleDescriptor.newModule("foo").exports(pn); | |
| } | |
| @Test(expectedExceptions = NullPointerException.class ) | |
| public void testExportsWithNullExports() { | |
| ModuleDescriptor.newModule("foo").exports((Exports) null); | |
| } | |
| @Test(expectedExceptions = NullPointerException.class ) | |
| public void testExportsWithNullTargets() { | |
| ModuleDescriptor.newModule("foo").exports("p", (Set<String>) null); | |
| } | |
| public void testExportsCompare() { | |
| Exports e1 = exports("p"); | |
| Exports e2 = exports("p"); | |
| assertEquals(e1, e2); | |
| assertTrue(e1.hashCode() == e2.hashCode()); | |
| assertTrue(e1.compareTo(e2) == 0); | |
| assertTrue(e2.compareTo(e1) == 0); | |
| } | |
| public void testExportsCompareWithSameModifiers() { | |
| Exports e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); | |
| Exports e2 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); | |
| assertEquals(e1, e2); | |
| assertTrue(e1.hashCode() == e2.hashCode()); | |
| assertTrue(e1.compareTo(e2) == 0); | |
| assertTrue(e2.compareTo(e1) == 0); | |
| } | |
| public void testExportsCompareWithDifferentModifiers() { | |
| Exports e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); | |
| Exports e2 = exports("p"); | |
| assertNotEquals(e1, e2); | |
| assertTrue(e1.compareTo(e2) == 1); | |
| assertTrue(e2.compareTo(e1) == -1); | |
| } | |
| public void testExportsCompareWithSameTargets() { | |
| Exports e1 = exports("p", "x"); | |
| Exports e2 = exports("p", "x"); | |
| assertEquals(e1, e2); | |
| assertTrue(e1.hashCode() == e2.hashCode()); | |
| assertTrue(e1.compareTo(e2) == 0); | |
| assertTrue(e2.compareTo(e1) == 0); | |
| } | |
| public void testExportsCompareWithDifferentTargets() { | |
| Exports e1 = exports("p", "y"); | |
| Exports e2 = exports("p", "x"); | |
| assertNotEquals(e1, e2); | |
| assertTrue(e1.compareTo(e2) == 1); | |
| assertTrue(e2.compareTo(e1) == -1); | |
| } | |
| public void testExportsToString() { | |
| String s = ModuleDescriptor.newModule("foo") | |
| .exports("p1", Set.of("bar")) | |
| .build() | |
| .exports() | |
| .iterator() | |
| .next() | |
| .toString(); | |
| assertTrue(s.contains("p1")); | |
| assertTrue(s.contains("bar")); | |
| } | |
| // opens | |
| private Opens opens(Set<Opens.Modifier> mods, String pn) { | |
| return ModuleDescriptor.newModule("foo") | |
| .opens(mods, pn) | |
| .build() | |
| .opens() | |
| .iterator() | |
| .next(); | |
| } | |
| private Opens opens(String pn) { | |
| return opens(Set.of(), pn); | |
| } | |
| private Opens opens(Set<Opens.Modifier> mods, String pn, String target) { | |
| return ModuleDescriptor.newModule("foo") | |
| .opens(mods, pn, Set.of(target)) | |
| .build() | |
| .opens() | |
| .iterator() | |
| .next(); | |
| } | |
| private Opens opens(String pn, String target) { | |
| return opens(Set.of(), pn, target); | |
| } | |
| public void testOpensOpens() { | |
| Opens o1 = opens("p"); | |
| ModuleDescriptor descriptor = ModuleDescriptor.newModule("m").opens(o1).build(); | |
| Opens o2 = descriptor.opens().iterator().next(); | |
| assertEquals(o1, o2); | |
| } | |
| public void testOpensToAll() { | |
| Opens o = opens("p"); | |
| assertEquals(o, o); | |
| assertTrue(o.modifiers().isEmpty()); | |
| assertEquals(o.source(), "p"); | |
| assertFalse(o.isQualified()); | |
| assertTrue(o.targets().isEmpty()); | |
| } | |
| public void testOpensToTarget() { | |
| Opens o = opens("p", "bar"); | |
| assertEquals(o, o); | |
| assertTrue(o.modifiers().isEmpty()); | |
| assertEquals(o.source(), "p"); | |
| assertTrue(o.isQualified()); | |
| assertTrue(o.targets().size() == 1); | |
| assertTrue(o.targets().contains("bar")); | |
| } | |
| public void testOpensToTargets() { | |
| Set<String> targets = new HashSet<>(); | |
| targets.add("bar"); | |
| targets.add("gus"); | |
| Opens o = ModuleDescriptor.newModule("foo") | |
| .opens("p", targets) | |
| .build() | |
| .opens() | |
| .iterator() | |
| .next(); | |
| assertEquals(o, o); | |
| assertTrue(o.modifiers().isEmpty()); | |
| assertEquals(o.source(), "p"); | |
| assertTrue(o.isQualified()); | |
| assertTrue(o.targets().size() == 2); | |
| assertTrue(o.targets().contains("bar")); | |
| assertTrue(o.targets().contains("gus")); | |
| } | |
| @Test(expectedExceptions = IllegalStateException.class) | |
| public void testOpensWithDuplicate1() { | |
| Opens o = opens("p"); | |
| ModuleDescriptor.newModule("foo").opens(o).opens(o); | |
| } | |
| @Test(expectedExceptions = IllegalStateException.class) | |
| public void testOpensWithDuplicate2() { | |
| ModuleDescriptor.newModule("foo").opens("p").opens("p"); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class ) | |
| public void testOpensWithEmptySet() { | |
| ModuleDescriptor.newModule("foo").opens("p", Collections.emptySet()); | |
| } | |
| @Test(dataProvider = "invalidNames", | |
| expectedExceptions = IllegalArgumentException.class ) | |
| public void testOpensWithBadName(String pn, String ignore) { | |
| ModuleDescriptor.newModule("foo").opens(pn); | |
| } | |
| @Test(expectedExceptions = NullPointerException.class ) | |
| public void testOpensWithNullExports() { | |
| ModuleDescriptor.newModule("foo").opens((Opens) null); | |
| } | |
| @Test(expectedExceptions = NullPointerException.class ) | |
| public void testOpensWithNullTargets() { | |
| ModuleDescriptor.newModule("foo").opens("p", (Set<String>) null); | |
| } | |
| public void testOpensCompare() { | |
| Opens o1 = opens("p"); | |
| Opens o2 = opens("p"); | |
| assertEquals(o1, o2); | |
| assertTrue(o1.hashCode() == o2.hashCode()); | |
| assertTrue(o1.compareTo(o2) == 0); | |
| assertTrue(o2.compareTo(o1) == 0); | |
| } | |
| public void testOpensCompareWithSameModifiers() { | |
| Opens o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); | |
| Opens o2 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); | |
| assertEquals(o1, o2); | |
| assertTrue(o1.hashCode() == o2.hashCode()); | |
| assertTrue(o1.compareTo(o2) == 0); | |
| assertTrue(o2.compareTo(o1) == 0); | |
| } | |
| public void testOpensCompareWithDifferentModifiers() { | |
| Opens o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); | |
| Opens o2 = opens("p"); | |
| assertNotEquals(o1, o2); | |
| assertTrue(o1.compareTo(o2) == 1); | |
| assertTrue(o2.compareTo(o1) == -1); | |
| } | |
| public void testOpensCompareWithSameTargets() { | |
| Opens o1 = opens("p", "x"); | |
| Opens o2 = opens("p", "x"); | |
| assertEquals(o1, o2); | |
| assertTrue(o1.hashCode() == o2.hashCode()); | |
| assertTrue(o1.compareTo(o2) == 0); | |
| assertTrue(o2.compareTo(o1) == 0); | |
| } | |
| public void testOpensCompareWithDifferentTargets() { | |
| Opens o1 = opens("p", "y"); | |
| Opens o2 = opens("p", "x"); | |
| assertNotEquals(o1, o2); | |
| assertTrue(o1.compareTo(o2) == 1); | |
| assertTrue(o2.compareTo(o1) == -1); | |
| } | |
| public void testOpensToString() { | |
| String s = ModuleDescriptor.newModule("foo") | |
| .opens("p1", Set.of("bar")) | |
| .build() | |
| .opens() | |
| .iterator() | |
| .next() | |
| .toString(); | |
| assertTrue(s.contains("p1")); | |
| assertTrue(s.contains("bar")); | |
| } | |
| // uses | |
| public void testUses() { | |
| Set<String> uses | |
| = ModuleDescriptor.newModule("foo") | |
| .uses("p.S") | |
| .uses("q.S") | |
| .build() | |
| .uses(); | |
| assertTrue(uses.size() == 2); | |
| assertTrue(uses.contains("p.S")); | |
| assertTrue(uses.contains("q.S")); | |
| } | |
| @Test(expectedExceptions = IllegalStateException.class) | |
| public void testUsesWithDuplicate() { | |
| ModuleDescriptor.newModule("foo").uses("p.S").uses("p.S"); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testUsesWithSimpleIdentifier() { | |
| ModuleDescriptor.newModule("foo").uses("S"); | |
| } | |
| @Test(dataProvider = "invalidNames", | |
| expectedExceptions = IllegalArgumentException.class ) | |
| public void testUsesWithBadName(String service, String ignore) { | |
| ModuleDescriptor.newModule("foo").uses(service); | |
| } | |
| // provides | |
| private Provides provides(String st, String pc) { | |
| return ModuleDescriptor.newModule("foo") | |
| .provides(st, List.of(pc)) | |
| .build() | |
| .provides() | |
| .iterator() | |
| .next(); | |
| } | |
| private Provides provides(String st, List<String> pns) { | |
| return ModuleDescriptor.newModule("foo") | |
| .provides(st, pns) | |
| .build() | |
| .provides() | |
| .iterator() | |
| .next(); | |
| } | |
| public void testProvidesWithProvides() { | |
| Provides p1 = provides("p.S", "q.S1"); | |
| ModuleDescriptor descriptor = ModuleDescriptor.newModule("m") | |
| .provides(p1) | |
| .build(); | |
| Provides p2 = descriptor.provides().iterator().next(); | |
| assertEquals(p1, p2); | |
| } | |
| public void testProvides() { | |
| Set<Provides> set = ModuleDescriptor.newModule("foo") | |
| .provides("p.S", List.of("q.P1", "q.P2")) | |
| .build() | |
| .provides(); | |
| assertTrue(set.size() == 1); | |
| Provides p = set.iterator().next(); | |
| assertEquals(p, p); | |
| assertEquals(p.service(), "p.S"); | |
| assertTrue(p.providers().size() == 2); | |
| assertEquals(p.providers().get(0), "q.P1"); | |
| assertEquals(p.providers().get(1), "q.P2"); | |
| } | |
| @Test(expectedExceptions = IllegalStateException.class ) | |
| public void testProvidesWithDuplicateProvides() { | |
| Provides p = provides("p.S", "q.S2"); | |
| ModuleDescriptor.newModule("m").provides("p.S", List.of("q.S1")).provides(p); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class ) | |
| public void testProvidesWithEmptySet() { | |
| ModuleDescriptor.newModule("foo").provides("p.Service", Collections.emptyList()); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class ) | |
| public void testProvidesWithSimpleIdentifier1() { | |
| ModuleDescriptor.newModule("foo").provides("S", List.of("q.P")); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class ) | |
| public void testProvidesWithSimpleIdentifier2() { | |
| ModuleDescriptor.newModule("foo").provides("p.S", List.of("P")); | |
| } | |
| @Test(dataProvider = "invalidNames", | |
| expectedExceptions = IllegalArgumentException.class ) | |
| public void testProvidesWithBadService(String service, String ignore) { | |
| ModuleDescriptor.newModule("foo").provides(service, List.of("p.Provider")); | |
| } | |
| @Test(dataProvider = "invalidNames", | |
| expectedExceptions = IllegalArgumentException.class ) | |
| public void testProvidesWithBadProvider(String provider, String ignore) { | |
| List<String> names = new ArrayList<>(); // allows nulls | |
| names.add(provider); | |
| ModuleDescriptor.newModule("foo").provides("p.Service", names); | |
| } | |
| @Test(expectedExceptions = NullPointerException.class ) | |
| public void testProvidesWithNullProvides() { | |
| ModuleDescriptor.newModule("foo").provides((Provides) null); | |
| } | |
| @Test(expectedExceptions = NullPointerException.class ) | |
| public void testProvidesWithNullProviders() { | |
| ModuleDescriptor.newModule("foo").provides("p.S", (List<String>) null); | |
| } | |
| public void testProvidesCompare() { | |
| Provides p1 = provides("p.S", "q.S1"); | |
| Provides p2 = provides("p.S", "q.S1"); | |
| assertEquals(p1, p2); | |
| assertTrue(p1.hashCode() == p2.hashCode()); | |
| assertTrue(p1.compareTo(p2) == 0); | |
| assertTrue(p2.compareTo(p1) == 0); | |
| } | |
| public void testProvidesCompareWithDifferentService() { | |
| Provides p1 = provides("p.S2", "q.S1"); | |
| Provides p2 = provides("p.S1", "q.S1"); | |
| assertNotEquals(p1, p2); | |
| assertTrue(p1.compareTo(p2) == 1); | |
| assertTrue(p2.compareTo(p1) == -1); | |
| } | |
| public void testProvidesCompareWithDifferentProviders1() { | |
| Provides p1 = provides("p.S", "q.S2"); | |
| Provides p2 = provides("p.S", "q.S1"); | |
| assertNotEquals(p1, p2); | |
| assertTrue(p1.compareTo(p2) == 1); | |
| assertTrue(p2.compareTo(p1) == -1); | |
| } | |
| public void testProvidesCompareWithDifferentProviders2() { | |
| Provides p1 = provides("p.S", List.of("q.S1", "q.S2")); | |
| Provides p2 = provides("p.S", "q.S1"); | |
| assertNotEquals(p1, p2); | |
| assertTrue(p1.compareTo(p2) == 1); | |
| assertTrue(p2.compareTo(p1) == -1); | |
| } | |
| // packages | |
| public void testPackages1() { | |
| Set<String> packages = ModuleDescriptor.newModule("foo") | |
| .packages(Set.of("p", "q")) | |
| .build() | |
| .packages(); | |
| assertTrue(packages.size() == 2); | |
| assertTrue(packages.contains("p")); | |
| assertTrue(packages.contains("q")); | |
| } | |
| public void testPackages2() { | |
| Set<String> packages = ModuleDescriptor.newModule("foo") | |
| .packages(Set.of("p")) | |
| .packages(Set.of("q")) | |
| .build() | |
| .packages(); | |
| assertTrue(packages.size() == 2); | |
| assertTrue(packages.contains("p")); | |
| assertTrue(packages.contains("q")); | |
| } | |
| public void testPackagesWithEmptySet() { | |
| Set<String> packages = ModuleDescriptor.newModule("foo") | |
| .packages(Collections.emptySet()) | |
| .build() | |
| .packages(); | |
| assertTrue(packages.size() == 0); | |
| } | |
| public void testPackagesDuplicate() { | |
| Set<String> packages = ModuleDescriptor.newModule("foo") | |
| .packages(Set.of("p")) | |
| .packages(Set.of("p")) | |
| .build() | |
| .packages(); | |
| assertTrue(packages.size() == 1); | |
| assertTrue(packages.contains("p")); | |
| } | |
| public void testPackagesAndExportsPackage1() { | |
| Set<String> packages = ModuleDescriptor.newModule("foo") | |
| .packages(Set.of("p")) | |
| .exports("p") | |
| .build() | |
| .packages(); | |
| assertTrue(packages.size() == 1); | |
| assertTrue(packages.contains("p")); | |
| } | |
| public void testPackagesAndExportsPackage2() { | |
| Set<String> packages = ModuleDescriptor.newModule("foo") | |
| .exports("p") | |
| .packages(Set.of("p")) | |
| .build() | |
| .packages(); | |
| assertTrue(packages.size() == 1); | |
| assertTrue(packages.contains("p")); | |
| } | |
| public void testPackagesAndOpensPackage1() { | |
| Set<String> packages = ModuleDescriptor.newModule("foo") | |
| .packages(Set.of("p")) | |
| .opens("p") | |
| .build() | |
| .packages(); | |
| assertTrue(packages.size() == 1); | |
| assertTrue(packages.contains("p")); | |
| } | |
| public void testPackagesAndOpensPackage2() { | |
| Set<String> packages = ModuleDescriptor.newModule("foo") | |
| .opens("p") | |
| .packages(Set.of("p")) | |
| .build() | |
| .packages(); | |
| assertTrue(packages.size() == 1); | |
| assertTrue(packages.contains("p")); | |
| } | |
| public void testPackagesAndProvides1() { | |
| Set<String> packages = ModuleDescriptor.newModule("foo") | |
| .packages(Set.of("p")) | |
| .provides("q.S", List.of("p.T")) | |
| .build() | |
| .packages(); | |
| assertTrue(packages.size() == 1); | |
| assertTrue(packages.contains("p")); | |
| } | |
| public void testPackagesAndProvides2() { | |
| Set<String> packages = ModuleDescriptor.newModule("foo") | |
| .provides("q.S", List.of("p.T")) | |
| .packages(Set.of("p")) | |
| .build() | |
| .packages(); | |
| assertTrue(packages.size() == 1); | |
| assertTrue(packages.contains("p")); | |
| } | |
| public void testPackagesAndMainClass1() { | |
| Set<String> packages = ModuleDescriptor.newModule("foo") | |
| .packages(Set.of("p")) | |
| .mainClass("p.Main") | |
| .build() | |
| .packages(); | |
| assertTrue(packages.size() == 1); | |
| assertTrue(packages.contains("p")); | |
| } | |
| public void testPackagesAndMainClass2() { | |
| Set<String> packages = ModuleDescriptor.newModule("foo") | |
| .mainClass("p.Main") | |
| .packages(Set.of("p")) | |
| .build() | |
| .packages(); | |
| assertTrue(packages.size() == 1); | |
| assertTrue(packages.contains("p")); | |
| } | |
| public void testPackagesAndAll() { | |
| Set<String> packages = ModuleDescriptor.newModule("foo") | |
| .exports("p1") | |
| .opens("p2") | |
| .packages(Set.of("p3")) | |
| .provides("q.S", List.of("p4.T")) | |
| .mainClass("p5.Main") | |
| .build() | |
| .packages(); | |
| assertTrue(Objects.equals(packages, Set.of("p1", "p2", "p3", "p4", "p5"))); | |
| } | |
| @Test(dataProvider = "invalidNames", | |
| expectedExceptions = IllegalArgumentException.class ) | |
| public void testPackagesWithBadName(String pn, String ignore) { | |
| Set<String> pkgs = new HashSet<>(); // allows nulls | |
| pkgs.add(pn); | |
| ModuleDescriptor.newModule("foo").packages(pkgs); | |
| } | |
| // name | |
| public void testModuleName() { | |
| String mn = ModuleDescriptor.newModule("foo").build().name(); | |
| assertEquals(mn, "foo"); | |
| } | |
| @Test(dataProvider = "invalidNames", | |
| expectedExceptions = IllegalArgumentException.class ) | |
| public void testBadModuleName(String mn, String ignore) { | |
| ModuleDescriptor.newModule(mn); | |
| } | |
| // version | |
| public void testVersion1() { | |
| Version v1 = Version.parse("1.0"); | |
| Version v2 = ModuleDescriptor.newModule("foo") | |
| .version(v1) | |
| .build() | |
| .version() | |
| .get(); | |
| assertEquals(v1, v2); | |
| } | |
| public void testVersion2() { | |
| String vs = "1.0"; | |
| Version v1 = ModuleDescriptor.newModule("foo") | |
| .version(vs) | |
| .build() | |
| .version() | |
| .get(); | |
| Version v2 = Version.parse(vs); | |
| assertEquals(v1, v2); | |
| } | |
| @Test(expectedExceptions = NullPointerException.class ) | |
| public void testNullVersion1() { | |
| ModuleDescriptor.newModule("foo").version((Version) null); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class ) | |
| public void testNullVersion2() { | |
| ModuleDescriptor.newModule("foo").version((String) null); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class ) | |
| public void testEmptyVersion() { | |
| ModuleDescriptor.newModule("foo").version(""); | |
| } | |
| @DataProvider(name = "unparseableVersions") | |
| public Object[][] unparseableVersions() { | |
| return new Object[][]{ | |
| { null, "A1" }, // no version < unparseable | |
| { "A1", "A2" }, // unparseable < unparseable | |
| { "A1", "1.0" }, // unparseable < parseable | |
| }; | |
| } | |
| /** | |
| * Basic test for unparseable module versions | |
| */ | |
| @Test(dataProvider = "unparseableVersions") | |
| public void testUnparseableModuleVersion(String vs1, String vs2) { | |
| ModuleDescriptor descriptor1 = newModule("m", vs1); | |
| ModuleDescriptor descriptor2 = newModule("m", vs2); | |
| if (vs1 != null && !isParsableVersion(vs1)) { | |
| assertFalse(descriptor1.version().isPresent()); | |
| assertTrue(descriptor1.rawVersion().isPresent()); | |
| assertEquals(descriptor1.rawVersion().get(), vs1); | |
| } | |
| if (vs2 != null && !isParsableVersion(vs2)) { | |
| assertFalse(descriptor2.version().isPresent()); | |
| assertTrue(descriptor2.rawVersion().isPresent()); | |
| assertEquals(descriptor2.rawVersion().get(), vs2); | |
| } | |
| assertFalse(descriptor1.equals(descriptor2)); | |
| assertFalse(descriptor2.equals(descriptor1)); | |
| assertTrue(descriptor1.compareTo(descriptor2) == -1); | |
| assertTrue(descriptor2.compareTo(descriptor1) == 1); | |
| } | |
| /** | |
| * Basic test for requiring a module with an unparseable version recorded | |
| * at compile version. | |
| */ | |
| @Test(dataProvider = "unparseableVersions") | |
| public void testUnparseableCompiledVersion(String vs1, String vs2) { | |
| Requires r1 = newRequires("m", vs1); | |
| Requires r2 = newRequires("m", vs2); | |
| if (vs1 != null && !isParsableVersion(vs1)) { | |
| assertFalse(r1.compiledVersion().isPresent()); | |
| assertTrue(r1.rawCompiledVersion().isPresent()); | |
| assertEquals(r1.rawCompiledVersion().get(), vs1); | |
| } | |
| if (vs2 != null && !isParsableVersion(vs2)) { | |
| assertFalse(r2.compiledVersion().isPresent()); | |
| assertTrue(r2.rawCompiledVersion().isPresent()); | |
| assertEquals(r2.rawCompiledVersion().get(), vs2); | |
| } | |
| assertFalse(r1.equals(r2)); | |
| assertFalse(r2.equals(r1)); | |
| assertTrue(r1.compareTo(r2) == -1); | |
| assertTrue(r2.compareTo(r1) == 1); | |
| } | |
| private ModuleDescriptor newModule(String name, String vs) { | |
| Builder builder = JLMA.newModuleBuilder(name, false, Set.of()); | |
| if (vs != null) | |
| builder.version(vs); | |
| builder.requires("java.base"); | |
| ByteBuffer bb = ModuleInfoWriter.toByteBuffer(builder.build()); | |
| return ModuleDescriptor.read(bb); | |
| } | |
| private Requires newRequires(String name, String vs) { | |
| Builder builder = JLMA.newModuleBuilder("foo", false, Set.of()); | |
| if (vs == null) { | |
| builder.requires(name); | |
| } else { | |
| JLMA.requires(builder, Set.of(), name, vs); | |
| } | |
| Set<ModuleDescriptor.Requires> requires = builder.build().requires(); | |
| Iterator<ModuleDescriptor.Requires> iterator = requires.iterator(); | |
| ModuleDescriptor.Requires r = iterator.next(); | |
| if (r.name().equals("java.base")) { | |
| r = iterator.next(); | |
| } | |
| return r; | |
| } | |
| private boolean isParsableVersion(String vs) { | |
| try { | |
| Version.parse(vs); | |
| return true; | |
| } catch (IllegalArgumentException e) { | |
| return false; | |
| } | |
| } | |
| // toNameAndVersion | |
| public void testToNameAndVersion() { | |
| ModuleDescriptor md1 = ModuleDescriptor.newModule("foo").build(); | |
| assertEquals(md1.toNameAndVersion(), "foo"); | |
| ModuleDescriptor md2 = ModuleDescriptor.newModule("foo").version("1.0").build(); | |
| assertEquals(md2.toNameAndVersion(), "foo@1.0"); | |
| } | |
| // open modules | |
| public void testOpenModule() { | |
| ModuleDescriptor descriptor = ModuleDescriptor.newOpenModule("foo") | |
| .requires("bar") | |
| .exports("p") | |
| .provides("p.Service", List.of("q.ServiceImpl")) | |
| .build(); | |
| // modifiers | |
| assertTrue(descriptor.modifiers().contains(ModuleDescriptor.Modifier.OPEN)); | |
| assertTrue(descriptor.isOpen()); | |
| // requires | |
| assertTrue(descriptor.requires().size() == 2); | |
| Set<String> names = descriptor.requires() | |
| .stream() | |
| .map(Requires::name) | |
| .collect(Collectors.toSet()); | |
| assertEquals(names, Set.of("bar", "java.base")); | |
| // packages | |
| assertEquals(descriptor.packages(), Set.of("p", "q")); | |
| // exports | |
| assertTrue(descriptor.exports().size() == 1); | |
| names = descriptor.exports() | |
| .stream() | |
| .map(Exports::source) | |
| .collect(Collectors.toSet()); | |
| assertEquals(names, Set.of("p")); | |
| // opens | |
| assertTrue(descriptor.opens().isEmpty()); | |
| } | |
| @Test(expectedExceptions = IllegalStateException.class) | |
| public void testOpensOnOpenModule1() { | |
| ModuleDescriptor.newOpenModule("foo").opens("p"); | |
| } | |
| @Test(expectedExceptions = IllegalStateException.class) | |
| public void testOpensOnOpenModule2() { | |
| ModuleDescriptor.newOpenModule("foo").opens("p", Set.of("bar")); | |
| } | |
| public void testIsOpen() { | |
| assertFalse(ModuleDescriptor.newModule("m").build().isOpen()); | |
| assertFalse(ModuleDescriptor.newAutomaticModule("m").build().isOpen()); | |
| assertTrue(ModuleDescriptor.newOpenModule("m").build().isOpen()); | |
| } | |
| // automatic modules | |
| public void testAutomaticModule() { | |
| ModuleDescriptor descriptor = ModuleDescriptor.newAutomaticModule("foo") | |
| .packages(Set.of("p")) | |
| .provides("p.Service", List.of("q.ServiceImpl")) | |
| .build(); | |
| // modifiers | |
| assertTrue(descriptor.modifiers().contains(ModuleDescriptor.Modifier.AUTOMATIC)); | |
| assertTrue(descriptor.isAutomatic()); | |
| // requires | |
| assertTrue(descriptor.requires().size() == 1); | |
| Set<String> names = descriptor.requires() | |
| .stream() | |
| .map(Requires::name) | |
| .collect(Collectors.toSet()); | |
| assertEquals(names, Set.of("java.base")); | |
| // packages | |
| assertEquals(descriptor.packages(), Set.of("p", "q")); | |
| assertTrue(descriptor.exports().isEmpty()); | |
| assertTrue(descriptor.opens().isEmpty()); | |
| } | |
| @Test(expectedExceptions = IllegalStateException.class) | |
| public void testRequiresOnAutomaticModule() { | |
| ModuleDescriptor.newAutomaticModule("foo").requires("java.base"); | |
| } | |
| @Test(expectedExceptions = IllegalStateException.class) | |
| public void testExportsOnAutomaticModule1() { | |
| ModuleDescriptor.newAutomaticModule("foo").exports("p"); | |
| } | |
| @Test(expectedExceptions = IllegalStateException.class) | |
| public void testExportsOnAutomaticModule2() { | |
| ModuleDescriptor.newAutomaticModule("foo").exports("p", Set.of("bar")); | |
| } | |
| @Test(expectedExceptions = IllegalStateException.class) | |
| public void testOpensOnAutomaticModule1() { | |
| ModuleDescriptor.newAutomaticModule("foo").opens("p"); | |
| } | |
| @Test(expectedExceptions = IllegalStateException.class) | |
| public void testOpensOnAutomaticModule2() { | |
| ModuleDescriptor.newAutomaticModule("foo").opens("p", Set.of("bar")); | |
| } | |
| @Test(expectedExceptions = IllegalStateException.class) | |
| public void testUsesOnAutomaticModule() { | |
| ModuleDescriptor.newAutomaticModule("foo").uses("p.Service"); | |
| } | |
| public void testIsAutomatic() { | |
| ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("foo").build(); | |
| assertFalse(descriptor1.isAutomatic()); | |
| ModuleDescriptor descriptor2 = ModuleDescriptor.newOpenModule("foo").build(); | |
| assertFalse(descriptor2.isAutomatic()); | |
| ModuleDescriptor descriptor3 = ModuleDescriptor.newAutomaticModule("foo").build(); | |
| assertTrue(descriptor3.isAutomatic()); | |
| } | |
| // newModule with modifiers | |
| public void testNewModuleToBuildAutomaticModule() { | |
| Set<ModuleDescriptor.Modifier> ms = Set.of(ModuleDescriptor.Modifier.AUTOMATIC); | |
| ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo", ms).build(); | |
| assertTrue(descriptor.modifiers().equals(ms)); | |
| assertTrue(descriptor.isAutomatic()); | |
| } | |
| public void testNewModuleToBuildOpenModule() { | |
| Set<ModuleDescriptor.Modifier> ms = Set.of(ModuleDescriptor.Modifier.OPEN); | |
| ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo", ms).build(); | |
| assertTrue(descriptor.modifiers().equals(ms)); | |
| assertTrue(descriptor.isOpen()); | |
| ms = Set.of(ModuleDescriptor.Modifier.OPEN, ModuleDescriptor.Modifier.SYNTHETIC); | |
| descriptor = ModuleDescriptor.newModule("foo", ms).build(); | |
| assertTrue(descriptor.modifiers().equals(ms)); | |
| assertTrue(descriptor.isOpen()); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testNewModuleToBuildAutomaticAndOpenModule() { | |
| Set<ModuleDescriptor.Modifier> ms = Set.of(ModuleDescriptor.Modifier.AUTOMATIC, | |
| ModuleDescriptor.Modifier.OPEN); | |
| ModuleDescriptor.newModule("foo", ms); | |
| } | |
| // mainClass | |
| public void testMainClass() { | |
| String mainClass | |
| = ModuleDescriptor.newModule("foo").mainClass("p.Main").build().mainClass().get(); | |
| assertEquals(mainClass, "p.Main"); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testMainClassWithSimpleIdentifier() { | |
| ModuleDescriptor.newModule("foo").mainClass("Main"); | |
| } | |
| @Test(dataProvider = "invalidNames", | |
| expectedExceptions = IllegalArgumentException.class ) | |
| public void testMainClassWithBadName(String mainClass, String ignore) { | |
| Builder builder = ModuleDescriptor.newModule("foo"); | |
| builder.mainClass(mainClass); | |
| } | |
| // reads | |
| private static InputStream EMPTY_INPUT_STREAM = new InputStream() { | |
| @Override | |
| public int read() { | |
| return -1; | |
| } | |
| }; | |
| private static InputStream FAILING_INPUT_STREAM = new InputStream() { | |
| @Override | |
| public int read() throws IOException { | |
| throw new IOException(); | |
| } | |
| }; | |
| /** | |
| * Basic test reading module-info.class | |
| */ | |
| public void testRead() throws Exception { | |
| Module base = Object.class.getModule(); | |
| try (InputStream in = base.getResourceAsStream("module-info.class")) { | |
| ModuleDescriptor descriptor = ModuleDescriptor.read(in); | |
| assertTrue(in.read() == -1); // all bytes read | |
| assertEquals(descriptor.name(), "java.base"); | |
| } | |
| try (InputStream in = base.getResourceAsStream("module-info.class")) { | |
| ByteBuffer bb = ByteBuffer.wrap(in.readAllBytes()); | |
| ModuleDescriptor descriptor = ModuleDescriptor.read(bb); | |
| assertFalse(bb.hasRemaining()); // no more remaining bytes | |
| assertEquals(descriptor.name(), "java.base"); | |
| } | |
| } | |
| /** | |
| * Test ModuleDescriptor with a packager finder | |
| */ | |
| public void testReadsWithPackageFinder() throws Exception { | |
| ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo") | |
| .requires("java.base") | |
| .build(); | |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
| ModuleInfoWriter.write(descriptor, baos); | |
| ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray()); | |
| descriptor = ModuleDescriptor.read(bb, () -> Set.of("p", "q")); | |
| assertTrue(descriptor.packages().size() == 2); | |
| assertTrue(descriptor.packages().contains("p")); | |
| assertTrue(descriptor.packages().contains("q")); | |
| } | |
| /** | |
| * Test ModuleDescriptor with a packager finder that doesn't return the | |
| * complete set of packages. | |
| */ | |
| public void testReadsWithBadPackageFinder() throws Exception { | |
| ByteBuffer bb = ByteBuffer.wrap(ClassFile.of().buildModule( | |
| ModuleAttribute.of( | |
| ModuleDesc.of("foo"), | |
| mb -> mb.requires(ModuleDesc.of("java.base"), 0, null) | |
| .exports(PackageDesc.of("p"), 0)))); | |
| // package finder returns a set that doesn't include p | |
| assertThrows(InvalidModuleDescriptorException.class, | |
| () -> ModuleDescriptor.read(bb, () -> Set.of("q"))); | |
| } | |
| @Test(expectedExceptions = InvalidModuleDescriptorException.class) | |
| public void testReadFromEmptyInputStream() throws Exception { | |
| ModuleDescriptor.read(EMPTY_INPUT_STREAM); | |
| } | |
| @Test(expectedExceptions = IOException.class) | |
| public void testReadFromFailingInputStream() throws Exception { | |
| ModuleDescriptor.read(FAILING_INPUT_STREAM); | |
| } | |
| @Test(expectedExceptions = InvalidModuleDescriptorException.class) | |
| public void testReadFromEmptyBuffer() { | |
| ByteBuffer bb = ByteBuffer.allocate(0); | |
| ModuleDescriptor.read(bb); | |
| } | |
| /** | |
| * Test ModuleDescriptor.read reading a module-info for java.base that has a non-0 | |
| * length requires table. | |
| */ | |
| public void testReadOfJavaBaseWithRequires() { | |
| ModuleDescriptor descriptor = ModuleDescriptor.newModule("java.base") | |
| .requires("other") | |
| .build(); | |
| ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor); | |
| assertThrows(InvalidModuleDescriptorException.class, | |
| () -> ModuleDescriptor.read(bb)); | |
| } | |
| /** | |
| * Test ModuleDescriptor.read reading a module-info with a zero length requires table | |
| * (no entry for java.base). | |
| */ | |
| public void testReadWithEmptyRequires() { | |
| // use non-strict builder to create module that does not require java.base | |
| ModuleDescriptor descriptor = JLMA.newModuleBuilder("m", false, Set.of()).build(); | |
| ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor); | |
| assertThrows(InvalidModuleDescriptorException.class, | |
| () -> ModuleDescriptor.read(bb)); | |
| } | |
| /** | |
| * Test ModuleDescriptor.read reading a module-info with a non-zero length requires | |
| * table that does not have entry for java.base. | |
| */ | |
| public void testReadWithNoRequiresBase() { | |
| // use non-strict builder to create module that does not require java.base | |
| ModuleDescriptor descriptor = JLMA.newModuleBuilder("m1", false, Set.of()) | |
| .requires("m2") | |
| .build(); | |
| ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor); | |
| assertThrows(InvalidModuleDescriptorException.class, | |
| () -> ModuleDescriptor.read(bb)); | |
| } | |
| /** | |
| * Test ModuleDescriptor.read reading a module-info with a requires entry for | |
| * java.base with the ACC_SYNTHETIC flag set. | |
| */ | |
| public void testReadWithSynethticRequiresBase() { | |
| ModuleDescriptor descriptor = ModuleDescriptor.newModule("m") | |
| .requires(Set.of(SYNTHETIC), "java.base") | |
| .build(); | |
| ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor); | |
| assertThrows(InvalidModuleDescriptorException.class, | |
| () -> ModuleDescriptor.read(bb)); | |
| } | |
| /** | |
| * Test ModuleDescriptor.read with a null parameter. | |
| */ | |
| public void testReadWithNull() throws Exception { | |
| Module base = Object.class.getModule(); | |
| assertThrows(NullPointerException.class, | |
| () -> ModuleDescriptor.read((InputStream) null)); | |
| assertThrows(NullPointerException.class, | |
| () -> ModuleDescriptor.read((ByteBuffer) null)); | |
| try (InputStream in = base.getResourceAsStream("module-info.class")) { | |
| assertThrows(NullPointerException.class, | |
| () -> ModuleDescriptor.read(in, null)); | |
| ByteBuffer bb = ByteBuffer.wrap(in.readAllBytes()); | |
| assertThrows(NullPointerException.class, | |
| () -> ModuleDescriptor.read(bb, null)); | |
| } | |
| } | |
| // equals/hashCode/compareTo/toString | |
| public void testEqualsAndHashCode() { | |
| ModuleDescriptor md1 = ModuleDescriptor.newModule("m").build(); | |
| ModuleDescriptor md2 = ModuleDescriptor.newModule("m").build(); | |
| assertEquals(md1, md1); | |
| assertEquals(md1.hashCode(), md2.hashCode()); | |
| assertTrue(md1.compareTo(md2) == 0); | |
| assertTrue(md2.compareTo(md1) == 0); | |
| } | |
| @DataProvider(name = "sortedModuleDescriptors") | |
| public Object[][] sortedModuleDescriptors() { | |
| return new Object[][]{ | |
| { ModuleDescriptor.newModule("m2").build(), | |
| ModuleDescriptor.newModule("m1").build() | |
| }, | |
| { ModuleDescriptor.newModule("m").version("2").build(), | |
| ModuleDescriptor.newModule("m").version("1").build() | |
| }, | |
| { ModuleDescriptor.newModule("m").version("1").build(), | |
| ModuleDescriptor.newModule("m").build() | |
| }, | |
| { ModuleDescriptor.newOpenModule("m").build(), | |
| ModuleDescriptor.newModule("m").build() | |
| }, | |
| }; | |
| } | |
| @Test(dataProvider = "sortedModuleDescriptors") | |
| public void testCompare(ModuleDescriptor md1, ModuleDescriptor md2) { | |
| assertNotEquals(md1, md2); | |
| assertTrue(md1.compareTo(md2) == 1); | |
| assertTrue(md2.compareTo(md1) == -1); | |
| } | |
| public void testToString() { | |
| String s = ModuleDescriptor.newModule("m1") | |
| .requires("m2") | |
| .exports("p1") | |
| .build() | |
| .toString(); | |
| assertTrue(s.contains("m1")); | |
| assertTrue(s.contains("m2")); | |
| assertTrue(s.contains("p1")); | |
| } | |
| public void testRequiresTransitiveJavaBaseNotPermitted1() throws Exception { | |
| ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo") | |
| .requires(Set.of(Modifier.TRANSITIVE), "java.base") | |
| .build(); | |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
| ModuleInfoWriter.write(descriptor, baos); | |
| ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray()); | |
| ModuleDescriptor.read(bb, () -> Set.of("p", "q")); | |
| } | |
| public void testRequiresTransitiveJavaBaseNotPermitted2() throws Exception { | |
| ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo") | |
| .requires(Set.of(Modifier.TRANSITIVE), "java.base") | |
| .build(); | |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
| ModuleInfoWriter.write(descriptor, baos); | |
| byte[] bytecode = baos.toByteArray(); | |
| ByteBuffer bb = ByteBuffer.wrap(bytecode); | |
| setClassFileVersion(bb, ClassFile.JAVA_21_VERSION, -1); | |
| ModuleDescriptor.read(bb, () -> Set.of("p", "q")); | |
| } | |
| public void testRequiresTransitiveJavaBasePermitted() throws Exception { | |
| ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo") | |
| .requires(Set.of(Modifier.TRANSITIVE), "java.base") | |
| .build(); | |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
| ModuleInfoWriter.write(descriptor, baos); | |
| byte[] bytecode = baos.toByteArray(); | |
| ByteBuffer bb = ByteBuffer.wrap(bytecode); | |
| setClassFileVersion(bb, -1, ClassFile.PREVIEW_MINOR_VERSION); | |
| descriptor = ModuleDescriptor.read(bb, () -> Set.of("p", "q")); | |
| assertEquals(descriptor.requires().size(), 1); | |
| Requires javaBase = descriptor.requires().iterator().next(); | |
| assertEquals(javaBase.name(), "java.base"); | |
| assertEquals(javaBase.modifiers(), Set.of(Modifier.TRANSITIVE)); | |
| } | |
| /**Change the classfile versions of the provided classfile to the provided | |
| * values. | |
| * | |
| * @param bytecode the classfile content to modify | |
| * @param major the major classfile version to set, | |
| * -1 if the existing version should be kept | |
| * @param minor the minor classfile version to set, | |
| * -1 if the existing version should be kept | |
| */ | |
| private void setClassFileVersion(ByteBuffer bb, int major, int minor) { | |
| if (minor != (-1)) { | |
| bb.putShort(4, (short) minor); | |
| } | |
| if (major != (-1)) { | |
| bb.putShort(6, (short) major); | |
| } | |
| } | |
| } |