PageRenderTime 49ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/MRI-J/jdk/test/java/lang/ProcessBuilder/Basic.java

http://github.com/GregBowyer/ManagedRuntimeInitiative
Java | 1525 lines | 1132 code | 185 blank | 208 comment | 121 complexity | 3d55f8a0b0f1e3050b3ac033dccea565 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright 2003-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20. * CA 95054 USA or visit www.sun.com if you need additional information or
  21. * have any questions.
  22. */
  23. /*
  24. * @test
  25. * @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689
  26. * 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313
  27. * 6464154 6523983 6206031
  28. * @summary Basic tests for Process and Environment Variable code
  29. * @run main/othervm Basic
  30. * @author Martin Buchholz
  31. */
  32. import java.io.*;
  33. import java.util.*;
  34. import java.security.*;
  35. import java.util.regex.Pattern;
  36. import static java.lang.System.getenv;
  37. import static java.lang.System.out;
  38. import static java.lang.Boolean.TRUE;
  39. import static java.util.AbstractMap.SimpleImmutableEntry;
  40. public class Basic {
  41. private static String commandOutput(Reader r) throws Throwable {
  42. StringBuilder sb = new StringBuilder();
  43. int c;
  44. while ((c = r.read()) > 0)
  45. if (c != '\r')
  46. sb.append((char) c);
  47. return sb.toString();
  48. }
  49. private static String commandOutput(Process p) throws Throwable {
  50. check(p.getInputStream() == p.getInputStream());
  51. check(p.getOutputStream() == p.getOutputStream());
  52. check(p.getErrorStream() == p.getErrorStream());
  53. Reader r = new InputStreamReader(p.getInputStream(),"UTF-8");
  54. String output = commandOutput(r);
  55. equal(p.waitFor(), 0);
  56. equal(p.exitValue(), 0);
  57. return output;
  58. }
  59. private static String commandOutput(ProcessBuilder pb) {
  60. try {
  61. return commandOutput(pb.start());
  62. } catch (Throwable t) {
  63. String commandline = "";
  64. for (String arg : pb.command())
  65. commandline += " " + arg;
  66. System.out.println("Exception trying to run process: " + commandline);
  67. unexpected(t);
  68. return "";
  69. }
  70. }
  71. private static String commandOutput(String...command) {
  72. try {
  73. return commandOutput(Runtime.getRuntime().exec(command));
  74. } catch (Throwable t) {
  75. String commandline = "";
  76. for (String arg : command)
  77. commandline += " " + arg;
  78. System.out.println("Exception trying to run process: " + commandline);
  79. unexpected(t);
  80. return "";
  81. }
  82. }
  83. private static void checkCommandOutput(ProcessBuilder pb,
  84. String expected,
  85. String failureMsg) {
  86. String got = commandOutput(pb);
  87. check(got.equals(expected),
  88. failureMsg + "\n" +
  89. "Expected: \"" + expected + "\"\n" +
  90. "Got: \"" + got + "\"");
  91. }
  92. private static String absolutifyPath(String path) {
  93. StringBuilder sb = new StringBuilder();
  94. for (String file : path.split(File.pathSeparator)) {
  95. if (sb.length() != 0)
  96. sb.append(File.pathSeparator);
  97. sb.append(new File(file).getAbsolutePath());
  98. }
  99. return sb.toString();
  100. }
  101. // compare windows-style, by canonicalizing to upper case,
  102. // not lower case as String.compareToIgnoreCase does
  103. private static class WindowsComparator
  104. implements Comparator<String> {
  105. public int compare(String x, String y) {
  106. return x.toUpperCase(Locale.US)
  107. .compareTo(y.toUpperCase(Locale.US));
  108. }
  109. }
  110. private static String sortedLines(String lines) {
  111. String[] arr = lines.split("\n");
  112. List<String> ls = new ArrayList<String>();
  113. for (String s : arr)
  114. ls.add(s);
  115. Collections.sort(ls, new WindowsComparator());
  116. StringBuilder sb = new StringBuilder();
  117. for (String s : ls)
  118. sb.append(s + "\n");
  119. return sb.toString();
  120. }
  121. private static void compareLinesIgnoreCase(String lines1, String lines2) {
  122. if (! (sortedLines(lines1).equalsIgnoreCase(sortedLines(lines2)))) {
  123. String dashes =
  124. "-----------------------------------------------------";
  125. out.println(dashes);
  126. out.print(sortedLines(lines1));
  127. out.println(dashes);
  128. out.print(sortedLines(lines2));
  129. out.println(dashes);
  130. out.println("sizes: " + sortedLines(lines1).length() +
  131. " " + sortedLines(lines2).length());
  132. fail("Sorted string contents differ");
  133. }
  134. }
  135. private static final Runtime runtime = Runtime.getRuntime();
  136. private static final String[] winEnvCommand = {"cmd.exe", "/c", "set"};
  137. private static String winEnvFilter(String env) {
  138. return env.replaceAll("\r", "")
  139. .replaceAll("(?m)^(?:COMSPEC|PROMPT|PATHEXT)=.*\n","");
  140. }
  141. private static String unixEnvProg() {
  142. return new File("/usr/bin/env").canExecute() ? "/usr/bin/env"
  143. : "/bin/env";
  144. }
  145. private static String nativeEnv(String[] env) {
  146. try {
  147. if (Windows.is()) {
  148. return winEnvFilter
  149. (commandOutput(runtime.exec(winEnvCommand, env)));
  150. } else {
  151. return commandOutput(runtime.exec(unixEnvProg(), env));
  152. }
  153. } catch (Throwable t) { throw new Error(t); }
  154. }
  155. private static String nativeEnv(ProcessBuilder pb) {
  156. try {
  157. if (Windows.is()) {
  158. pb.command(winEnvCommand);
  159. return winEnvFilter(commandOutput(pb));
  160. } else {
  161. pb.command(new String[]{unixEnvProg()});
  162. return commandOutput(pb);
  163. }
  164. } catch (Throwable t) { throw new Error(t); }
  165. }
  166. private static void checkSizes(Map<String,String> environ, int size) {
  167. try {
  168. equal(size, environ.size());
  169. equal(size, environ.entrySet().size());
  170. equal(size, environ.keySet().size());
  171. equal(size, environ.values().size());
  172. boolean isEmpty = (size == 0);
  173. equal(isEmpty, environ.isEmpty());
  174. equal(isEmpty, environ.entrySet().isEmpty());
  175. equal(isEmpty, environ.keySet().isEmpty());
  176. equal(isEmpty, environ.values().isEmpty());
  177. } catch (Throwable t) { unexpected(t); }
  178. }
  179. private interface EnvironmentFrobber {
  180. void doIt(Map<String,String> environ);
  181. }
  182. private static void testVariableDeleter(EnvironmentFrobber fooDeleter) {
  183. try {
  184. Map<String,String> environ = new ProcessBuilder().environment();
  185. environ.put("Foo", "BAAR");
  186. fooDeleter.doIt(environ);
  187. equal(environ.get("Foo"), null);
  188. equal(environ.remove("Foo"), null);
  189. } catch (Throwable t) { unexpected(t); }
  190. }
  191. private static void testVariableAdder(EnvironmentFrobber fooAdder) {
  192. try {
  193. Map<String,String> environ = new ProcessBuilder().environment();
  194. environ.remove("Foo");
  195. fooAdder.doIt(environ);
  196. equal(environ.get("Foo"), "Bahrein");
  197. } catch (Throwable t) { unexpected(t); }
  198. }
  199. private static void testVariableModifier(EnvironmentFrobber fooModifier) {
  200. try {
  201. Map<String,String> environ = new ProcessBuilder().environment();
  202. environ.put("Foo","OldValue");
  203. fooModifier.doIt(environ);
  204. equal(environ.get("Foo"), "NewValue");
  205. } catch (Throwable t) { unexpected(t); }
  206. }
  207. private static void printUTF8(String s) throws IOException {
  208. out.write(s.getBytes("UTF-8"));
  209. }
  210. private static String getenvAsString(Map<String,String> environment) {
  211. StringBuilder sb = new StringBuilder();
  212. for (Map.Entry<String,String> e : environment.entrySet())
  213. // Ignore magic environment variables added by the launcher
  214. if (! e.getKey().equals("NLSPATH") &&
  215. ! e.getKey().equals("XFILESEARCHPATH") &&
  216. ! e.getKey().equals("LD_LIBRARY_PATH"))
  217. sb.append(e.getKey())
  218. .append('=')
  219. .append(e.getValue())
  220. .append(',');
  221. return sb.toString();
  222. }
  223. static void print4095(OutputStream s) throws Throwable {
  224. byte[] bytes = new byte[4095];
  225. Arrays.fill(bytes, (byte) '!');
  226. s.write(bytes); // Might hang!
  227. }
  228. public static class JavaChild {
  229. public static void main(String args[]) throws Throwable {
  230. String action = args[0];
  231. if (action.equals("System.getenv(String)")) {
  232. String val = System.getenv(args[1]);
  233. printUTF8(val == null ? "null" : val);
  234. } else if (action.equals("System.getenv(\\u1234)")) {
  235. String val = System.getenv("\u1234");
  236. printUTF8(val == null ? "null" : val);
  237. } else if (action.equals("System.getenv()")) {
  238. printUTF8(getenvAsString(System.getenv()));
  239. } else if (action.equals("pwd")) {
  240. printUTF8(new File(System.getProperty("user.dir"))
  241. .getCanonicalPath());
  242. } else if (action.equals("print4095")) {
  243. print4095(System.out);
  244. System.exit(5);
  245. } else if (action.equals("OutErr")) {
  246. // You might think the system streams would be
  247. // buffered, and in fact they are implemented using
  248. // BufferedOutputStream, but each and every print
  249. // causes immediate operating system I/O.
  250. System.out.print("out");
  251. System.err.print("err");
  252. System.out.print("out");
  253. System.err.print("err");
  254. } else if (action.equals("null PATH")) {
  255. equal(System.getenv("PATH"), null);
  256. check(new File("/bin/true").exists());
  257. check(new File("/bin/false").exists());
  258. ProcessBuilder pb1 = new ProcessBuilder();
  259. ProcessBuilder pb2 = new ProcessBuilder();
  260. pb2.environment().put("PATH", "anyOldPathIgnoredAnyways");
  261. ProcessResults r;
  262. for (final ProcessBuilder pb :
  263. new ProcessBuilder[] {pb1, pb2}) {
  264. pb.command("true");
  265. r = run(pb.start());
  266. equal(r.exitValue(), True.exitValue());
  267. pb.command("false");
  268. r = run(pb.start());
  269. equal(r.exitValue(), False.exitValue());
  270. }
  271. if (failed != 0) throw new Error("null PATH");
  272. } else if (action.equals("PATH search algorithm")) {
  273. equal(System.getenv("PATH"), "dir1:dir2:");
  274. check(new File("/bin/true").exists());
  275. check(new File("/bin/false").exists());
  276. String[] cmd = {"prog"};
  277. ProcessBuilder pb1 = new ProcessBuilder(cmd);
  278. ProcessBuilder pb2 = new ProcessBuilder(cmd);
  279. ProcessBuilder pb3 = new ProcessBuilder(cmd);
  280. pb2.environment().put("PATH", "anyOldPathIgnoredAnyways");
  281. pb3.environment().remove("PATH");
  282. for (final ProcessBuilder pb :
  283. new ProcessBuilder[] {pb1, pb2, pb3}) {
  284. try {
  285. // Not on PATH at all; directories don't exist
  286. try {
  287. pb.start();
  288. fail("Expected IOException not thrown");
  289. } catch (IOException e) {
  290. String m = e.getMessage();
  291. if (EnglishUnix.is() &&
  292. ! matches(m, "No such file"))
  293. unexpected(e);
  294. } catch (Throwable t) { unexpected(t); }
  295. // Not on PATH at all; directories exist
  296. new File("dir1").mkdirs();
  297. new File("dir2").mkdirs();
  298. try {
  299. pb.start();
  300. fail("Expected IOException not thrown");
  301. } catch (IOException e) {
  302. String m = e.getMessage();
  303. if (EnglishUnix.is() &&
  304. ! matches(m, "No such file"))
  305. unexpected(e);
  306. } catch (Throwable t) { unexpected(t); }
  307. // Can't execute a directory -- permission denied
  308. // Report EACCES errno
  309. new File("dir1/prog").mkdirs();
  310. try {
  311. pb.start();
  312. fail("Expected IOException not thrown");
  313. } catch (IOException e) {
  314. String m = e.getMessage();
  315. if (EnglishUnix.is() &&
  316. ! matches(m, "Permission denied"))
  317. unexpected(e);
  318. } catch (Throwable t) { unexpected(t); }
  319. // continue searching if EACCES
  320. copy("/bin/true", "dir2/prog");
  321. equal(run(pb.start()).exitValue(), True.exitValue());
  322. new File("dir1/prog").delete();
  323. new File("dir2/prog").delete();
  324. new File("dir2/prog").mkdirs();
  325. copy("/bin/true", "dir1/prog");
  326. equal(run(pb.start()).exitValue(), True.exitValue());
  327. // Check empty PATH component means current directory
  328. new File("dir1/prog").delete();
  329. new File("dir2/prog").delete();
  330. copy("/bin/true", "./prog");
  331. equal(run(pb.start()).exitValue(), True.exitValue());
  332. // If prog found on both parent and child's PATH,
  333. // parent's is used.
  334. new File("dir1/prog").delete();
  335. new File("dir2/prog").delete();
  336. new File("prog").delete();
  337. new File("dir3").mkdirs();
  338. copy("/bin/true", "dir1/prog");
  339. copy("/bin/false", "dir3/prog");
  340. pb.environment().put("PATH","dir3");
  341. equal(run(pb.start()).exitValue(), True.exitValue());
  342. copy("/bin/true", "dir3/prog");
  343. copy("/bin/false", "dir1/prog");
  344. equal(run(pb.start()).exitValue(), False.exitValue());
  345. } finally {
  346. // cleanup
  347. new File("dir1/prog").delete();
  348. new File("dir2/prog").delete();
  349. new File("dir3/prog").delete();
  350. new File("dir1").delete();
  351. new File("dir2").delete();
  352. new File("dir3").delete();
  353. new File("prog").delete();
  354. }
  355. }
  356. if (failed != 0) throw new Error("PATH search algorithm");
  357. }
  358. else throw new Error("JavaChild invocation error");
  359. }
  360. }
  361. private static void copy(String src, String dst) {
  362. system("/bin/cp", "-fp", src, dst);
  363. }
  364. private static void system(String... command) {
  365. try {
  366. ProcessBuilder pb = new ProcessBuilder(command);
  367. ProcessResults r = run(pb.start());
  368. equal(r.exitValue(), 0);
  369. equal(r.out(), "");
  370. equal(r.err(), "");
  371. } catch (Throwable t) { unexpected(t); }
  372. }
  373. private static String javaChildOutput(ProcessBuilder pb, String...args) {
  374. List<String> list = new ArrayList<String>(javaChildArgs);
  375. for (String arg : args)
  376. list.add(arg);
  377. pb.command(list);
  378. return commandOutput(pb);
  379. }
  380. private static String getenvInChild(ProcessBuilder pb) {
  381. return javaChildOutput(pb, "System.getenv()");
  382. }
  383. private static String getenvInChild1234(ProcessBuilder pb) {
  384. return javaChildOutput(pb, "System.getenv(\\u1234)");
  385. }
  386. private static String getenvInChild(ProcessBuilder pb, String name) {
  387. return javaChildOutput(pb, "System.getenv(String)", name);
  388. }
  389. private static String pwdInChild(ProcessBuilder pb) {
  390. return javaChildOutput(pb, "pwd");
  391. }
  392. private static final String javaExe =
  393. System.getProperty("java.home") +
  394. File.separator + "bin" + File.separator + "java";
  395. private static final String classpath =
  396. System.getProperty("java.class.path");
  397. private static final List<String> javaChildArgs =
  398. Arrays.asList(new String[]
  399. { javaExe, "-classpath", absolutifyPath(classpath),
  400. "Basic$JavaChild"});
  401. private static void testEncoding(String encoding, String tested) {
  402. try {
  403. // If round trip conversion works, should be able to set env vars
  404. // correctly in child.
  405. if (new String(tested.getBytes()).equals(tested)) {
  406. out.println("Testing " + encoding + " environment values");
  407. ProcessBuilder pb = new ProcessBuilder();
  408. pb.environment().put("ASCIINAME",tested);
  409. equal(getenvInChild(pb,"ASCIINAME"), tested);
  410. }
  411. } catch (Throwable t) { unexpected(t); }
  412. }
  413. static class Windows {
  414. public static boolean is() { return is; }
  415. private static final boolean is =
  416. System.getProperty("os.name").startsWith("Windows");
  417. }
  418. static class Unix {
  419. public static boolean is() { return is; }
  420. private static final boolean is =
  421. (! Windows.is() &&
  422. new File("/bin/sh").exists() &&
  423. new File("/bin/true").exists() &&
  424. new File("/bin/false").exists());
  425. }
  426. static class UnicodeOS {
  427. public static boolean is() { return is; }
  428. private static final String osName = System.getProperty("os.name");
  429. private static final boolean is =
  430. // MacOS X would probably also qualify
  431. osName.startsWith("Windows") &&
  432. ! osName.startsWith("Windows 9") &&
  433. ! osName.equals("Windows Me");
  434. }
  435. static class True {
  436. public static int exitValue() { return 0; }
  437. }
  438. private static class False {
  439. public static int exitValue() { return exitValue; }
  440. private static final int exitValue = exitValue0();
  441. private static int exitValue0() {
  442. // /bin/false returns an *unspecified* non-zero number.
  443. try {
  444. if (! Unix.is())
  445. return -1;
  446. else {
  447. int rc = new ProcessBuilder("/bin/false")
  448. .start().waitFor();
  449. check(rc != 0);
  450. return rc;
  451. }
  452. } catch (Throwable t) { unexpected(t); return -1; }
  453. }
  454. }
  455. static class EnglishUnix {
  456. private final static Boolean is =
  457. (! Windows.is() && isEnglish("LANG") && isEnglish("LC_ALL"));
  458. private static boolean isEnglish(String envvar) {
  459. String val = getenv(envvar);
  460. return (val == null) || val.matches("en.*");
  461. }
  462. /** Returns true if we can expect English OS error strings */
  463. static boolean is() { return is; }
  464. }
  465. private static boolean matches(String str, String regex) {
  466. return Pattern.compile(regex).matcher(str).find();
  467. }
  468. private static String sortByLinesWindowsly(String text) {
  469. String[] lines = text.split("\n");
  470. Arrays.sort(lines, new WindowsComparator());
  471. StringBuilder sb = new StringBuilder();
  472. for (String line : lines)
  473. sb.append(line).append("\n");
  474. return sb.toString();
  475. }
  476. private static void checkMapSanity(Map<String,String> map) {
  477. try {
  478. Set<String> keySet = map.keySet();
  479. Collection<String> values = map.values();
  480. Set<Map.Entry<String,String>> entrySet = map.entrySet();
  481. equal(entrySet.size(), keySet.size());
  482. equal(entrySet.size(), values.size());
  483. StringBuilder s1 = new StringBuilder();
  484. for (Map.Entry<String,String> e : entrySet)
  485. s1.append(e.getKey() + "=" + e.getValue() + "\n");
  486. StringBuilder s2 = new StringBuilder();
  487. for (String var : keySet)
  488. s2.append(var + "=" + map.get(var) + "\n");
  489. equal(s1.toString(), s2.toString());
  490. Iterator<String> kIter = keySet.iterator();
  491. Iterator<String> vIter = values.iterator();
  492. Iterator<Map.Entry<String,String>> eIter = entrySet.iterator();
  493. while (eIter.hasNext()) {
  494. Map.Entry<String,String> entry = eIter.next();
  495. String key = kIter.next();
  496. String value = vIter.next();
  497. check(entrySet.contains(entry));
  498. check(keySet.contains(key));
  499. check(values.contains(value));
  500. check(map.containsKey(key));
  501. check(map.containsValue(value));
  502. equal(entry.getKey(), key);
  503. equal(entry.getValue(), value);
  504. }
  505. check(! kIter.hasNext() &&
  506. ! vIter.hasNext());
  507. } catch (Throwable t) { unexpected(t); }
  508. }
  509. private static void checkMapEquality(Map<String,String> map1,
  510. Map<String,String> map2) {
  511. try {
  512. equal(map1.size(), map2.size());
  513. equal(map1.isEmpty(), map2.isEmpty());
  514. for (String key : map1.keySet()) {
  515. equal(map1.get(key), map2.get(key));
  516. check(map2.keySet().contains(key));
  517. }
  518. equal(map1, map2);
  519. equal(map2, map1);
  520. equal(map1.entrySet(), map2.entrySet());
  521. equal(map2.entrySet(), map1.entrySet());
  522. equal(map1.keySet(), map2.keySet());
  523. equal(map2.keySet(), map1.keySet());
  524. equal(map1.hashCode(), map2.hashCode());
  525. equal(map1.entrySet().hashCode(), map2.entrySet().hashCode());
  526. equal(map1.keySet().hashCode(), map2.keySet().hashCode());
  527. } catch (Throwable t) { unexpected(t); }
  528. }
  529. private static void realMain(String[] args) throws Throwable {
  530. if (Windows.is())
  531. System.out.println("This appears to be a Windows system.");
  532. if (Unix.is())
  533. System.out.println("This appears to be a Unix system.");
  534. if (UnicodeOS.is())
  535. System.out.println("This appears to be a Unicode-based OS.");
  536. //----------------------------------------------------------------
  537. // Basic tests for setting, replacing and deleting envvars
  538. //----------------------------------------------------------------
  539. try {
  540. ProcessBuilder pb = new ProcessBuilder();
  541. Map<String,String> environ = pb.environment();
  542. // New env var
  543. environ.put("QUUX", "BAR");
  544. equal(environ.get("QUUX"), "BAR");
  545. equal(getenvInChild(pb,"QUUX"), "BAR");
  546. // Modify env var
  547. environ.put("QUUX","bear");
  548. equal(environ.get("QUUX"), "bear");
  549. equal(getenvInChild(pb,"QUUX"), "bear");
  550. checkMapSanity(environ);
  551. // Remove env var
  552. environ.remove("QUUX");
  553. equal(environ.get("QUUX"), null);
  554. equal(getenvInChild(pb,"QUUX"), "null");
  555. checkMapSanity(environ);
  556. // Remove non-existent env var
  557. environ.remove("QUUX");
  558. equal(environ.get("QUUX"), null);
  559. equal(getenvInChild(pb,"QUUX"), "null");
  560. checkMapSanity(environ);
  561. } catch (Throwable t) { unexpected(t); }
  562. //----------------------------------------------------------------
  563. // Pass Empty environment to child
  564. //----------------------------------------------------------------
  565. try {
  566. ProcessBuilder pb = new ProcessBuilder();
  567. pb.environment().clear();
  568. equal(getenvInChild(pb), "");
  569. } catch (Throwable t) { unexpected(t); }
  570. //----------------------------------------------------------------
  571. // System.getenv() is read-only.
  572. //----------------------------------------------------------------
  573. THROWS(UnsupportedOperationException.class,
  574. new Fun(){void f(){ getenv().put("FOO","BAR");}},
  575. new Fun(){void f(){ getenv().remove("PATH");}},
  576. new Fun(){void f(){ getenv().keySet().remove("PATH");}},
  577. new Fun(){void f(){ getenv().values().remove("someValue");}});
  578. try {
  579. Collection<Map.Entry<String,String>> c = getenv().entrySet();
  580. if (! c.isEmpty())
  581. try {
  582. c.iterator().next().setValue("foo");
  583. fail("Expected UnsupportedOperationException not thrown");
  584. } catch (UnsupportedOperationException e) {} // OK
  585. } catch (Throwable t) { unexpected(t); }
  586. //----------------------------------------------------------------
  587. // System.getenv() always returns the same object in our implementation.
  588. //----------------------------------------------------------------
  589. try {
  590. check(System.getenv() == System.getenv());
  591. } catch (Throwable t) { unexpected(t); }
  592. //----------------------------------------------------------------
  593. // You can't create an env var name containing "=",
  594. // or an env var name or value containing NUL.
  595. //----------------------------------------------------------------
  596. {
  597. final Map<String,String> m = new ProcessBuilder().environment();
  598. THROWS(IllegalArgumentException.class,
  599. new Fun(){void f(){ m.put("FOO=","BAR");}},
  600. new Fun(){void f(){ m.put("FOO\u0000","BAR");}},
  601. new Fun(){void f(){ m.put("FOO","BAR\u0000");}});
  602. }
  603. //----------------------------------------------------------------
  604. // Commands must never be null.
  605. //----------------------------------------------------------------
  606. THROWS(NullPointerException.class,
  607. new Fun(){void f(){
  608. new ProcessBuilder((List<String>)null);}},
  609. new Fun(){void f(){
  610. new ProcessBuilder().command((List<String>)null);}});
  611. //----------------------------------------------------------------
  612. // Put in a command; get the same one back out.
  613. //----------------------------------------------------------------
  614. try {
  615. List<String> command = new ArrayList<String>();
  616. ProcessBuilder pb = new ProcessBuilder(command);
  617. check(pb.command() == command);
  618. List<String> command2 = new ArrayList<String>(2);
  619. command2.add("foo");
  620. command2.add("bar");
  621. pb.command(command2);
  622. check(pb.command() == command2);
  623. pb.command("foo", "bar");
  624. check(pb.command() != command2 && pb.command().equals(command2));
  625. pb.command(command2);
  626. command2.add("baz");
  627. equal(pb.command().get(2), "baz");
  628. } catch (Throwable t) { unexpected(t); }
  629. //----------------------------------------------------------------
  630. // Commands must contain at least one element.
  631. //----------------------------------------------------------------
  632. THROWS(IndexOutOfBoundsException.class,
  633. new Fun() { void f() throws IOException {
  634. new ProcessBuilder().start();}},
  635. new Fun() { void f() throws IOException {
  636. new ProcessBuilder(new ArrayList<String>()).start();}},
  637. new Fun() { void f() throws IOException {
  638. Runtime.getRuntime().exec(new String[]{});}});
  639. //----------------------------------------------------------------
  640. // Commands must not contain null elements at start() time.
  641. //----------------------------------------------------------------
  642. THROWS(NullPointerException.class,
  643. new Fun() { void f() throws IOException {
  644. new ProcessBuilder("foo",null,"bar").start();}},
  645. new Fun() { void f() throws IOException {
  646. new ProcessBuilder((String)null).start();}},
  647. new Fun() { void f() throws IOException {
  648. new ProcessBuilder(new String[]{null}).start();}},
  649. new Fun() { void f() throws IOException {
  650. new ProcessBuilder(new String[]{"foo",null,"bar"}).start();}});
  651. //----------------------------------------------------------------
  652. // Command lists are growable.
  653. //----------------------------------------------------------------
  654. try {
  655. new ProcessBuilder().command().add("foo");
  656. new ProcessBuilder("bar").command().add("foo");
  657. new ProcessBuilder(new String[]{"1","2"}).command().add("3");
  658. } catch (Throwable t) { unexpected(t); }
  659. //----------------------------------------------------------------
  660. // Nulls in environment updates generate NullPointerException
  661. //----------------------------------------------------------------
  662. try {
  663. final Map<String,String> env = new ProcessBuilder().environment();
  664. THROWS(NullPointerException.class,
  665. new Fun(){void f(){ env.put("foo",null);}},
  666. new Fun(){void f(){ env.put(null,"foo");}},
  667. new Fun(){void f(){ env.remove(null);}},
  668. new Fun(){void f(){
  669. for (Map.Entry<String,String> e : env.entrySet())
  670. e.setValue(null);}},
  671. new Fun() { void f() throws IOException {
  672. Runtime.getRuntime().exec(new String[]{"foo"},
  673. new String[]{null});}});
  674. } catch (Throwable t) { unexpected(t); }
  675. //----------------------------------------------------------------
  676. // Non-String types in environment updates generate ClassCastException
  677. //----------------------------------------------------------------
  678. try {
  679. final Map<String,String> env = new ProcessBuilder().environment();
  680. THROWS(ClassCastException.class,
  681. new Fun(){void f(){ env.remove(TRUE);}},
  682. new Fun(){void f(){ env.keySet().remove(TRUE);}},
  683. new Fun(){void f(){ env.values().remove(TRUE);}},
  684. new Fun(){void f(){ env.entrySet().remove(TRUE);}});
  685. } catch (Throwable t) { unexpected(t); }
  686. //----------------------------------------------------------------
  687. // Check query operations on environment maps
  688. //----------------------------------------------------------------
  689. try {
  690. List<Map<String,String>> envs =
  691. new ArrayList<Map<String,String>>(2);
  692. envs.add(System.getenv());
  693. envs.add(new ProcessBuilder().environment());
  694. for (final Map<String,String> env : envs) {
  695. //----------------------------------------------------------------
  696. // Nulls in environment queries are forbidden.
  697. //----------------------------------------------------------------
  698. THROWS(NullPointerException.class,
  699. new Fun(){void f(){ getenv(null);}},
  700. new Fun(){void f(){ env.get(null);}},
  701. new Fun(){void f(){ env.containsKey(null);}},
  702. new Fun(){void f(){ env.containsValue(null);}},
  703. new Fun(){void f(){ env.keySet().contains(null);}},
  704. new Fun(){void f(){ env.values().contains(null);}});
  705. //----------------------------------------------------------------
  706. // Non-String types in environment queries are forbidden.
  707. //----------------------------------------------------------------
  708. THROWS(ClassCastException.class,
  709. new Fun(){void f(){ env.get(TRUE);}},
  710. new Fun(){void f(){ env.containsKey(TRUE);}},
  711. new Fun(){void f(){ env.containsValue(TRUE);}},
  712. new Fun(){void f(){ env.keySet().contains(TRUE);}},
  713. new Fun(){void f(){ env.values().contains(TRUE);}});
  714. //----------------------------------------------------------------
  715. // Illegal String values in environment queries are (grumble) OK
  716. //----------------------------------------------------------------
  717. equal(env.get("\u0000"), null);
  718. check(! env.containsKey("\u0000"));
  719. check(! env.containsValue("\u0000"));
  720. check(! env.keySet().contains("\u0000"));
  721. check(! env.values().contains("\u0000"));
  722. }
  723. } catch (Throwable t) { unexpected(t); }
  724. try {
  725. final Set<Map.Entry<String,String>> entrySet =
  726. new ProcessBuilder().environment().entrySet();
  727. THROWS(NullPointerException.class,
  728. new Fun(){void f(){ entrySet.contains(null);}});
  729. THROWS(ClassCastException.class,
  730. new Fun(){void f(){ entrySet.contains(TRUE);}},
  731. new Fun(){void f(){
  732. entrySet.contains(
  733. new SimpleImmutableEntry<Boolean,String>(TRUE,""));}});
  734. check(! entrySet.contains
  735. (new SimpleImmutableEntry<String,String>("", "")));
  736. } catch (Throwable t) { unexpected(t); }
  737. //----------------------------------------------------------------
  738. // Put in a directory; get the same one back out.
  739. //----------------------------------------------------------------
  740. try {
  741. ProcessBuilder pb = new ProcessBuilder();
  742. File foo = new File("foo");
  743. equal(pb.directory(), null);
  744. equal(pb.directory(foo).directory(), foo);
  745. equal(pb.directory(null).directory(), null);
  746. } catch (Throwable t) { unexpected(t); }
  747. //----------------------------------------------------------------
  748. // If round-trip conversion works, check envvar pass-through to child
  749. //----------------------------------------------------------------
  750. try {
  751. testEncoding("ASCII", "xyzzy");
  752. testEncoding("Latin1", "\u00f1\u00e1");
  753. testEncoding("Unicode", "\u22f1\u11e1");
  754. } catch (Throwable t) { unexpected(t); }
  755. //----------------------------------------------------------------
  756. // A surprisingly large number of ways to delete an environment var.
  757. //----------------------------------------------------------------
  758. testVariableDeleter(new EnvironmentFrobber() {
  759. public void doIt(Map<String,String> environ) {
  760. environ.remove("Foo");}});
  761. testVariableDeleter(new EnvironmentFrobber() {
  762. public void doIt(Map<String,String> environ) {
  763. environ.keySet().remove("Foo");}});
  764. testVariableDeleter(new EnvironmentFrobber() {
  765. public void doIt(Map<String,String> environ) {
  766. environ.values().remove("BAAR");}});
  767. testVariableDeleter(new EnvironmentFrobber() {
  768. public void doIt(Map<String,String> environ) {
  769. // Legally fabricate a ProcessEnvironment.StringEntry,
  770. // even though it's private.
  771. Map<String,String> environ2
  772. = new ProcessBuilder().environment();
  773. environ2.clear();
  774. environ2.put("Foo","BAAR");
  775. // Subtlety alert.
  776. Map.Entry<String,String> e
  777. = environ2.entrySet().iterator().next();
  778. environ.entrySet().remove(e);}});
  779. testVariableDeleter(new EnvironmentFrobber() {
  780. public void doIt(Map<String,String> environ) {
  781. Map.Entry<String,String> victim = null;
  782. for (Map.Entry<String,String> e : environ.entrySet())
  783. if (e.getKey().equals("Foo"))
  784. victim = e;
  785. if (victim != null)
  786. environ.entrySet().remove(victim);}});
  787. testVariableDeleter(new EnvironmentFrobber() {
  788. public void doIt(Map<String,String> environ) {
  789. Iterator<String> it = environ.keySet().iterator();
  790. while (it.hasNext()) {
  791. String val = it.next();
  792. if (val.equals("Foo"))
  793. it.remove();}}});
  794. testVariableDeleter(new EnvironmentFrobber() {
  795. public void doIt(Map<String,String> environ) {
  796. Iterator<Map.Entry<String,String>> it
  797. = environ.entrySet().iterator();
  798. while (it.hasNext()) {
  799. Map.Entry<String,String> e = it.next();
  800. if (e.getKey().equals("Foo"))
  801. it.remove();}}});
  802. testVariableDeleter(new EnvironmentFrobber() {
  803. public void doIt(Map<String,String> environ) {
  804. Iterator<String> it = environ.values().iterator();
  805. while (it.hasNext()) {
  806. String val = it.next();
  807. if (val.equals("BAAR"))
  808. it.remove();}}});
  809. //----------------------------------------------------------------
  810. // A surprisingly small number of ways to add an environment var.
  811. //----------------------------------------------------------------
  812. testVariableAdder(new EnvironmentFrobber() {
  813. public void doIt(Map<String,String> environ) {
  814. environ.put("Foo","Bahrein");}});
  815. //----------------------------------------------------------------
  816. // A few ways to modify an environment var.
  817. //----------------------------------------------------------------
  818. testVariableModifier(new EnvironmentFrobber() {
  819. public void doIt(Map<String,String> environ) {
  820. environ.put("Foo","NewValue");}});
  821. testVariableModifier(new EnvironmentFrobber() {
  822. public void doIt(Map<String,String> environ) {
  823. for (Map.Entry<String,String> e : environ.entrySet())
  824. if (e.getKey().equals("Foo"))
  825. e.setValue("NewValue");}});
  826. //----------------------------------------------------------------
  827. // Fiddle with environment sizes
  828. //----------------------------------------------------------------
  829. try {
  830. Map<String,String> environ = new ProcessBuilder().environment();
  831. int size = environ.size();
  832. checkSizes(environ, size);
  833. environ.put("UnLiKeLYeNVIROmtNam", "someVal");
  834. checkSizes(environ, size+1);
  835. // Check for environment independence
  836. new ProcessBuilder().environment().clear();
  837. environ.put("UnLiKeLYeNVIROmtNam", "someOtherVal");
  838. checkSizes(environ, size+1);
  839. environ.remove("UnLiKeLYeNVIROmtNam");
  840. checkSizes(environ, size);
  841. environ.clear();
  842. checkSizes(environ, 0);
  843. environ.clear();
  844. checkSizes(environ, 0);
  845. environ = new ProcessBuilder().environment();
  846. environ.keySet().clear();
  847. checkSizes(environ, 0);
  848. environ = new ProcessBuilder().environment();
  849. environ.entrySet().clear();
  850. checkSizes(environ, 0);
  851. environ = new ProcessBuilder().environment();
  852. environ.values().clear();
  853. checkSizes(environ, 0);
  854. } catch (Throwable t) { unexpected(t); }
  855. //----------------------------------------------------------------
  856. // Check that various map invariants hold
  857. //----------------------------------------------------------------
  858. checkMapSanity(new ProcessBuilder().environment());
  859. checkMapSanity(System.getenv());
  860. checkMapEquality(new ProcessBuilder().environment(),
  861. new ProcessBuilder().environment());
  862. //----------------------------------------------------------------
  863. // Check effects on external "env" command.
  864. //----------------------------------------------------------------
  865. try {
  866. Set<String> env1 = new HashSet<String>
  867. (Arrays.asList(nativeEnv((String[])null).split("\n")));
  868. ProcessBuilder pb = new ProcessBuilder();
  869. pb.environment().put("QwErTyUiOp","AsDfGhJk");
  870. Set<String> env2 = new HashSet<String>
  871. (Arrays.asList(nativeEnv(pb).split("\n")));
  872. check(env2.size() == env1.size() + 1);
  873. env1.add("QwErTyUiOp=AsDfGhJk");
  874. check(env1.equals(env2));
  875. } catch (Throwable t) { unexpected(t); }
  876. //----------------------------------------------------------------
  877. // Test Runtime.exec(...envp...)
  878. // Check for sort order of environment variables on Windows.
  879. //----------------------------------------------------------------
  880. try {
  881. // '+' < 'A' < 'Z' < '_' < 'a' < 'z' < '~'
  882. String[]envp = {"FOO=BAR","BAZ=GORP","QUUX=",
  883. "+=+", "_=_", "~=~"};
  884. String output = nativeEnv(envp);
  885. String expected = "+=+\nBAZ=GORP\nFOO=BAR\nQUUX=\n_=_\n~=~\n";
  886. // On Windows, Java must keep the environment sorted.
  887. // Order is random on Unix, so this test does the sort.
  888. if (! Windows.is())
  889. output = sortByLinesWindowsly(output);
  890. equal(output, expected);
  891. } catch (Throwable t) { unexpected(t); }
  892. //----------------------------------------------------------------
  893. // System.getenv() must be consistent with System.getenv(String)
  894. //----------------------------------------------------------------
  895. try {
  896. for (Map.Entry<String,String> e : getenv().entrySet())
  897. equal(getenv(e.getKey()), e.getValue());
  898. } catch (Throwable t) { unexpected(t); }
  899. //----------------------------------------------------------------
  900. // Fiddle with working directory in child
  901. //----------------------------------------------------------------
  902. try {
  903. String canonicalUserDir =
  904. new File(System.getProperty("user.dir")).getCanonicalPath();
  905. String[] sdirs = new String[]
  906. {".", "..", "/", "/bin",
  907. "C:", "c:", "C:/", "c:\\", "\\", "\\bin" };
  908. for (String sdir : sdirs) {
  909. File dir = new File(sdir);
  910. if (! (dir.isDirectory() && dir.exists()))
  911. continue;
  912. out.println("Testing directory " + dir);
  913. dir = new File(dir.getCanonicalPath());
  914. ProcessBuilder pb = new ProcessBuilder();
  915. equal(pb.directory(), null);
  916. equal(pwdInChild(pb), canonicalUserDir);
  917. pb.directory(dir);
  918. equal(pb.directory(), dir);
  919. equal(pwdInChild(pb), dir.toString());
  920. pb.directory(null);
  921. equal(pb.directory(), null);
  922. equal(pwdInChild(pb), canonicalUserDir);
  923. pb.directory(dir);
  924. }
  925. } catch (Throwable t) { unexpected(t); }
  926. //----------------------------------------------------------------
  927. // Windows has tricky semi-case-insensitive semantics
  928. //----------------------------------------------------------------
  929. if (Windows.is())
  930. try {
  931. out.println("Running case insensitve variable tests");
  932. for (String[] namePair :
  933. new String[][]
  934. { new String[]{"PATH","PaTh"},
  935. new String[]{"home","HOME"},
  936. new String[]{"SYSTEMROOT","SystemRoot"}}) {
  937. check((getenv(namePair[0]) == null &&
  938. getenv(namePair[1]) == null)
  939. ||
  940. getenv(namePair[0]).equals(getenv(namePair[1])),
  941. "Windows environment variables are not case insensitive");
  942. }
  943. } catch (Throwable t) { unexpected(t); }
  944. //----------------------------------------------------------------
  945. // Test proper Unicode child environment transfer
  946. //----------------------------------------------------------------
  947. if (UnicodeOS.is())
  948. try {
  949. ProcessBuilder pb = new ProcessBuilder();
  950. pb.environment().put("\u1234","\u5678");
  951. pb.environment().remove("PATH");
  952. equal(getenvInChild1234(pb), "\u5678");
  953. } catch (Throwable t) { unexpected(t); }
  954. //----------------------------------------------------------------
  955. // Test Runtime.exec(...envp...) with envstrings with initial `='
  956. //----------------------------------------------------------------
  957. try {
  958. List<String> childArgs = new ArrayList<String>(javaChildArgs);
  959. childArgs.add("System.getenv()");
  960. String[] cmdp = childArgs.toArray(new String[childArgs.size()]);
  961. String[] envp = {"=ExitValue=3", "=C:=\\"};
  962. Process p = Runtime.getRuntime().exec(cmdp, envp);
  963. String expected = Windows.is() ? "=C:=\\,=ExitValue=3," : "=C:=\\,";
  964. equal(commandOutput(p), expected);
  965. if (Windows.is()) {
  966. ProcessBuilder pb = new ProcessBuilder(childArgs);
  967. pb.environment().clear();
  968. pb.environment().put("=ExitValue", "3");
  969. pb.environment().put("=C:", "\\");
  970. equal(commandOutput(pb), expected);
  971. }
  972. } catch (Throwable t) { unexpected(t); }
  973. //----------------------------------------------------------------
  974. // Test Runtime.exec(...envp...) with envstrings without any `='
  975. //----------------------------------------------------------------
  976. try {
  977. String[] cmdp = {"echo"};
  978. String[] envp = {"Hello", "World"}; // Yuck!
  979. Process p = Runtime.getRuntime().exec(cmdp, envp);
  980. equal(commandOutput(p), "\n");
  981. } catch (Throwable t) { unexpected(t); }
  982. //----------------------------------------------------------------
  983. // Test Runtime.exec(...envp...) with envstrings containing NULs
  984. //----------------------------------------------------------------
  985. try {
  986. List<String> childArgs = new ArrayList<String>(javaChildArgs);
  987. childArgs.add("System.getenv()");
  988. String[] cmdp = childArgs.toArray(new String[childArgs.size()]);
  989. String[] envp = {"LC_ALL=C\u0000\u0000", // Yuck!
  990. "FO\u0000=B\u0000R"};
  991. Process p = Runtime.getRuntime().exec(cmdp, envp);
  992. check(commandOutput(p).equals("LC_ALL=C,"),
  993. "Incorrect handling of envstrings containing NULs");
  994. } catch (Throwable t) { unexpected(t); }
  995. //----------------------------------------------------------------
  996. // Test the redirectErrorStream property
  997. //----------------------------------------------------------------
  998. try {
  999. ProcessBuilder pb = new ProcessBuilder();
  1000. equal(pb.redirectErrorStream(), false);
  1001. equal(pb.redirectErrorStream(true), pb);
  1002. equal(pb.redirectErrorStream(), true);
  1003. equal(pb.redirectErrorStream(false), pb);
  1004. equal(pb.redirectErrorStream(), false);
  1005. } catch (Throwable t) { unexpected(t); }
  1006. try {
  1007. List<String> childArgs = new ArrayList<String>(javaChildArgs);
  1008. childArgs.add("OutErr");
  1009. ProcessBuilder pb = new ProcessBuilder(childArgs);
  1010. {
  1011. ProcessResults r = run(pb.start());
  1012. equal(r.out(

Large files files are truncated, but you can click here to view the full file