1 /*
  2  * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /**
 25  * @test
 26  * @modules java.base/jdk.internal.access
 27  *          java.base/jdk.internal.module
 28  * @library /test/lib
 29  * @run testng ModuleNamesTest
 30  * @summary Basic test of reading a module-info.class with module names that
 31  *          are legal in class files but not legal in the Java Language
 32  */
 33 
 34 import java.io.ByteArrayOutputStream;
 35 import java.lang.module.InvalidModuleDescriptorException;
 36 import java.lang.module.ModuleDescriptor;
 37 import java.lang.module.ModuleDescriptor.Builder;
 38 import java.lang.module.ModuleDescriptor.Exports;
 39 import java.lang.module.ModuleDescriptor.Opens;
 40 import java.lang.module.ModuleDescriptor.Requires;
 41 import java.nio.ByteBuffer;
 42 import java.util.Optional;
 43 import java.util.Set;
 44 
 45 import jdk.internal.access.SharedSecrets;
 46 
 47 import jdk.test.lib.util.ModuleInfoWriter;
 48 
 49 import org.testng.annotations.DataProvider;
 50 import org.testng.annotations.Test;
 51 import static org.testng.Assert.*;
 52 
 53 @Test
 54 public class ModuleNamesTest {
 55 
 56     @DataProvider(name = "legalModuleNames")
 57     public Object[][] legalModuleNames() {
 58         return new Object[][] {
 59 
 60                 { ".",              "." },
 61                 { ".foo",           ".foo" },
 62                 { "foo.",           "foo." },
 63                 { "foo.bar",        "foo.bar" },
 64 
 65                 { "..",             ".." },
 66                 { "..foo",          "..foo" },
 67                 { "foo..",          "foo.." },
 68                 { "foo..bar",       "foo..bar" },
 69 
 70                 { "[",              "[" },
 71                 { "[foo",           "[foo" },
 72                 { "foo[",           "foo[" },
 73                 { "foo[bar",        "foo[bar" },
 74 
 75                 { ";",              ";" },
 76                 { ";foo",           ";foo" },
 77                 { "foo;",           "foo;" },
 78                 { "foo;bar",        "foo;bar" },
 79 
 80                 { "\\\\",           "\\" },
 81                 { "\\\\foo",        "\\foo" },
 82                 { "foo\\\\",        "foo\\" },
 83                 { "foo\\\\bar",     "foo\\bar" },
 84 
 85                 { "\\\\\\\\",       "\\\\" },
 86                 { "\\\\\\\\foo",    "\\\\foo" },
 87                 { "foo\\\\\\\\",    "foo\\\\" },
 88                 { "foo\\\\\\\\bar", "foo\\\\bar" },
 89 
 90                 { "\\:",            ":" },
 91                 { "\\:foo",         ":foo" },
 92                 { "foo\\:",         "foo:" },
 93                 { "foo\\:bar",      "foo:bar" },
 94 
 95                 { "\\:\\:",         "::" },
 96                 { "\\:\\:foo",      "::foo" },
 97                 { "foo\\:\\:",      "foo::" },
 98                 { "foo\\:\\:bar",   "foo::bar" },
 99 
100                 { "\\@",            "@" },
101                 { "\\@foo",         "@foo" },
102                 { "foo\\@",         "foo@" },
103                 { "foo\\@bar",      "foo@bar" },
104 
105                 { "\\@\\@",         "@@" },
106                 { "\\@\\@foo",      "@@foo" },
107                 { "foo\\@\\@",      "foo@@" },
108                 { "foo\\@\\@bar",   "foo@@bar" },
109 
110                 { makeString("", 0x20, ""),        " "  },
111                 { makeString("foo", 0x20, ""),     "foo " },
112                 { makeString("", 0x20, "foo"),     " foo" },
113                 { makeString("foo", 0x20, "bar"),  "foo bar" },
114         };
115     }
116 
117     @DataProvider(name = "illegalModuleNames")
118     public Object[][] illegalModuleNames() {
119         return new Object[][] {
120 
121                 { "",               null },
122 
123                 { ":",              null },
124                 { ":foo",           null },
125                 { "foo:",           null },
126                 { "foo:bar",        null },
127 
128                 { "@",              null },
129                 { "@foo",           null },
130                 { "foo@",           null },
131                 { "foo@bar",        null },
132 
133                 { "\\",            null },
134                 { "\\foo",         null },
135                 { "foo\\",         null },
136                 { "foo\\bar",      null },
137 
138                 { makeString("", 0x00, ""),         null },
139                 { makeString("", 0x00, "foo"),      null },
140                 { makeString("foo", 0x00, ""),      null },
141                 { makeString("foo", 0x00, "bar"),   null },
142 
143                 { makeString("", 0x1f, ""),         null },
144                 { makeString("", 0x1f, "foo"),      null },
145                 { makeString("foo", 0x1f, ""),      null },
146                 { makeString("foo", 0x1f, "bar"),   null },
147 
148         };
149     }
150 
151     @Test(dataProvider = "legalModuleNames")
152     public void testLegalModuleName(String mn, String expected) throws Exception {
153         ModuleDescriptor md = newBuilder(mn).requires("java.base").build();
154         ByteBuffer bb = toBuffer(md);
155         String name = ModuleDescriptor.read(bb).name();
156         assertEquals(name, expected);
157     }
158 
159     @Test(dataProvider = "illegalModuleNames",
160           expectedExceptions = InvalidModuleDescriptorException.class)
161     public void testIllegalModuleName(String mn, String ignore) throws Exception {
162         ModuleDescriptor md = newBuilder(mn).requires("java.base").build();
163         ByteBuffer bb = toBuffer(md);
164         ModuleDescriptor.read(bb);  // throws InvalidModuleDescriptorException
165     }
166 
167     @Test(dataProvider = "legalModuleNames")
168     public void testLegalRequires(String mn, String expected) throws Exception {
169         ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build();
170         ByteBuffer bb = toBuffer(md);
171         ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
172         Optional<Requires> requires = descriptor.requires().stream()
173                 .filter(r -> !r.name().equals("java.base"))
174                 .findAny();
175         assertTrue(requires.isPresent());
176         assertEquals(requires.get().name(), expected);
177     }
178 
179     @Test(dataProvider = "illegalModuleNames",
180           expectedExceptions = InvalidModuleDescriptorException.class)
181     public void testIllegalRequires(String mn, String ignore) throws Exception {
182         ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build();
183         ByteBuffer bb = toBuffer(md);
184         ModuleDescriptor.read(bb);   // throws InvalidModuleDescriptorException
185     }
186 
187     @Test(dataProvider = "legalModuleNames")
188     public void testLegalExports(String mn, String expected) throws Exception {
189         ModuleDescriptor md = newBuilder("m")
190                 .requires("java.base")
191                 .exports("p", Set.of(mn))
192                 .build();
193         ByteBuffer bb = toBuffer(md);
194         ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
195         Optional<Exports> export = descriptor.exports().stream().findAny();
196         assertTrue(export.isPresent());
197         assertTrue(export.get().targets().contains(expected));
198     }
199 
200     @Test(dataProvider = "illegalModuleNames",
201           expectedExceptions = InvalidModuleDescriptorException.class)
202     public void testIllegalExports(String mn, String ignore) throws Exception {
203         ModuleDescriptor md = newBuilder("m")
204                 .requires("java.base")
205                 .exports("p", Set.of(mn))
206                 .build();
207         ByteBuffer bb = toBuffer(md);
208         ModuleDescriptor.read(bb);   // throws InvalidModuleDescriptorException
209     }
210 
211     @Test(dataProvider = "legalModuleNames")
212     public void testLegalOpens(String mn, String expected) throws Exception {
213         ModuleDescriptor md = newBuilder("m")
214                 .requires("java.base")
215                 .opens("p", Set.of(mn))
216                 .build();
217         ByteBuffer bb = toBuffer(md);
218         ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
219         Optional<Opens> opens = descriptor.opens().stream().findAny();
220         assertTrue(opens.isPresent());
221         assertTrue(opens.get().targets().contains(expected));
222     }
223 
224     @Test(dataProvider = "illegalModuleNames",
225           expectedExceptions = InvalidModuleDescriptorException.class)
226     public void testIllegalOpens(String mn, String ignore) throws Exception {
227         ModuleDescriptor md = newBuilder("m")
228                 .requires("java.base")
229                 .opens("p", Set.of(mn))
230                 .build();
231         ByteBuffer bb = toBuffer(md);
232         ModuleDescriptor.read(bb);   // throws InvalidModuleDescriptorException
233     }
234 
235     /**
236      * Returns a Builder that does not validate module names.
237      */
238     private Builder newBuilder(String mn) {
239         return SharedSecrets.getJavaLangModuleAccess()
240                             .newModuleBuilder(mn, false, Set.of());
241     }
242 
243     /**
244      * Returns a {@code ByteBuffer} containing the given module descriptor
245      * in module-info.class format.
246      */
247     private ByteBuffer toBuffer(ModuleDescriptor descriptor) throws Exception {
248         ByteArrayOutputStream baos = new ByteArrayOutputStream();
249         ModuleInfoWriter.write(descriptor, baos);
250         return ByteBuffer.wrap(baos.toByteArray());
251     }
252 
253     /**
254      * Returns a string containing a given code point.
255      */
256     private String makeString(String prefix, int codePoint, String suffix) {
257         StringBuilder sb = new StringBuilder();
258         sb.append(prefix);
259         sb.appendCodePoint(codePoint);
260         sb.append(suffix);
261         return sb.toString();
262     }
263 }