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