| /* | |
| * Copyright (c) 2016, 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 | |
| * @modules java.base/jdk.internal.access | |
| * java.base/jdk.internal.module | |
| * @library /test/lib | |
| * @build jdk.test.lib.util.ModuleInfoWriter | |
| * @run testng ModuleNamesTest | |
| * @summary Basic test of reading a module-info.class with module names that | |
| * are legal in class files but not legal in the Java Language | |
| */ | |
| import java.io.ByteArrayOutputStream; | |
| 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.nio.ByteBuffer; | |
| import java.util.Optional; | |
| import java.util.Set; | |
| import jdk.internal.access.SharedSecrets; | |
| import jdk.test.lib.util.ModuleInfoWriter; | |
| import org.testng.annotations.DataProvider; | |
| import org.testng.annotations.Test; | |
| import static org.testng.Assert.*; | |
| @Test | |
| public class ModuleNamesTest { | |
| @DataProvider(name = "legalModuleNames") | |
| public Object[][] legalModuleNames() { | |
| return new Object[][] { | |
| { ".", "." }, | |
| { ".foo", ".foo" }, | |
| { "foo.", "foo." }, | |
| { "foo.bar", "foo.bar" }, | |
| { "..", ".." }, | |
| { "..foo", "..foo" }, | |
| { "foo..", "foo.." }, | |
| { "foo..bar", "foo..bar" }, | |
| { "[", "[" }, | |
| { "[foo", "[foo" }, | |
| { "foo[", "foo[" }, | |
| { "foo[bar", "foo[bar" }, | |
| { ";", ";" }, | |
| { ";foo", ";foo" }, | |
| { "foo;", "foo;" }, | |
| { "foo;bar", "foo;bar" }, | |
| { "\\\\", "\\" }, | |
| { "\\\\foo", "\\foo" }, | |
| { "foo\\\\", "foo\\" }, | |
| { "foo\\\\bar", "foo\\bar" }, | |
| { "\\\\\\\\", "\\\\" }, | |
| { "\\\\\\\\foo", "\\\\foo" }, | |
| { "foo\\\\\\\\", "foo\\\\" }, | |
| { "foo\\\\\\\\bar", "foo\\\\bar" }, | |
| { "\\:", ":" }, | |
| { "\\:foo", ":foo" }, | |
| { "foo\\:", "foo:" }, | |
| { "foo\\:bar", "foo:bar" }, | |
| { "\\:\\:", "::" }, | |
| { "\\:\\:foo", "::foo" }, | |
| { "foo\\:\\:", "foo::" }, | |
| { "foo\\:\\:bar", "foo::bar" }, | |
| { "\\@", "@" }, | |
| { "\\@foo", "@foo" }, | |
| { "foo\\@", "foo@" }, | |
| { "foo\\@bar", "foo@bar" }, | |
| { "\\@\\@", "@@" }, | |
| { "\\@\\@foo", "@@foo" }, | |
| { "foo\\@\\@", "foo@@" }, | |
| { "foo\\@\\@bar", "foo@@bar" }, | |
| { makeString("", 0x20, ""), " " }, | |
| { makeString("foo", 0x20, ""), "foo " }, | |
| { makeString("", 0x20, "foo"), " foo" }, | |
| { makeString("foo", 0x20, "bar"), "foo bar" }, | |
| }; | |
| } | |
| @DataProvider(name = "illegalModuleNames") | |
| public Object[][] illegalModuleNames() { | |
| return new Object[][] { | |
| { "", null }, | |
| { ":", null }, | |
| { ":foo", null }, | |
| { "foo:", null }, | |
| { "foo:bar", null }, | |
| { "@", null }, | |
| { "@foo", null }, | |
| { "foo@", null }, | |
| { "foo@bar", null }, | |
| { "\\", null }, | |
| { "\\foo", null }, | |
| { "foo\\", null }, | |
| { "foo\\bar", null }, | |
| { makeString("", 0x00, ""), null }, | |
| { makeString("", 0x00, "foo"), null }, | |
| { makeString("foo", 0x00, ""), null }, | |
| { makeString("foo", 0x00, "bar"), null }, | |
| { makeString("", 0x1f, ""), null }, | |
| { makeString("", 0x1f, "foo"), null }, | |
| { makeString("foo", 0x1f, ""), null }, | |
| { makeString("foo", 0x1f, "bar"), null }, | |
| }; | |
| } | |
| @Test(dataProvider = "legalModuleNames") | |
| public void testLegalModuleName(String mn, String expected) throws Exception { | |
| ModuleDescriptor md = newBuilder(mn).requires("java.base").build(); | |
| ByteBuffer bb = toBuffer(md); | |
| String name = ModuleDescriptor.read(bb).name(); | |
| assertEquals(name, expected); | |
| } | |
| @Test(dataProvider = "illegalModuleNames", | |
| expectedExceptions = InvalidModuleDescriptorException.class) | |
| public void testIllegalModuleName(String mn, String ignore) throws Exception { | |
| ModuleDescriptor md = newBuilder(mn).requires("java.base").build(); | |
| ByteBuffer bb = toBuffer(md); | |
| ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException | |
| } | |
| @Test(dataProvider = "legalModuleNames") | |
| public void testLegalRequires(String mn, String expected) throws Exception { | |
| ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build(); | |
| ByteBuffer bb = toBuffer(md); | |
| ModuleDescriptor descriptor = ModuleDescriptor.read(bb); | |
| Optional<Requires> requires = descriptor.requires().stream() | |
| .filter(r -> !r.name().equals("java.base")) | |
| .findAny(); | |
| assertTrue(requires.isPresent()); | |
| assertEquals(requires.get().name(), expected); | |
| } | |
| @Test(dataProvider = "illegalModuleNames", | |
| expectedExceptions = InvalidModuleDescriptorException.class) | |
| public void testIllegalRequires(String mn, String ignore) throws Exception { | |
| ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build(); | |
| ByteBuffer bb = toBuffer(md); | |
| ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException | |
| } | |
| @Test(dataProvider = "legalModuleNames") | |
| public void testLegalExports(String mn, String expected) throws Exception { | |
| ModuleDescriptor md = newBuilder("m") | |
| .requires("java.base") | |
| .exports("p", Set.of(mn)) | |
| .build(); | |
| ByteBuffer bb = toBuffer(md); | |
| ModuleDescriptor descriptor = ModuleDescriptor.read(bb); | |
| Optional<Exports> export = descriptor.exports().stream().findAny(); | |
| assertTrue(export.isPresent()); | |
| assertTrue(export.get().targets().contains(expected)); | |
| } | |
| @Test(dataProvider = "illegalModuleNames", | |
| expectedExceptions = InvalidModuleDescriptorException.class) | |
| public void testIllegalExports(String mn, String ignore) throws Exception { | |
| ModuleDescriptor md = newBuilder("m") | |
| .requires("java.base") | |
| .exports("p", Set.of(mn)) | |
| .build(); | |
| ByteBuffer bb = toBuffer(md); | |
| ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException | |
| } | |
| @Test(dataProvider = "legalModuleNames") | |
| public void testLegalOpens(String mn, String expected) throws Exception { | |
| ModuleDescriptor md = newBuilder("m") | |
| .requires("java.base") | |
| .opens("p", Set.of(mn)) | |
| .build(); | |
| ByteBuffer bb = toBuffer(md); | |
| ModuleDescriptor descriptor = ModuleDescriptor.read(bb); | |
| Optional<Opens> opens = descriptor.opens().stream().findAny(); | |
| assertTrue(opens.isPresent()); | |
| assertTrue(opens.get().targets().contains(expected)); | |
| } | |
| @Test(dataProvider = "illegalModuleNames", | |
| expectedExceptions = InvalidModuleDescriptorException.class) | |
| public void testIllegalOpens(String mn, String ignore) throws Exception { | |
| ModuleDescriptor md = newBuilder("m") | |
| .requires("java.base") | |
| .opens("p", Set.of(mn)) | |
| .build(); | |
| ByteBuffer bb = toBuffer(md); | |
| ModuleDescriptor.read(bb); // throws InvalidModuleDescriptorException | |
| } | |
| /** | |
| * Returns a Builder that does not validate module names. | |
| */ | |
| private Builder newBuilder(String mn) { | |
| return SharedSecrets.getJavaLangModuleAccess() | |
| .newModuleBuilder(mn, false, Set.of()); | |
| } | |
| /** | |
| * Returns a {@code ByteBuffer} containing the given module descriptor | |
| * in module-info.class format. | |
| */ | |
| private ByteBuffer toBuffer(ModuleDescriptor descriptor) throws Exception { | |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
| ModuleInfoWriter.write(descriptor, baos); | |
| return ByteBuffer.wrap(baos.toByteArray()); | |
| } | |
| /** | |
| * Returns a string containing a given code point. | |
| */ | |
| private String makeString(String prefix, int codePoint, String suffix) { | |
| StringBuilder sb = new StringBuilder(); | |
| sb.append(prefix); | |
| sb.appendCodePoint(codePoint); | |
| sb.append(suffix); | |
| return sb.toString(); | |
| } | |
| } |