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  */
  31 import java.io.File;
  32 import java.io.IOException;
  33 import java.util.ArrayList;
  34 import java.util.Arrays;
  35 import java.util.Collections;
  36 import java.util.HashMap;
  37 import java.util.List;
  38 import java.util.Map;
  39 import java.util.regex.Matcher;
  40 import java.util.regex.Pattern;
  41 
  42 public 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("-Xdisable-@files"));
 187 
 188         TestResult tr = doExec(env, javaCmd, "@argFile1", "-Xdisable-@files", "@argFile2");
 189         List<String> options = new ArrayList<>();
 190         options.add("-Xmx32m");
 191         options.add("-Xint");
 192         options.add("-Xdisable-@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", "-Xdisable-@files", "@argFile2");
 206         options = Arrays.asList("-Xdisable-@files", "@argFile1",
 207                 "-Xdisable-@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 }