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
33import java.nio.file.Path;
34import java.nio.file.Paths;
35import java.util.stream.Stream;
36
37import jdk.testlibrary.OutputAnalyzer;
38import static jdk.testlibrary.ProcessTools.*;
39
40import org.testng.annotations.BeforeTest;
41import org.testng.annotations.DataProvider;
42import org.testng.annotations.Test;
43import static org.testng.Assert.*;
44
45
46@Test
47public 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}
294