1 /*
  2  * Copyright (c) 2016, 2023, 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  * @enablePreview
 27  * @modules java.base/jdk.internal.access
 28  *          java.base/jdk.internal.module
 29  * @library /test/lib
 30  * @run testng ModuleNamesTest
 31  * @summary Basic test of reading a module-info.class with module names that
 32  *          are legal in class files but not legal in the Java Language
 33  */
 34 
 35 import java.io.ByteArrayOutputStream;
 36 import java.lang.module.InvalidModuleDescriptorException;
 37 import java.lang.module.ModuleDescriptor;
 38 import java.lang.module.ModuleDescriptor.Builder;
 39 import java.lang.module.ModuleDescriptor.Exports;
 40 import java.lang.module.ModuleDescriptor.Opens;
 41 import java.lang.module.ModuleDescriptor.Requires;
 42 import java.nio.ByteBuffer;
 43 import java.util.Optional;
 44 import java.util.Set;
 45 
 46 import jdk.internal.access.SharedSecrets;
 47 
 48 import jdk.test.lib.util.ModuleInfoWriter;
 49 
 50 import org.testng.annotations.DataProvider;
 51 import org.testng.annotations.Test;
 52 import static org.testng.Assert.*;
 53 
 54 @Test
 55 public class ModuleNamesTest {
 56 
 57     @DataProvider(name = "legalModuleNames")
 58     public Object[][] legalModuleNames() {
 59         return new Object[][] {
 60 
 61                 { ".",              "." },
 62                 { ".foo",           ".foo" },
 63                 { "foo.",           "foo." },
 64                 { "foo.bar",        "foo.bar" },
 65 
 66                 { "..",             ".." },
 67                 { "..foo",          "..foo" },
 68                 { "foo..",          "foo.." },
 69                 { "foo..bar",       "foo..bar" },
 70 
 71                 { "[",              "[" },
 72                 { "[foo",           "[foo" },
 73                 { "foo[",           "foo[" },
 74                 { "foo[bar",        "foo[bar" },
 75 
 76                 { ";",              ";" },
 77                 { ";foo",           ";foo" },
 78                 { "foo;",           "foo;" },
 79                 { "foo;bar",        "foo;bar" },
 80 
 81                 { "\\\\",           "\\" },
 82                 { "\\\\foo",        "\\foo" },
 83                 { "foo\\\\",        "foo\\" },
 84                 { "foo\\\\bar",     "foo\\bar" },
 85 
 86                 { "\\\\\\\\",       "\\\\" },
 87                 { "\\\\\\\\foo",    "\\\\foo" },
 88                 { "foo\\\\\\\\",    "foo\\\\" },
 89                 { "foo\\\\\\\\bar", "foo\\\\bar" },
 90 
 91                 { "\\:",            ":" },
 92                 { "\\:foo",         ":foo" },
 93                 { "foo\\:",         "foo:" },
 94                 { "foo\\:bar",      "foo:bar" },
 95 
 96                 { "\\:\\:",         "::" },
 97                 { "\\:\\:foo",      "::foo" },
 98                 { "foo\\:\\:",      "foo::" },
 99                 { "foo\\:\\:bar",   "foo::bar" },
100 
101                 { "\\@",            "@" },
102                 { "\\@foo",         "@foo" },
103                 { "foo\\@",         "foo@" },
104                 { "foo\\@bar",      "foo@bar" },
105 
106                 { "\\@\\@",         "@@" },
107                 { "\\@\\@foo",      "@@foo" },
108                 { "foo\\@\\@",      "foo@@" },
109                 { "foo\\@\\@bar",   "foo@@bar" },
110 
111                 { makeString("", 0x20, ""),        " "  },
112                 { makeString("foo", 0x20, ""),     "foo " },
113                 { makeString("", 0x20, "foo"),     " foo" },
114                 { makeString("foo", 0x20, "bar"),  "foo bar" },
115         };
116     }
117 
118     @DataProvider(name = "illegalModuleNames")
119     public Object[][] illegalModuleNames() {
120         return new Object[][] {
121 
122                 { "",               null },
123 
124                 { ":",              null },
125                 { ":foo",           null },
126                 { "foo:",           null },
127                 { "foo:bar",        null },
128 
129                 { "@",              null },
130                 { "@foo",           null },
131                 { "foo@",           null },
132                 { "foo@bar",        null },
133 
134                 { "\\",            null },
135                 { "\\foo",         null },
136                 { "foo\\",         null },
137                 { "foo\\bar",      null },
138 
139                 { makeString("", 0x00, ""),         null },
140                 { makeString("", 0x00, "foo"),      null },
141                 { makeString("foo", 0x00, ""),      null },
142                 { makeString("foo", 0x00, "bar"),   null },
143 
144                 { makeString("", 0x1f, ""),         null },
145                 { makeString("", 0x1f, "foo"),      null },
146                 { makeString("foo", 0x1f, ""),      null },
147                 { makeString("foo", 0x1f, "bar"),   null },
148 
149         };
150     }
151 
152     @Test(dataProvider = "legalModuleNames")
153     public void testLegalModuleName(String mn, String expected) throws Exception {
154         ModuleDescriptor md = newBuilder(mn).requires("java.base").build();
155         ByteBuffer bb = toBuffer(md);
156         String name = ModuleDescriptor.read(bb).name();
157         assertEquals(name, expected);
158     }
159 
160     @Test(dataProvider = "illegalModuleNames",
161           expectedExceptions = InvalidModuleDescriptorException.class)
162     public void testIllegalModuleName(String mn, String ignore) throws Exception {
163         ModuleDescriptor md = newBuilder(mn).requires("java.base").build();
164         ByteBuffer bb = toBuffer(md);
165         ModuleDescriptor.read(bb);  // throws InvalidModuleDescriptorException
166     }
167 
168     @Test(dataProvider = "legalModuleNames")
169     public void testLegalRequires(String mn, String expected) throws Exception {
170         ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build();
171         ByteBuffer bb = toBuffer(md);
172         ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
173         Optional<Requires> requires = descriptor.requires().stream()
174                 .filter(r -> !r.name().equals("java.base"))
175                 .findAny();
176         assertTrue(requires.isPresent());
177         assertEquals(requires.get().name(), expected);
178     }
179 
180     @Test(dataProvider = "illegalModuleNames",
181           expectedExceptions = InvalidModuleDescriptorException.class)
182     public void testIllegalRequires(String mn, String ignore) throws Exception {
183         ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build();
184         ByteBuffer bb = toBuffer(md);
185         ModuleDescriptor.read(bb);   // throws InvalidModuleDescriptorException
186     }
187 
188     @Test(dataProvider = "legalModuleNames")
189     public void testLegalExports(String mn, String expected) throws Exception {
190         ModuleDescriptor md = newBuilder("m")
191                 .requires("java.base")
192                 .exports("p", Set.of(mn))
193                 .build();
194         ByteBuffer bb = toBuffer(md);
195         ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
196         Optional<Exports> export = descriptor.exports().stream().findAny();
197         assertTrue(export.isPresent());
198         assertTrue(export.get().targets().contains(expected));
199     }
200 
201     @Test(dataProvider = "illegalModuleNames",
202           expectedExceptions = InvalidModuleDescriptorException.class)
203     public void testIllegalExports(String mn, String ignore) throws Exception {
204         ModuleDescriptor md = newBuilder("m")
205                 .requires("java.base")
206                 .exports("p", Set.of(mn))
207                 .build();
208         ByteBuffer bb = toBuffer(md);
209         ModuleDescriptor.read(bb);   // throws InvalidModuleDescriptorException
210     }
211 
212     @Test(dataProvider = "legalModuleNames")
213     public void testLegalOpens(String mn, String expected) throws Exception {
214         ModuleDescriptor md = newBuilder("m")
215                 .requires("java.base")
216                 .opens("p", Set.of(mn))
217                 .build();
218         ByteBuffer bb = toBuffer(md);
219         ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
220         Optional<Opens> opens = descriptor.opens().stream().findAny();
221         assertTrue(opens.isPresent());
222         assertTrue(opens.get().targets().contains(expected));
223     }
224 
225     @Test(dataProvider = "illegalModuleNames",
226           expectedExceptions = InvalidModuleDescriptorException.class)
227     public void testIllegalOpens(String mn, String ignore) throws Exception {
228         ModuleDescriptor md = newBuilder("m")
229                 .requires("java.base")
230                 .opens("p", Set.of(mn))
231                 .build();
232         ByteBuffer bb = toBuffer(md);
233         ModuleDescriptor.read(bb);   // throws InvalidModuleDescriptorException
234     }
235 
236     /**
237      * Returns a Builder that does not validate module names.
238      */
239     private Builder newBuilder(String mn) {
240         return SharedSecrets.getJavaLangModuleAccess()
241                             .newModuleBuilder(mn, false, Set.of());
242     }
243 
244     /**
245      * Returns a {@code ByteBuffer} containing the given module descriptor
246      * in module-info.class format.
247      */
248     private ByteBuffer toBuffer(ModuleDescriptor descriptor) throws Exception {
249         ByteArrayOutputStream baos = new ByteArrayOutputStream();
250         ModuleInfoWriter.write(descriptor, baos);
251         return ByteBuffer.wrap(baos.toByteArray());
252     }
253 
254     /**
255      * Returns a string containing a given code point.
256      */
257     private String makeString(String prefix, int codePoint, String suffix) {
258         StringBuilder sb = new StringBuilder();
259         sb.append(prefix);
260         sb.appendCodePoint(codePoint);
261         sb.append(suffix);
262         return sb.toString();
263     }
264 }