1 /*
   2  * Copyright (c) 2014, 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  * @library /lib/testlibrary
  27  * @modules jdk.compiler
  28  * @build AddExportsTest CompilerUtils jdk.testlibrary.*
  29  * @run testng AddExportsTest
  30  * @summary Basic tests for java --add-exports
  31  */
  32 
  33 import java.nio.file.Path;
  34 import java.nio.file.Paths;
  35 import java.util.stream.Stream;
  36 
  37 import jdk.testlibrary.OutputAnalyzer;
  38 import static jdk.testlibrary.ProcessTools.*;
  39 
  40 import org.testng.annotations.BeforeTest;
  41 import org.testng.annotations.DataProvider;
  42 import org.testng.annotations.Test;
  43 import static org.testng.Assert.*;
  44 
  45 
  46 @Test
  47 public class AddExportsTest {
  48 
  49     private static final String TEST_SRC = System.getProperty("test.src");
  50 
  51     private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
  52     private static final Path MODS_DIR = Paths.get("mods");
  53     private static final Path UPGRADE_MODS_DIRS = Paths.get("upgrademods");
  54 
  55     // test module m1 that uses Unsafe
  56     private static final String TEST1_MODULE = "m1";
  57     private static final String TEST1_MAIN_CLASS = "jdk.test1.Main";
  58 
  59     // test module m2 uses java.transaction internals
  60     private static final String TEST2_MODULE = "m2";
  61     private static final String TEST2_MAIN_CLASS = "jdk.test2.Main";
  62 
  63     // test module m3 uses m4 internals
  64     private static final String TEST3_MODULE = "m3";
  65     private static final String TEST3_MAIN_CLASS = "jdk.test3.Main";
  66     private static final String TEST4_MODULE = "m4";
  67 
  68 
  69     @BeforeTest
  70     public void compileTestModules() throws Exception {
  71 
  72         // javac -d mods/m1 src/m1/**
  73         boolean compiled = CompilerUtils.compile(
  74                 SRC_DIR.resolve(TEST1_MODULE),
  75                 MODS_DIR.resolve(TEST1_MODULE),
  76                 "--add-exports", "java.base/jdk.internal.misc=m1");
  77         assertTrue(compiled, "module " + TEST1_MODULE + " did not compile");
  78 
  79         // javac -d upgrademods/java.transaction src/java.transaction/**
  80         compiled = CompilerUtils.compile(
  81                 SRC_DIR.resolve("java.transaction"),
  82                 UPGRADE_MODS_DIRS.resolve("java.transaction"));
  83         assertTrue(compiled, "module java.transaction did not compile");
  84 
  85         // javac --upgrade-module-path upgrademods -d mods/m2 src/m2/**
  86         compiled = CompilerUtils.compile(
  87                 SRC_DIR.resolve(TEST2_MODULE),
  88                 MODS_DIR.resolve(TEST2_MODULE),
  89                 "--upgrade-module-path", UPGRADE_MODS_DIRS.toString(),
  90                 "--add-exports", "java.transaction/javax.transaction.internal=m2");
  91         assertTrue(compiled, "module " + TEST2_MODULE + " did not compile");
  92 
  93         // javac -d mods/m3 src/m3/**
  94         compiled = CompilerUtils.compile(
  95                 SRC_DIR.resolve(TEST3_MODULE),
  96                 MODS_DIR.resolve(TEST3_MODULE));
  97         assertTrue(compiled, "module " + TEST3_MODULE + " did not compile");
  98 
  99         // javac -d mods/m4 src/m4/**
 100         compiled = CompilerUtils.compile(
 101                 SRC_DIR.resolve(TEST4_MODULE),
 102                 MODS_DIR.resolve(TEST4_MODULE));
 103         assertTrue(compiled, "module " + TEST4_MODULE + " did not compile");
 104     }
 105 
 106     /**
 107      * Sanity check with -version
 108      */
 109     public void testSanity() throws Exception {
 110 
 111         int exitValue
 112             =  executeTestJava("--add-exports", "java.base/jdk.internal.reflect=ALL-UNNAMED",
 113                                "-version")
 114                 .outputTo(System.out)
 115                 .errorTo(System.out)
 116                 .getExitValue();
 117 
 118         assertTrue(exitValue == 0);
 119     }
 120 
 121 
 122     /**
 123      * Run class path application that uses jdk.internal.misc.Unsafe
 124      */
 125     public void testUnnamedModule() throws Exception {
 126 
 127         // java --add-exports java.base/jdk.internal.misc=ALL-UNNAMED \
 128         //      -cp mods/$TESTMODULE jdk.test.UsesUnsafe
 129 
 130         String classpath = MODS_DIR.resolve(TEST1_MODULE).toString();
 131         int exitValue
 132             = executeTestJava("--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED",
 133                               "-cp", classpath,
 134                               TEST1_MAIN_CLASS)
 135                 .outputTo(System.out)
 136                 .errorTo(System.out)
 137                 .getExitValue();
 138 
 139         assertTrue(exitValue == 0);
 140     }
 141 
 142 
 143     /**
 144      * Run named module that uses jdk.internal.misc.Unsafe
 145      */
 146     public void testNamedModule() throws Exception {
 147 
 148         //  java --add-exports java.base/jdk.internal.misc=test \
 149         //       --module-path mods -m $TESTMODULE/$MAIN_CLASS
 150 
 151         String mid = TEST1_MODULE + "/" + TEST1_MAIN_CLASS;
 152         int exitValue =
 153             executeTestJava("--add-exports", "java.base/jdk.internal.misc=" + TEST1_MODULE,
 154                             "--module-path", MODS_DIR.toString(),
 155                             "-m", mid)
 156                 .outputTo(System.out)
 157                 .errorTo(System.out)
 158                 .getExitValue();
 159 
 160         assertTrue(exitValue == 0);
 161     }
 162 
 163 
 164     /**
 165      * Test --add-exports with upgraded module
 166      */
 167     public void testWithUpgradedModule() throws Exception {
 168 
 169         // java --add-exports java.transaction/javax.transaction.internal=m2
 170         //      --upgrade-module-path upgrademods --module-path mods -m ...
 171         String mid = TEST2_MODULE + "/" + TEST2_MAIN_CLASS;
 172         int exitValue = executeTestJava(
 173                 "--add-exports", "java.transaction/javax.transaction.internal=m2",
 174                 "--upgrade-module-path", UPGRADE_MODS_DIRS.toString(),
 175                 "--module-path", MODS_DIR.toString(),
 176                 "-m", mid)
 177                 .outputTo(System.out)
 178                 .errorTo(System.out)
 179                 .getExitValue();
 180 
 181         assertTrue(exitValue == 0);
 182     }
 183 
 184 
 185     /**
 186      * Test --add-exports with module that is added to the set of root modules
 187      * with --add-modules.
 188      */
 189     public void testWithAddMods() throws Exception {
 190 
 191         // java --add-exports m4/jdk.test4=m3 --module-path mods -m ...
 192         String mid = TEST3_MODULE + "/" + TEST3_MAIN_CLASS;
 193         int exitValue = executeTestJava(
 194                 "--add-exports", "m4/jdk.test4=m3",
 195                 "--module-path", MODS_DIR.toString(),
 196                 "--add-modules", TEST4_MODULE,
 197                 "-m", mid)
 198                 .outputTo(System.out)
 199                 .errorTo(System.out)
 200                 .getExitValue();
 201 
 202         assertTrue(exitValue == 0);
 203     }
 204 
 205 
 206     /**
 207      * --add-exports and --add-opens allows duplicates
 208      */
 209     public void testWithDuplicateOption() throws Exception {
 210 
 211         int exitValue
 212             =  executeTestJava("--add-exports", "java.base/jdk.internal.reflect=ALL-UNNAMED",
 213                                "--add-exports", "java.base/jdk.internal.reflect=ALL-UNNAMED",
 214                                "--add-opens", "java.base/java.util=ALL-UNNAMED",
 215                                "--add-opens", "java.base/java.util=ALL-UNNAMED",
 216                                "-version")
 217                 .outputTo(System.out)
 218                 .errorTo(System.out)
 219                 .getExitValue();
 220 
 221         assertTrue(exitValue == 0);
 222     }
 223 
 224 
 225     private OutputAnalyzer execJava(String... options) {
 226         try {
 227             return executeTestJava(options);
 228         } catch (Exception e) {
 229             throw new Error(e);
 230         }
 231     }
 232 
 233     /**
 234      * Exercise --add-exports and --add-opens with unknown values.
 235      * Warning is emitted.
 236      */
 237     @Test(dataProvider = "unknownvalues")
 238     public void testWithUnknownValue(String value, String ignore) {
 239         Stream.of("--add-exports", "--add-opens")
 240             .forEach(option -> {
 241                 //  --add-exports $VALUE -version
 242                 int exitValue = execJava(option, value, "-version")
 243                     .stderrShouldMatch("WARNING: .*.monkey.*")
 244                     .outputTo(System.out)
 245                     .errorTo(System.out)
 246                     .getExitValue();
 247 
 248                 assertTrue(exitValue == 0);
 249             });
 250     }
 251 
 252 
 253     @DataProvider(name = "unknownvalues")
 254     public Object[][] unknownValues() {
 255         return new Object[][]{
 256 
 257             { "java.base/jdk.internal.misc=sun.monkey", null }, // unknown target
 258             { "java.monkey/sun.monkey=ALL-UNNAMED",     null }, // unknown module
 259             { "java.base/sun.monkey=ALL-UNNAMED",       null }, // unknown package
 260             { "java.monkey/sun.monkey=ALL-UNNAMED",     null }, // unknown module/package
 261 
 262         };
 263     }
 264 
 265 
 266     /**
 267      * Exercise --add-exports and --add-opens with bad values
 268      */
 269     @Test(dataProvider = "badvalues")
 270     public void testWithBadValue(String value, String ignore) {
 271         Stream.of("--add-exports", "--add-opens")
 272             .forEach(option -> {
 273                 //  --add-exports $VALUE -version
 274                 int exitValue = execJava(option, value, "-version")
 275                     .outputTo(System.out)
 276                     .errorTo(System.out)
 277                     .getExitValue();
 278 
 279         assertTrue(exitValue != 0);
 280             });
 281     }
 282 
 283     @DataProvider(name = "badvalues")
 284     public Object[][] badValues() {
 285         return new Object[][]{
 286 
 287             { "java.base/jdk.internal.misc",            null }, // missing target
 288             { "java.base=ALL-UNNAMED",                  null }, // missing package
 289             { "java.base/=ALL-UNNAMED",                 null }  // missing package
 290 
 291         };
 292     }
 293 }