1 /* 2 * Copyright (c) 2007, 2014, 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 5030233 6214916 6356475 6571029 6684582 6742159 4459600 6758881 6753938 27 * 6894719 6968053 7151434 7146424 8007333 28 * @summary Argument parsing validation. 29 * @compile -XDignore.symbol.file Arrrghs.java 30 * @run main/othervm Arrrghs 31 */ 32 33 import java.io.BufferedReader; 34 import java.io.File; 35 import java.io.FileNotFoundException; 36 import java.io.IOException; 37 import java.io.InputStream; 38 import java.io.InputStreamReader; 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.HashMap; 42 import java.util.List; 43 import java.util.Map; 44 import java.util.regex.Matcher; 45 import java.util.regex.Pattern; 46 47 public class Arrrghs extends TestHelper { 48 private Arrrghs(){} 49 /** 50 * This class provides various tests for arguments processing. 51 * A group of tests to ensure that arguments are passed correctly to 52 * a child java process upon a re-exec, this typically happens when 53 * a version other than the one being executed is requested by the user. 54 * 55 * History: these set of tests were part of Arrrghs.sh. The MKS shell 56 * implementations were notoriously buggy. Implementing these tests purely 57 * in Java is not only portable but also robust. 58 * 59 */ 60 61 // The version string to force a re-exec 62 final static String VersionStr = "-version:1.1+"; 63 64 // The Cookie or the pattern we match in the debug output. 65 final static String Cookie = "ReExec Args: "; 66 67 /* 68 * SIGH, On Windows all strings are quoted, we need to unwrap it 69 */ 70 private static String removeExtraQuotes(String in) { 71 if (isWindows) { 72 // Trim the string and remove the enclosed quotes if any. 73 in = in.trim(); 74 if (in.startsWith("\"") && in.endsWith("\"")) { 75 return in.substring(1, in.length()-1); 76 } 77 } 78 return in; 79 } 80 81 /* 82 * This method detects the cookie in the output stream of the process. 83 */ 84 private boolean detectCookie(InputStream istream, 85 String expectedArguments) throws IOException { 86 BufferedReader rd = new BufferedReader(new InputStreamReader(istream)); 87 boolean retval = false; 88 89 String in = rd.readLine(); 90 while (in != null) { 91 if (debug) System.out.println(in); 92 if (in.startsWith(Cookie)) { 93 String detectedArgument = removeExtraQuotes(in.substring(Cookie.length())); 94 if (expectedArguments.equals(detectedArgument)) { 95 retval = true; 96 } else { 97 System.out.println("Error: Expected Arguments\t:'" + 98 expectedArguments + "'"); 99 System.out.println(" Detected Arguments\t:'" + 100 detectedArgument + "'"); 101 } 102 // Return the value asap if not in debug mode. 103 if (!debug) { 104 rd.close(); 105 istream.close(); 106 return retval; 107 } 108 } 109 in = rd.readLine(); 110 } 111 return retval; 112 } 113 114 private boolean doReExecTest0(ProcessBuilder pb, String expectedArguments) { 115 boolean retval = false; 116 try { 117 pb.redirectErrorStream(true); 118 Process p = pb.start(); 119 retval = detectCookie(p.getInputStream(), expectedArguments); 120 p.waitFor(); 121 p.destroy(); 122 } catch (Exception ex) { 123 ex.printStackTrace(); 124 throw new RuntimeException(ex.getMessage()); 125 } 126 return retval; 127 } 128 129 /** 130 * This method returns true if the expected and detected arguments are the same. 131 * Quoting could cause dissimilar testArguments and expected arguments. 132 */ 133 int doReExecTest(String testArguments, String expectedPattern) { 134 ProcessBuilder pb = new ProcessBuilder(javaCmd, 135 VersionStr, testArguments); 136 137 Map<String, String> env = pb.environment(); 138 env.put(JLDEBUG_KEY, "true"); 139 return doReExecTest0(pb, testArguments) ? 0 : 1; 140 } 141 142 /** 143 * A convenience method for identical test pattern and expected arguments 144 */ 145 int doReExecTest(String testPattern) { 146 return doReExecTest(testPattern, testPattern); 147 } 148 149 @Test 150 void testQuoteParsingThroughReExec() { 151 /* 152 * Tests for 6214916 153 * These tests require that a JVM (any JVM) be installed in the system registry. 154 * If none is installed, skip this test. 155 */ 156 TestResult tr = doExec(javaCmd, VersionStr, "-version"); 157 if (!tr.isOK()) { 158 System.err.println("Warning:Argument Passing Tests were skipped, " + 159 "no java found in system registry."); 160 return; 161 } 162 163 // Basic test 164 testExitValue += doReExecTest("-a -b -c -d"); 165 166 // Basic test with many spaces 167 testExitValue += doReExecTest("-a -b -c -d"); 168 169 // Quoted whitespace does matter ? 170 testExitValue += doReExecTest("-a \"\"-b -c\"\" -d"); 171 172 173 // Escaped quotes outside of quotes as literals 174 testExitValue += doReExecTest("-a \\\"-b -c\\\" -d"); 175 176 // Check for escaped quotes inside of quotes as literal 177 testExitValue += doReExecTest("-a \"-b \\\"stuff\\\"\" -c -d"); 178 179 // A quote preceeded by an odd number of slashes is a literal quote 180 testExitValue += doReExecTest("-a -b\\\\\\\" -c -d"); 181 182 // A quote preceeded by an even number of slashes is a literal quote 183 // see 6214916. 184 testExitValue += doReExecTest("-a -b\\\\\\\\\" -c -d"); 185 186 // Make sure that whitespace doesn't interfere with the removal of the 187 // appropriate tokens. (space-tab-space preceeds -jre-restict-search). 188 testExitValue += doReExecTest("-a -b \t -jre-restrict-search -c -d", "-a -b -c -d"); 189 190 // Make sure that the mJRE tokens being stripped, aren't stripped if 191 // they happen to appear as arguments to the main class. 192 testExitValue += doReExecTest("foo -version:1.1+"); 193 194 System.out.println("Completed arguments quoting tests with " 195 + testExitValue + " errors"); 196 } 197 // the pattern we hope to see in the output 198 static final Pattern ArgPattern = Pattern.compile("\\s*argv\\[[0-9]*\\].*=.*"); 199 200 void checkArgumentParsing(String inArgs, String... expArgs) throws IOException { 201 List<String> scratchpad = new ArrayList<>(); 202 scratchpad.add("set " + JLDEBUG_KEY + "=true"); 203 // GAK, -version needs to be added so that windows can flush its stderr 204 // exiting the process prematurely can terminate the stderr. 205 scratchpad.add(javaCmd + " -version " + inArgs); 206 File batFile = new File("atest.bat"); 207 createAFile(batFile, scratchpad); 208 209 TestResult tr = doExec(batFile.getName()); 210 211 ArrayList<String> expList = new ArrayList<>(); 212 expList.add(javaCmd); 213 expList.add("-version"); 214 expList.addAll(Arrays.asList(expArgs)); 215 216 List<String> gotList = new ArrayList<>(); 217 for (String x : tr.testOutput) { 218 Matcher m = ArgPattern.matcher(x); 219 if (m.matches()) { 220 String a[] = x.split("="); 221 gotList.add(a[a.length - 1].trim()); 222 } 223 } 224 if (!gotList.equals(expList)) { 225 System.out.println(tr); 226 System.out.println("Expected args:"); 227 System.out.println(expList); 228 System.out.println("Obtained args:"); 229 System.out.println(gotList); 230 throw new RuntimeException("Error: args do not match"); 231 } 232 System.out.println("\'" + inArgs + "\'" + " - Test passed"); 233 } 234 235 /* 236 * This tests general quoting and are specific to Windows, *nixes 237 * need not worry about this, these have been tested with Windows 238 * implementation and those that are known to work are used against 239 * the java implementation. Note that the ProcessBuilder gets in the 240 * way when testing some of these arguments, therefore we need to 241 * create and execute a .bat file containing the arguments. 242 */ 243 @Test 244 void testArgumentParsing() throws IOException { 245 if (!isWindows) 246 return; 247 // no quotes 248 checkArgumentParsing("a b c d", "a", "b", "c", "d"); 249 250 // single quotes 251 checkArgumentParsing("\"a b c d\"", "a b c d"); 252 253 //double quotes 254 checkArgumentParsing("\"\"a b c d\"\"", "a", "b", "c", "d"); 255 256 // triple quotes 257 checkArgumentParsing("\"\"\"a b c d\"\"\"", "\"a b c d\""); 258 259 // a literal within single quotes 260 checkArgumentParsing("\"a\"b c d\"e\"", "ab", "c", "de"); 261 262 // a literal within double quotes 263 checkArgumentParsing("\"\"a\"b c d\"e\"\"", "ab c de"); 264 265 // a literal quote 266 checkArgumentParsing("a\\\"b", "a\"b"); 267 268 // double back-slash 269 checkArgumentParsing("\"a b c d\\\\\"", "a b c d\\"); 270 271 // triple back-slash 272 checkArgumentParsing("a\\\\\\\"b", "a\\\"b"); 273 274 // dangling quote 275 checkArgumentParsing("\"a b c\"\"", "a b c\""); 276 277 // expansions of white space separators 278 checkArgumentParsing("a b", "a", "b"); 279 checkArgumentParsing("a\tb", "a", "b"); 280 checkArgumentParsing("a \t b", "a", "b"); 281 282 checkArgumentParsing("\"C:\\TEST A\\\\\"", "C:\\TEST A\\"); 283 checkArgumentParsing("\"\"C:\\TEST A\\\\\"\"", "C:\\TEST", "A\\"); 284 285 // MS Windows tests 286 // triple back-slash 287 checkArgumentParsing("a\\\\\\d", "a\\\\\\d"); 288 289 // triple back-slash in quotes 290 checkArgumentParsing("\"a\\\\\\d\"", "a\\\\\\d"); 291 292 // slashes separating characters 293 checkArgumentParsing("X\\Y\\Z", "X\\Y\\Z"); 294 checkArgumentParsing("\\X\\Y\\Z", "\\X\\Y\\Z"); 295 296 // literals within dangling quotes, etc. 297 checkArgumentParsing("\"a b c\" d e", "a b c", "d", "e"); 298 checkArgumentParsing("\"ab\\\"c\" \"\\\\\" d", "ab\"c", "\\", "d"); 299 checkArgumentParsing("a\\\\\\c d\"e f\"g h", "a\\\\\\c", "de fg", "h"); 300 checkArgumentParsing("a\\\\\\\"b c d", "a\\\"b", "c", "d"); 301 checkArgumentParsing("a\\\\\\\\\"g c\" d e", "a\\\\g c", "d", "e"); 302 303 // treatment of back-slashes 304 checkArgumentParsing("*\\", "*\\"); 305 checkArgumentParsing("*/", "*/"); 306 checkArgumentParsing(".\\*", ".\\*"); 307 checkArgumentParsing("./*", "./*"); 308 checkArgumentParsing("..\\..\\*", "..\\..\\*"); 309 checkArgumentParsing("../../*", "../../*"); 310 checkArgumentParsing("..\\..\\", "..\\..\\"); 311 checkArgumentParsing("../../", "../../"); 312 checkArgumentParsing("a b\\ c", "a", "b\\", "c"); 313 // 2 back-slashes 314 checkArgumentParsing("\\\\?", "\\\\?"); 315 // 3 back-slashes 316 checkArgumentParsing("\\\\\\?", "\\\\\\?"); 317 // 4 back-slashes 318 checkArgumentParsing("\\\\\\\\?", "\\\\\\\\?"); 319 // 5 back-slashes 320 checkArgumentParsing("\\\\\\\\\\?", "\\\\\\\\\\?"); 321 // 6 back-slashes 322 checkArgumentParsing("\\\\\\\\\\\\?", "\\\\\\\\\\\\?"); 323 324 // more treatment of mixed slashes 325 checkArgumentParsing("f1/ f3\\ f4/", "f1/", "f3\\", "f4/"); 326 checkArgumentParsing("f1/ f2\' ' f3/ f4/", "f1/", "f2\'", "'", "f3/", "f4/"); 327 } 328 329 private void initEmptyDir(File emptyDir) throws IOException { 330 if (emptyDir.exists()) { 331 recursiveDelete(emptyDir); 332 } 333 emptyDir.mkdir(); 334 } 335 336 private void initDirWithJavaFiles(File libDir) throws IOException { 337 338 if (libDir.exists()) { 339 recursiveDelete(libDir); 340 } 341 libDir.mkdirs(); 342 ArrayList<String> scratchpad = new ArrayList<>(); 343 scratchpad.add("package lib;"); 344 scratchpad.add("public class Fbo {"); 345 scratchpad.add("public static void main(String... args){Foo.f();}"); 346 scratchpad.add("public static void f(){}"); 347 scratchpad.add("}"); 348 createFile(new File(libDir, "Fbo.java"), scratchpad); 349 350 scratchpad.clear(); 351 scratchpad.add("package lib;"); 352 scratchpad.add("public class Foo {"); 353 scratchpad.add("public static void main(String... args){"); 354 scratchpad.add("for (String x : args) {"); 355 scratchpad.add("System.out.println(x);"); 356 scratchpad.add("}"); 357 scratchpad.add("Fbo.f();"); 358 scratchpad.add("}"); 359 scratchpad.add("public static void f(){}"); 360 scratchpad.add("}"); 361 createFile(new File(libDir, "Foo.java"), scratchpad); 362 } 363 364 void checkArgumentWildcard(String inArgs, String... expArgs) throws IOException { 365 String[] in = {inArgs}; 366 checkArgumentWildcard(in, expArgs); 367 368 // now add arbitrary arguments before and after 369 String[] outInArgs = { "-Q", inArgs, "-R"}; 370 371 String[] outExpArgs = new String[expArgs.length + 2]; 372 outExpArgs[0] = "-Q"; 373 System.arraycopy(expArgs, 0, outExpArgs, 1, expArgs.length); 374 outExpArgs[expArgs.length + 1] = "-R"; 375 checkArgumentWildcard(outInArgs, outExpArgs); 376 } 377 378 void checkArgumentWildcard(String[] inArgs, String[] expArgs) throws IOException { 379 ArrayList<String> argList = new ArrayList<>(); 380 argList.add(javaCmd); 381 argList.add("-cp"); 382 argList.add("lib" + File.separator + "*"); 383 argList.add("lib.Foo"); 384 argList.addAll(Arrays.asList(inArgs)); 385 String[] cmds = new String[argList.size()]; 386 argList.toArray(cmds); 387 TestResult tr = doExec(cmds); 388 if (!tr.isOK()) { 389 System.out.println(tr); 390 throw new RuntimeException("Error: classpath single entry wildcard entry"); 391 } 392 393 ArrayList<String> expList = new ArrayList<>(); 394 expList.addAll(Arrays.asList(expArgs)); 395 396 List<String> gotList = new ArrayList<>(); 397 for (String x : tr.testOutput) { 398 gotList.add(x.trim()); 399 } 400 if (!gotList.equals(expList)) { 401 System.out.println(tr); 402 System.out.println("Expected args:"); 403 System.out.println(expList); 404 System.out.println("Obtained args:"); 405 System.out.println(gotList); 406 throw new RuntimeException("Error: args do not match"); 407 } 408 System.out.print("\'"); 409 for (String x : inArgs) { 410 System.out.print(x + " "); 411 } 412 System.out.println("\'" + " - Test passed"); 413 } 414 415 /* 416 * These tests are not expected to work on *nixes, and are ignored. 417 */ 418 @Test 419 void testWildCardArgumentProcessing() throws IOException { 420 if (!isWindows) 421 return; 422 File cwd = new File("."); 423 File libDir = new File(cwd, "lib"); 424 initDirWithJavaFiles(libDir); 425 initEmptyDir(new File(cwd, "empty")); 426 427 // test if javac (the command) can compile *.java 428 TestResult tr = doExec(javacCmd, libDir.getName() + File.separator + "*.java"); 429 if (!tr.isOK()) { 430 System.out.println(tr); 431 throw new RuntimeException("Error: compiling java wildcards"); 432 } 433 434 // use the jar cmd to create jars using the ? wildcard 435 File jarFoo = new File(libDir, "Foo.jar"); 436 tr = doExec(jarCmd, "cvf", jarFoo.getAbsolutePath(), "lib" + File.separator + "F?o.class"); 437 if (!tr.isOK()) { 438 System.out.println(tr); 439 throw new RuntimeException("Error: creating jar with wildcards"); 440 } 441 442 // now the litmus test!, this should work 443 checkArgumentWildcard("a", "a"); 444 445 // test for basic expansion 446 checkArgumentWildcard("lib\\F*java", "lib\\Fbo.java", "lib\\Foo.java"); 447 448 // basic expansion in quotes 449 checkArgumentWildcard("\"lib\\F*java\"", "lib\\F*java"); 450 451 checkArgumentWildcard("lib\\**", "lib\\Fbo.class", "lib\\Fbo.java", 452 "lib\\Foo.class", "lib\\Foo.jar", "lib\\Foo.java"); 453 454 checkArgumentWildcard("lib\\*?", "lib\\Fbo.class", "lib\\Fbo.java", 455 "lib\\Foo.class", "lib\\Foo.jar", "lib\\Foo.java"); 456 457 checkArgumentWildcard("lib\\?*", "lib\\Fbo.class", "lib\\Fbo.java", 458 "lib\\Foo.class", "lib\\Foo.jar", "lib\\Foo.java"); 459 460 checkArgumentWildcard("lib\\?", "lib\\?"); 461 462 // test for basic expansion 463 checkArgumentWildcard("lib\\*java", "lib\\Fbo.java", "lib\\Foo.java"); 464 465 // basic expansion in quotes 466 checkArgumentWildcard("\"lib\\*.java\"", "lib\\*.java"); 467 468 // suffix expansion 469 checkArgumentWildcard("lib\\*.class", "lib\\Fbo.class", "lib\\Foo.class"); 470 471 // suffix expansion in quotes 472 checkArgumentWildcard("\"lib\\*.class\"", "lib\\*.class"); 473 474 // check for ? expansion now 475 checkArgumentWildcard("lib\\F?o.java", "lib\\Fbo.java", "lib\\Foo.java"); 476 477 // check ? in quotes 478 checkArgumentWildcard("\"lib\\F?o.java\"", "lib\\F?o.java"); 479 480 // check ? as suffixes 481 checkArgumentWildcard("lib\\F?o.????", "lib\\Fbo.java", "lib\\Foo.java"); 482 483 // check ? in a leading role 484 checkArgumentWildcard("lib\\???.java", "lib\\Fbo.java", "lib\\Foo.java"); 485 checkArgumentWildcard("\"lib\\???.java\"", "lib\\???.java"); 486 487 // check ? prefixed with - 488 checkArgumentWildcard("-?", "-?"); 489 490 // check * prefixed with - 491 checkArgumentWildcard("-*", "-*"); 492 493 // check on empty directory 494 checkArgumentWildcard("empty\\*", "empty\\*"); 495 checkArgumentWildcard("empty\\**", "empty\\**"); 496 checkArgumentWildcard("empty\\?", "empty\\?"); 497 checkArgumentWildcard("empty\\??", "empty\\??"); 498 checkArgumentWildcard("empty\\*?", "empty\\*?"); 499 checkArgumentWildcard("empty\\?*", "empty\\?*"); 500 501 } 502 503 void doArgumentCheck(String inArgs, String... expArgs) { 504 Map<String, String> env = new HashMap<>(); 505 env.put(JLDEBUG_KEY, "true"); 506 TestResult tr = doExec(env, javaCmd, inArgs); 507 System.out.println(tr); 508 int sindex = tr.testOutput.indexOf("Command line args:"); 509 if (sindex < 0) { 510 System.out.println(tr); 511 throw new RuntimeException("Error: no output"); 512 } 513 sindex++; // skip over the tag 514 List<String> gotList = new ArrayList<>(); 515 for (String x : tr.testOutput.subList(sindex, sindex + expArgs.length)) { 516 String a[] = x.split("="); 517 gotList.add(a[a.length - 1].trim()); 518 } 519 List<String> expList = Arrays.asList(expArgs); 520 if (!gotList.equals(expList)) { 521 System.out.println(tr); 522 System.out.println("Expected args:"); 523 System.out.println(expList); 524 System.out.println("Obtained args:"); 525 System.out.println(gotList); 526 throw new RuntimeException("Error: args do not match"); 527 } 528 } 529 530 531 /* 532 * These tests are usually run on non-existent targets to check error results 533 */ 534 @Test 535 void testBasicErrorMessages() { 536 // Tests for 5030233 537 TestResult tr = doExec(javaCmd, "-cp"); 538 tr.checkNegative(); 539 tr.isNotZeroOutput(); 540 if (!tr.testStatus) 541 System.out.println(tr); 542 543 tr = doExec(javaCmd, "-classpath"); 544 tr.checkNegative(); 545 tr.isNotZeroOutput(); 546 if (!tr.testStatus) 547 System.out.println(tr); 548 549 tr = doExec(javaCmd, "-jar"); 550 tr.checkNegative(); 551 tr.isNotZeroOutput(); 552 if (!tr.testStatus) 553 System.out.println(tr); 554 555 tr = doExec(javacCmd, "-cp"); 556 tr.checkNegative(); 557 tr.isNotZeroOutput(); 558 if (!tr.testStatus) 559 System.out.println(tr); 560 561 // Test for 6356475 "REGRESSION:"java -X" from cmdline fails" 562 tr = doExec(javaCmd, "-X"); 563 tr.checkPositive(); 564 tr.isNotZeroOutput(); 565 if (!tr.testStatus) 566 System.out.println(tr); 567 568 tr = doExec(javaCmd, "-help"); 569 tr.checkPositive(); 570 tr.isNotZeroOutput(); 571 if (!tr.testStatus) 572 System.out.println(tr); 573 574 // 6753938, test for non-negative exit value for an incorrectly formed 575 // command line, '% java' 576 tr = doExec(javaCmd); 577 tr.checkNegative(); 578 tr.isNotZeroOutput(); 579 if (!tr.testStatus) 580 System.out.println(tr); 581 582 // 6753938, test for non-negative exit value for an incorrectly formed 583 // command line, '% java -Xcomp' 584 tr = doExec(javaCmd, "-Xcomp"); 585 tr.checkNegative(); 586 tr.isNotZeroOutput(); 587 if (!tr.testStatus) 588 System.out.println(tr); 589 590 // 7151434, test for non-negative exit value for an incorrectly formed 591 // command line, '% java -jar -W', note the bogus -W 592 tr = doExec(javaCmd, "-jar", "-W"); 593 tr.checkNegative(); 594 tr.contains("Unrecognized option: -W"); 595 if (!tr.testStatus) 596 System.out.println(tr); 597 } 598 599 /* 600 * Tests various dispositions of the main method, these tests are limited 601 * to English locales as they check for error messages that are localized. 602 */ 603 @Test 604 void testMainMethod() throws FileNotFoundException { 605 if (!isEnglishLocale()) { 606 return; 607 } 608 609 TestResult tr = null; 610 611 // a missing class 612 createJar("MIA", new File("some.jar"), new File("Foo"), 613 (String[])null); 614 tr = doExec(javaCmd, "-jar", "some.jar"); 615 tr.contains("Error: Could not find or load main class MIA"); 616 if (!tr.testStatus) 617 System.out.println(tr); 618 // use classpath to check 619 tr = doExec(javaCmd, "-cp", "some.jar", "MIA"); 620 tr.contains("Error: Could not find or load main class MIA"); 621 if (!tr.testStatus) 622 System.out.println(tr); 623 624 // incorrect method access 625 createJar(new File("some.jar"), new File("Foo"), 626 "private static void main(String[] args){}"); 627 tr = doExec(javaCmd, "-jar", "some.jar"); 628 tr.contains("Error: Main method not found in class Foo"); 629 if (!tr.testStatus) 630 System.out.println(tr); 631 // use classpath to check 632 tr = doExec(javaCmd, "-cp", "some.jar", "Foo"); 633 tr.contains("Error: Main method not found in class Foo"); 634 if (!tr.testStatus) 635 System.out.println(tr); 636 637 // incorrect return type 638 createJar(new File("some.jar"), new File("Foo"), 639 "public static int main(String[] args){return 1;}"); 640 tr = doExec(javaCmd, "-jar", "some.jar"); 641 tr.contains("Error: Main method must return a value of type void in class Foo"); 642 if (!tr.testStatus) 643 System.out.println(tr); 644 // use classpath to check 645 tr = doExec(javaCmd, "-cp", "some.jar", "Foo"); 646 tr.contains("Error: Main method must return a value of type void in class Foo"); 647 if (!tr.testStatus) 648 System.out.println(tr); 649 650 // incorrect parameter type 651 createJar(new File("some.jar"), new File("Foo"), 652 "public static void main(Object[] args){}"); 653 tr = doExec(javaCmd, "-jar", "some.jar"); 654 tr.contains("Error: Main method not found in class Foo"); 655 if (!tr.testStatus) 656 System.out.println(tr); 657 // use classpath to check 658 tr = doExec(javaCmd, "-cp", "some.jar", "Foo"); 659 tr.contains("Error: Main method not found in class Foo"); 660 if (!tr.testStatus) 661 System.out.println(tr); 662 663 // incorrect method type - non-static 664 createJar(new File("some.jar"), new File("Foo"), 665 "public void main(String[] args){}"); 666 tr = doExec(javaCmd, "-jar", "some.jar"); 667 tr.contains("Error: Main method is not static in class Foo"); 668 if (!tr.testStatus) 669 System.out.println(tr); 670 // use classpath to check 671 tr = doExec(javaCmd, "-cp", "some.jar", "Foo"); 672 tr.contains("Error: Main method is not static in class Foo"); 673 if (!tr.testStatus) 674 System.out.println(tr); 675 676 // amongst a potpourri of kindred main methods, is the right one chosen ? 677 createJar(new File("some.jar"), new File("Foo"), 678 "void main(Object[] args){}", 679 "int main(Float[] args){return 1;}", 680 "private void main() {}", 681 "private static void main(int x) {}", 682 "public int main(int argc, String[] argv) {return 1;}", 683 "public static void main(String[] args) {System.out.println(\"THE_CHOSEN_ONE\");}"); 684 tr = doExec(javaCmd, "-jar", "some.jar"); 685 tr.contains("THE_CHOSEN_ONE"); 686 if (!tr.testStatus) 687 System.out.println(tr); 688 // use classpath to check 689 tr = doExec(javaCmd, "-cp", "some.jar", "Foo"); 690 tr.contains("THE_CHOSEN_ONE"); 691 if (!tr.testStatus) 692 System.out.println(tr); 693 694 // test for extraneous whitespace in the Main-Class attribute 695 createJar(" Foo ", new File("some.jar"), new File("Foo"), 696 "public static void main(String... args){}"); 697 tr = doExec(javaCmd, "-jar", "some.jar"); 698 tr.checkPositive(); 699 if (!tr.testStatus) 700 System.out.println(tr); 701 } 702 /* 703 * tests 6968053, ie. we turn on the -Xdiag (for now) flag and check if 704 * the suppressed stack traces are exposed, ignore these tests for localized 705 * locales, limiting to English only. 706 */ 707 @Test 708 void testDiagOptions() throws FileNotFoundException { 709 if (!isEnglishLocale()) { // only english version 710 return; 711 } 712 TestResult tr = null; 713 // a missing class 714 createJar("MIA", new File("some.jar"), new File("Foo"), 715 (String[])null); 716 tr = doExec(javaCmd, "-Xdiag", "-jar", "some.jar"); 717 tr.contains("Error: Could not find or load main class MIA"); 718 tr.contains("java.lang.ClassNotFoundException: MIA"); 719 if (!tr.testStatus) 720 System.out.println(tr); 721 722 // use classpath to check 723 tr = doExec(javaCmd, "-Xdiag", "-cp", "some.jar", "MIA"); 724 tr.contains("Error: Could not find or load main class MIA"); 725 tr.contains("java.lang.ClassNotFoundException: MIA"); 726 if (!tr.testStatus) 727 System.out.println(tr); 728 729 // a missing class on the classpath 730 tr = doExec(javaCmd, "-Xdiag", "NonExistentClass"); 731 tr.contains("Error: Could not find or load main class NonExistentClass"); 732 tr.contains("java.lang.ClassNotFoundException: NonExistentClass"); 733 if (!tr.testStatus) 734 System.out.println(tr); 735 } 736 737 /** 738 * @param args the command line arguments 739 * @throws java.io.FileNotFoundException 740 */ 741 public static void main(String[] args) throws Exception { 742 if (debug) { 743 System.out.println("Starting Arrrghs tests"); 744 } 745 Arrrghs a = new Arrrghs(); 746 a.run(args); 747 if (testExitValue > 0) { 748 System.out.println("Total of " + testExitValue + " failed"); 749 System.exit(1); 750 } else { 751 System.out.println("All tests pass"); 752 } 753 } 754 }