1/*
2 * Copyright (c) 2015, 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 8027634
27 * @summary Argument parsing from file
28 * @build TestHelper
29 * @run main ArgsFileTest
30 */
31import java.io.File;
32import java.io.IOException;
33import java.util.ArrayList;
34import java.util.Arrays;
35import java.util.Collections;
36import java.util.HashMap;
37import java.util.List;
38import java.util.Map;
39import java.util.regex.Matcher;
40import java.util.regex.Pattern;
41
42public class ArgsFileTest extends TestHelper {
43    private static File testJar = null;
44    private static Map<String, String> env = new HashMap<>();
45
46    static void init() throws IOException {
47        if  (testJar != null) {
48            return;
49        }
50        testJar = new File("test.jar");
51        StringBuilder tsrc = new StringBuilder();
52        tsrc.append("public static void main(String... args) {\n");
53        tsrc.append("   for (String x : args) {\n");
54        tsrc.append("        System.out.println(x);\n");
55        tsrc.append("   }\n");
56        tsrc.append("}\n");
57        createJar(testJar, new File("Foo"), tsrc.toString());
58
59        env.put(JLDEBUG_KEY, "true");
60    }
61
62    private File createArgFile(String fname, List<String> lines) throws IOException {
63        File argFile = new File(fname);
64        argFile.delete();
65        createAFile(argFile, lines);
66        return argFile;
67    }
68
69    private void verifyOptions(List<String> args, TestResult tr) {
70        if (args.isEmpty()) {
71            return;
72        }
73
74        int i = 1;
75        for (String x : args) {
76            tr.matches(".*argv\\[" + i + "\\] = " + Pattern.quote(x) + ".*");
77            i++;
78        }
79        if (! tr.testStatus) {
80            System.out.println(tr);
81            throw new RuntimeException("test fails");
82        }
83    }
84
85    private void verifyUserArgs(List<String> args, TestResult tr, int index) {
86        if (javaCmd != TestHelper.javaCmd) {
87            tr.contains("\tFirst application arg index: 1");
88        } else {
89            tr.contains("\tFirst application arg index: " + index);
90
91            for (String arg: args) {
92                tr.matches("^" + Pattern.quote(arg) + "$");
93            }
94        }
95
96        if (! tr.testStatus) {
97            System.out.println(tr);
98            throw new RuntimeException("test fails");
99        }
100    }
101
102    @Test
103    public void expandAll() throws IOException {
104        List<String> lines = new ArrayList<>();
105        lines.add("-Xmx32m");
106        lines.add("-Xint");
107        File argFile1 = createArgFile("argFile1", lines);
108        lines = new ArrayList<>();
109        lines.add("-jar");
110        lines.add("test.jar");
111        lines.add("uarg1 @uarg2 @@uarg3 -uarg4 uarg5");
112        File argFile2 = createArgFile("argFile2", lines);
113
114        TestResult tr = doExec(env, javaCmd, "@argFile1", "@argFile2");
115
116        List<String> appArgs = new ArrayList<>();
117        appArgs.add("uarg1");
118        appArgs.add("@uarg2");
119        appArgs.add("@@uarg3");
120        appArgs.add("-uarg4");
121        appArgs.add("uarg5");
122
123        List<String> options = new ArrayList<>();
124        options.add("-Xmx32m");
125        options.add("-Xint");
126        options.add("-jar");
127        options.add("test.jar");
128        options.addAll(appArgs);
129
130        verifyOptions(options, tr);
131        verifyUserArgs(appArgs, tr, 5);
132        argFile1.delete();
133        argFile2.delete();
134
135        File cpFile = createArgFile("cpFile", Arrays.asList("-cp", "test.jar"));
136        List<String> appCmd = new ArrayList<>();
137        appCmd.add("Foo");
138        appCmd.addAll(appArgs);
139        File appFile = createArgFile("appFile", appCmd);
140
141        tr = doExec(env, javaCmd, "@cpFile", "@appFile");
142        verifyOptions(Arrays.asList("-cp", "test.jar", "Foo",
143                "uarg1", "@uarg2", "@@uarg3", "-uarg4", "uarg5"), tr);
144        verifyUserArgs(appArgs, tr, 4);
145        cpFile.delete();
146        appFile.delete();
147    }
148
149    @Test
150    public void escapeArg() throws IOException {
151        List<String> lines = new ArrayList<>();
152        lines.add("-Xmx32m");
153        lines.add("-Xint");
154        File argFile1 = createArgFile("argFile1", lines);
155
156        TestResult tr = doExec(env, javaCmd, "-cp", "@@arg", "-cp", "@",
157                "-cp", "@@@cp", "@argFile1", "@@@@Main@@@@", "-version");
158        List<String> options = new ArrayList<>();
159        options.add("-cp");
160        options.add("@arg");
161        options.add("-cp");
162        options.add("@");
163        options.add("-cp");
164        options.add("@@cp");
165        options.add("-Xmx32m");
166        options.add("-Xint");
167        options.add("@@@Main@@@@");
168        options.add("-version");
169        verifyOptions(options, tr);
170        verifyUserArgs(Collections.emptyList(), tr, options.size());
171        argFile1.delete();
172    }
173
174    @Test
175    public void killSwitch() throws IOException {
176        List<String> lines = new ArrayList<>();
177        lines.add("-Xmx32m");
178        lines.add("-Xint");
179        File argFile1 = createArgFile("argFile1", lines);
180        lines = new ArrayList<>();
181        lines.add("-jar");
182        lines.add("test.jar");
183        lines.add("uarg1 @uarg2 @@uarg3 -uarg4 uarg5");
184        File argFile2 = createArgFile("argFile2", lines);
185        File argKill = createArgFile("argKill",
186            Collections.singletonList("--disable-@files"));
187
188        TestResult tr = doExec(env, javaCmd, "@argFile1", "--disable-@files", "@argFile2");
189        List<String> options = new ArrayList<>();
190        options.add("-Xmx32m");
191        options.add("-Xint");
192        options.add("--disable-@files");
193        options.add("@argFile2");
194        verifyOptions(options, tr);
195        // Main class is @argFile2
196        verifyUserArgs(Collections.emptyList(), tr, 5);
197
198        // Specify in file is same as specify inline
199        tr = doExec(env, javaCmd, "@argFile1", "@argKill", "@argFile2");
200        verifyOptions(options, tr);
201        // Main class is @argFile2
202        verifyUserArgs(Collections.emptyList(), tr, 5);
203
204        // multiple is fine, once on is on.
205        tr = doExec(env, javaCmd, "@argKill", "@argFile1", "--disable-@files", "@argFile2");
206        options = Arrays.asList("--disable-@files", "@argFile1",
207                "--disable-@files", "@argFile2");
208        verifyOptions(options, tr);
209        verifyUserArgs(Collections.emptyList(), tr, 3);
210
211        // after main class, becoming an user application argument
212        tr = doExec(env, javaCmd, "@argFile2", "@argKill");
213        options = Arrays.asList("-jar", "test.jar", "uarg1", "@uarg2", "@@uarg3",
214                "-uarg4", "uarg5", "@argKill");
215        verifyOptions(options, tr);
216        verifyUserArgs(Arrays.asList("uarg1", "@uarg2", "@@uarg3",
217                "-uarg4", "uarg5", "@argKill"), tr, 3);
218
219        argFile1.delete();
220        argFile2.delete();
221        argKill.delete();
222    }
223
224    @Test
225    public void userApplication() throws IOException {
226        List<String> lines = new ArrayList<>();
227        lines.add("-Xmx32m");
228        lines.add("-Xint");
229        File vmArgs = createArgFile("vmArgs", lines);
230        File jarOpt = createArgFile("jarOpt", Arrays.asList("-jar"));
231        File cpOpt = createArgFile("cpOpt", Arrays.asList("-cp"));
232        File jarArg = createArgFile("jarArg", Arrays.asList("test.jar"));
233        File userArgs = createArgFile("userArgs", Arrays.asList("-opt", "arg", "--longopt"));
234
235        TestResult tr = doExec(env, javaCmd,
236                "@vmArgs", "@jarOpt", "test.jar", "-opt", "arg", "--longopt");
237        verifyOptions(Arrays.asList(
238                "-Xmx32m", "-Xint", "-jar", "test.jar", "-opt", "arg", "--longopt"), tr);
239        verifyUserArgs(Arrays.asList("-opt", "arg", "--longopt"), tr, 5);
240
241        tr = doExec(env, javaCmd, "@jarOpt", "@jarArg", "@vmArgs");
242        verifyOptions(Arrays.asList("-jar", "test.jar", "@vmArgs"), tr);
243        verifyUserArgs(Arrays.asList("@vmArgs"), tr, 3);
244
245        tr = doExec(env, javaCmd, "-cp", "@jarArg", "@vmArgs", "Foo", "@userArgs");
246        verifyOptions(Arrays.asList("-cp", "test.jar", "-Xmx32m", "-Xint",
247                "Foo", "@userArgs"), tr);
248        verifyUserArgs(Arrays.asList("@userArgs"), tr, 6);
249
250        tr = doExec(env, javaCmd, "@cpOpt", "@jarArg", "@vmArgs", "Foo", "@userArgs");
251        verifyOptions(Arrays.asList("-cp", "test.jar", "-Xmx32m", "-Xint",
252                "Foo", "@userArgs"), tr);
253        verifyUserArgs(Arrays.asList("@userArgs"), tr, 6);
254
255        tr = doExec(env, javaCmd, "@cpOpt", "test.jar", "@vmArgs", "Foo", "@userArgs");
256        verifyOptions(Arrays.asList("-cp", "test.jar", "-Xmx32m", "-Xint",
257                "Foo", "@userArgs"), tr);
258        verifyUserArgs(Arrays.asList("@userArgs"), tr, 6);
259
260        vmArgs.delete();
261        jarOpt.delete();
262        cpOpt.delete();
263        jarArg.delete();
264        userArgs.delete();
265    }
266
267    // test with missing file
268    @Test
269    public void missingFileNegativeTest() throws IOException {
270        TestResult tr = doExec(javaCmd, "@" + "missing.cmd");
271        tr.checkNegative();
272        tr.contains("Error: could not open `missing.cmd'");
273        if (!tr.testStatus) {
274            System.out.println(tr);
275            throw new RuntimeException("test fails");
276        }
277    }
278
279    public static void main(String... args) throws Exception {
280        init();
281        ArgsFileTest a = new ArgsFileTest();
282        a.run(args);
283        if (testExitValue > 0) {
284            System.out.println("Total of " + testExitValue + " failed");
285            System.exit(1);
286        } else {
287            System.out.println("All tests pass");
288        }
289    }
290}
291