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