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 * @bug 8168836
27 * @summary Basic argument validation for --add-exports
28 * @library /lib/testlibrary /test/lib
29 * @modules jdk.compiler
30 * @build jdk.test.lib.compiler.ModuleInfoMaker
31 *        jdk.test.lib.compiler.CompilerUtils
32 *        jdk.testlibrary.*
33 * @run testng AddExportsTestWarningError
34 */
35
36import java.io.BufferedOutputStream;
37import java.io.ByteArrayOutputStream;
38import java.io.PrintStream;
39import java.nio.file.Path;
40import java.nio.file.Paths;
41import java.util.Arrays;
42import java.util.stream.Stream;
43
44import jdk.test.lib.compiler.ModuleInfoMaker;
45import jdk.testlibrary.OutputAnalyzer;
46import static jdk.testlibrary.ProcessTools.*;
47
48import org.testng.annotations.BeforeTest;
49import org.testng.annotations.DataProvider;
50import org.testng.annotations.Test;
51import static org.testng.Assert.*;
52
53@Test
54public class AddExportsTestWarningError {
55
56    private static final Path MODS_DIR = Paths.get("mods");
57    private static final Path SRC_DIR = Paths.get("src");
58    private static final String M1_MAIN = "m1/p1.C1";
59    private static final String M3_MAIN = "m3/p3.C3";
60
61    @BeforeTest
62    public void setup() throws Exception {
63        ModuleInfoMaker builder = new ModuleInfoMaker(SRC_DIR);
64        builder.writeJavaFiles("m1",
65            "module m1 { }",
66            "package p1; public class C1 { " +
67                "    public static void main(String... args) {}" +
68                "}");
69
70        builder.writeJavaFiles("m2",
71            "module m2 { requires m1; exports p2; }",
72            "package p2; public class C2 {  private p1.C1 c1; }");
73
74        builder.writeJavaFiles("m3",
75            "module m3 { requires m2; }",
76            "package p3; class C3 { " +
77                "    p1.C1 c; " +
78                "    public static void main(String... args) { new p2.C2(); }" +
79                "}");
80
81        builder.compile("m1", MODS_DIR);
82        builder.compile("m2", MODS_DIR, "--add-exports", "m1/p1=m2");
83        builder.compile("m3", MODS_DIR, "--add-exports", "m1/p1=m3");
84    }
85
86
87    @DataProvider(name = "goodcases")
88    public Object[][] goodCases() {
89        return new Object[][]{
90
91            // empty items
92            { "m1/p1=,m2,m3",       null },
93            { "m1/p1=m2,,m3",       null },
94            { "m1/p1=m2,m3,",       null },
95
96            // duplicates
97            { "m1/p1=m2,m2,m3,,",   null },
98
99        };
100    }
101
102
103    @Test(dataProvider = "goodcases")
104    public void test(String value, String ignore) throws Exception {
105        testNoWarning(value);
106    }
107
108
109    @DataProvider(name = "illFormedAddExports")
110    public Object[][] illFormedAddExports() {
111        return new Object[][]{
112            { "m1",         "Unable to parse --add-exports <module>=<value>: m1"},
113
114            // missing source part
115            { "=m2",        "Unable to parse --add-exports <module>=<value>: =m2"},
116            { "/=m2",       "Unable to parse --add-exports <module>/<package>: /" },
117            { "m1=m2",      "Unable to parse --add-exports <module>/<package>: m1" },
118            { "/p1=m2",     "Unable to parse --add-exports <module>/<package>: /p1" },
119            { "m1p1=m2",    "Unable to parse --add-exports <module>/<package>: m1p1" },
120
121            // empty list, missing target
122            { "m1/p1=",     "Unable to parse --add-exports <module>=<value>: m1/p1=" },
123            { "m1/p1=,,",   "Target must be specified: --add-exports m1/p1=,," },
124        };
125    }
126
127    @Test(dataProvider = "illFormedAddExports")
128    public void testIllFormedAddExports(String value, String msg) throws Exception {
129        testError(value, msg);
130    }
131
132
133    @DataProvider(name = "unknownNames")
134    public Object[][] unknownNames() {
135        return new Object[][]{
136
137            // source not found
138            {"DoesNotExist/p=m1",  "WARNING: Unknown module: DoesNotExist specified to --add-exports"},
139            {"m1/DoesNotExist=m2", "WARNING: package DoesNotExist not in m1"},
140
141            // target not found
142            {"m1/p1=DoesNotExist", "WARNING: Unknown module: DoesNotExist specified to --add-exports"},
143
144            // bad names
145            {"m*/p1=m2",           "WARNING: Unknown module: m* specified to --add-exports"},
146            {"m1/p!=m2",           "WARNING: package p! not in m1"},
147            {"m1/p1=m!",           "WARNING: Unknown module: m! specified to --add-exports"},
148
149        };
150    }
151
152
153    @Test(dataProvider = "unknownNames")
154    public void testUnknownNames(String value, String msg) throws Exception {
155        testWarning(value, msg);
156    }
157
158
159    @DataProvider(name = "missingArguments")
160    public Object[][] missingArguments() {
161        return new Object[][]{
162            { new String[] { "--add-exports" },
163                "Error: --add-exports requires modules to be specified"},
164
165            { new String[] { "--add-exports=" },
166                "Error: --add-exports= requires modules to be specified" },
167
168            { new String[] { "--add-exports", "" },
169                "Error: --add-exports requires modules to be specified"}
170
171        };
172    }
173
174
175    @Test(dataProvider = "missingArguments")
176    public void testMissingArguments(String[] options, String msg) throws Exception {
177        String[] args = Stream.concat(Arrays.stream(options),
178                                      Stream.of("-version"))
179                              .toArray(String[]::new);
180        int exitValue = executeTestJava(args)
181            .outputTo(System.out)
182            .errorTo(System.out)
183            .shouldContain(msg)
184            .getExitValue();
185
186        assertTrue(exitValue != 0);
187    }
188
189     private void testWarning(String value, String msg) throws Exception {
190        int exitValue =
191            executeTestJava("--add-exports", value,
192                            "--module-path", MODS_DIR.toString(),
193                            "-m", M1_MAIN)
194                .outputTo(System.out)
195                .errorTo(System.out)
196                .shouldContain(msg)
197                .getExitValue();
198
199        assertTrue(exitValue == 0);
200    }
201
202    private void testError(String value, String msg) throws Exception {
203        int exitValue =
204            executeTestJava("--add-exports", value,
205                            "--module-path", MODS_DIR.toString(),
206                            "-m", M1_MAIN)
207                .outputTo(System.out)
208                .errorTo(System.out)
209                .shouldContain(msg)
210                .getExitValue();
211
212        assertTrue(exitValue != 0);
213    }
214
215    private void testNoWarning(String value) throws Exception {
216        ByteArrayOutputStream baos = new ByteArrayOutputStream();
217        PrintStream ps = new PrintStream(new BufferedOutputStream(baos));
218        OutputAnalyzer outputAnalyzer =
219            executeTestJava("--add-exports", value,
220                            "--module-path", MODS_DIR.toString(),
221                            "-m", M3_MAIN)
222                .outputTo(ps)
223                .errorTo(ps);
224
225        assertTrue(outputAnalyzer.getExitValue() == 0);
226
227        System.out.println(baos.toString());
228        String[] output = baos.toString().split("\\R");
229        assertFalse(Arrays.stream(output)
230                          .filter(s -> !s.matches("WARNING: Module name .* may soon be illegal"))
231                          .filter(s -> s.startsWith("WARNING:"))
232                          .findAny().isPresent());
233
234    }
235}
236