jdk/test/java/lang/ProcessBuilder/Basic.java
changeset 24692 268fbc344d53
parent 24577 b3bf9c82a050
child 25804 4ae4525723a5
equal deleted inserted replaced
24691:f96e172a6ce8 24692:268fbc344d53
     1 /*
     1 /*
     2  * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     7  * published by the Free Software Foundation.
   935         pb.redirectError(efile);
   935         pb.redirectError(efile);
   936         equal(pb.redirectError().file(), efile);
   936         equal(pb.redirectError().file(), efile);
   937         equal(pb.redirectError(), Redirect.to(efile));
   937         equal(pb.redirectError(), Redirect.to(efile));
   938 
   938 
   939         THROWS(IllegalArgumentException.class,
   939         THROWS(IllegalArgumentException.class,
   940             new Fun(){void f() {
   940                () -> pb.redirectInput(Redirect.to(ofile)),
   941                 pb.redirectInput(Redirect.to(ofile)); }},
   941                () -> pb.redirectOutput(Redirect.from(ifile)),
   942             new Fun(){void f() {
   942                () -> pb.redirectError(Redirect.from(ifile)));
   943                 pb.redirectInput(Redirect.appendTo(ofile)); }},
       
   944             new Fun(){void f() {
       
   945                 pb.redirectOutput(Redirect.from(ifile)); }},
       
   946             new Fun(){void f() {
       
   947                 pb.redirectError(Redirect.from(ifile)); }});
       
   948 
   943 
   949         THROWS(IOException.class,
   944         THROWS(IOException.class,
   950                // Input file does not exist
   945                // Input file does not exist
   951                new Fun(){void f() throws Throwable { pb.start(); }});
   946                () -> pb.start());
   952         setFileContents(ifile, "standard input");
   947         setFileContents(ifile, "standard input");
   953 
   948 
   954         //----------------------------------------------------------------
   949         //----------------------------------------------------------------
   955         // Writing to non-existent files
   950         // Writing to non-existent files
   956         //----------------------------------------------------------------
   951         //----------------------------------------------------------------
  1082                 = new FilePermission("<<ALL FILES>>", "write,execute");
  1077                 = new FilePermission("<<ALL FILES>>", "write,execute");
  1083             final Permission rwxPermission
  1078             final Permission rwxPermission
  1084                 = new FilePermission("<<ALL FILES>>", "read,write,execute");
  1079                 = new FilePermission("<<ALL FILES>>", "read,write,execute");
  1085 
  1080 
  1086             THROWS(SecurityException.class,
  1081             THROWS(SecurityException.class,
  1087                new Fun() { void f() throws IOException {
  1082                    () -> { policy.setPermissions(xPermission);
  1088                    policy.setPermissions(xPermission);
  1083                            redirectIO(pb, from(tmpFile), PIPE, PIPE);
  1089                    redirectIO(pb, from(tmpFile), PIPE, PIPE);
  1084                            pb.start();},
  1090                    pb.start();}},
  1085                    () -> { policy.setPermissions(rxPermission);
  1091                new Fun() { void f() throws IOException {
  1086                            redirectIO(pb, PIPE, to(ofile), PIPE);
  1092                    policy.setPermissions(rxPermission);
  1087                            pb.start();},
  1093                    redirectIO(pb, PIPE, to(ofile), PIPE);
  1088                    () -> { policy.setPermissions(rxPermission);
  1094                    pb.start();}},
  1089                            redirectIO(pb, PIPE, PIPE, to(efile));
  1095                new Fun() { void f() throws IOException {
  1090                            pb.start();});
  1096                    policy.setPermissions(rxPermission);
       
  1097                    redirectIO(pb, PIPE, PIPE, to(efile));
       
  1098                    pb.start();}});
       
  1099 
  1091 
  1100             {
  1092             {
  1101                 policy.setPermissions(rxPermission);
  1093                 policy.setPermissions(rxPermission);
  1102                 redirectIO(pb, from(tmpFile), PIPE, PIPE);
  1094                 redirectIO(pb, from(tmpFile), PIPE, PIPE);
  1103                 ProcessResults r = run(pb);
  1095                 ProcessResults r = run(pb);
  1256 
  1248 
  1257         //----------------------------------------------------------------
  1249         //----------------------------------------------------------------
  1258         // System.getenv() is read-only.
  1250         // System.getenv() is read-only.
  1259         //----------------------------------------------------------------
  1251         //----------------------------------------------------------------
  1260         THROWS(UnsupportedOperationException.class,
  1252         THROWS(UnsupportedOperationException.class,
  1261             new Fun(){void f(){ getenv().put("FOO","BAR");}},
  1253                () -> getenv().put("FOO","BAR"),
  1262             new Fun(){void f(){ getenv().remove("PATH");}},
  1254                () -> getenv().remove("PATH"),
  1263             new Fun(){void f(){ getenv().keySet().remove("PATH");}},
  1255                () -> getenv().keySet().remove("PATH"),
  1264             new Fun(){void f(){ getenv().values().remove("someValue");}});
  1256                () -> getenv().values().remove("someValue"));
  1265 
  1257 
  1266         try {
  1258         try {
  1267             Collection<Map.Entry<String,String>> c = getenv().entrySet();
  1259             Collection<Map.Entry<String,String>> c = getenv().entrySet();
  1268             if (! c.isEmpty())
  1260             if (! c.isEmpty())
  1269                 try {
  1261                 try {
  1284         // or an env var name or value containing NUL.
  1276         // or an env var name or value containing NUL.
  1285         //----------------------------------------------------------------
  1277         //----------------------------------------------------------------
  1286         {
  1278         {
  1287             final Map<String,String> m = new ProcessBuilder().environment();
  1279             final Map<String,String> m = new ProcessBuilder().environment();
  1288             THROWS(IllegalArgumentException.class,
  1280             THROWS(IllegalArgumentException.class,
  1289                 new Fun(){void f(){ m.put("FOO=","BAR");}},
  1281                    () -> m.put("FOO=","BAR"),
  1290                 new Fun(){void f(){ m.put("FOO\u0000","BAR");}},
  1282                    () -> m.put("FOO\u0000","BAR"),
  1291                 new Fun(){void f(){ m.put("FOO","BAR\u0000");}});
  1283                    () -> m.put("FOO","BAR\u0000"));
  1292         }
  1284         }
  1293 
  1285 
  1294         //----------------------------------------------------------------
  1286         //----------------------------------------------------------------
  1295         // Commands must never be null.
  1287         // Commands must never be null.
  1296         //----------------------------------------------------------------
  1288         //----------------------------------------------------------------
  1297         THROWS(NullPointerException.class,
  1289         THROWS(NullPointerException.class,
  1298                new Fun(){void f(){
  1290                () -> new ProcessBuilder((List<String>)null),
  1299                    new ProcessBuilder((List<String>)null);}},
  1291                () -> new ProcessBuilder().command((List<String>)null));
  1300                new Fun(){void f(){
       
  1301                    new ProcessBuilder().command((List<String>)null);}});
       
  1302 
  1292 
  1303         //----------------------------------------------------------------
  1293         //----------------------------------------------------------------
  1304         // Put in a command; get the same one back out.
  1294         // Put in a command; get the same one back out.
  1305         //----------------------------------------------------------------
  1295         //----------------------------------------------------------------
  1306         try {
  1296         try {
  1321 
  1311 
  1322         //----------------------------------------------------------------
  1312         //----------------------------------------------------------------
  1323         // Commands must contain at least one element.
  1313         // Commands must contain at least one element.
  1324         //----------------------------------------------------------------
  1314         //----------------------------------------------------------------
  1325         THROWS(IndexOutOfBoundsException.class,
  1315         THROWS(IndexOutOfBoundsException.class,
  1326             new Fun() { void f() throws IOException {
  1316                () -> new ProcessBuilder().start(),
  1327                 new ProcessBuilder().start();}},
  1317                () -> new ProcessBuilder(new ArrayList<String>()).start(),
  1328             new Fun() { void f() throws IOException {
  1318                () -> Runtime.getRuntime().exec(new String[]{}));
  1329                 new ProcessBuilder(new ArrayList<String>()).start();}},
       
  1330             new Fun() { void f() throws IOException {
       
  1331                 Runtime.getRuntime().exec(new String[]{});}});
       
  1332 
  1319 
  1333         //----------------------------------------------------------------
  1320         //----------------------------------------------------------------
  1334         // Commands must not contain null elements at start() time.
  1321         // Commands must not contain null elements at start() time.
  1335         //----------------------------------------------------------------
  1322         //----------------------------------------------------------------
  1336         THROWS(NullPointerException.class,
  1323         THROWS(NullPointerException.class,
  1337             new Fun() { void f() throws IOException {
  1324                () -> new ProcessBuilder("foo",null,"bar").start(),
  1338                 new ProcessBuilder("foo",null,"bar").start();}},
  1325                () -> new ProcessBuilder((String)null).start(),
  1339             new Fun() { void f() throws IOException {
  1326                () -> new ProcessBuilder(new String[]{null}).start(),
  1340                 new ProcessBuilder((String)null).start();}},
  1327                () -> new ProcessBuilder(new String[]{"foo",null,"bar"}).start());
  1341             new Fun() { void f() throws IOException {
       
  1342                 new ProcessBuilder(new String[]{null}).start();}},
       
  1343             new Fun() { void f() throws IOException {
       
  1344                 new ProcessBuilder(new String[]{"foo",null,"bar"}).start();}});
       
  1345 
  1328 
  1346         //----------------------------------------------------------------
  1329         //----------------------------------------------------------------
  1347         // Command lists are growable.
  1330         // Command lists are growable.
  1348         //----------------------------------------------------------------
  1331         //----------------------------------------------------------------
  1349         try {
  1332         try {
  1356         // Nulls in environment updates generate NullPointerException
  1339         // Nulls in environment updates generate NullPointerException
  1357         //----------------------------------------------------------------
  1340         //----------------------------------------------------------------
  1358         try {
  1341         try {
  1359             final Map<String,String> env = new ProcessBuilder().environment();
  1342             final Map<String,String> env = new ProcessBuilder().environment();
  1360             THROWS(NullPointerException.class,
  1343             THROWS(NullPointerException.class,
  1361                 new Fun(){void f(){ env.put("foo",null);}},
  1344                    () -> env.put("foo",null),
  1362                 new Fun(){void f(){ env.put(null,"foo");}},
  1345                    () -> env.put(null,"foo"),
  1363                 new Fun(){void f(){ env.remove(null);}},
  1346                    () -> env.remove(null),
  1364                 new Fun(){void f(){
  1347                    () -> { for (Map.Entry<String,String> e : env.entrySet())
  1365                     for (Map.Entry<String,String> e : env.entrySet())
  1348                                e.setValue(null);},
  1366                         e.setValue(null);}},
  1349                    () -> Runtime.getRuntime().exec(new String[]{"foo"},
  1367                 new Fun() { void f() throws IOException {
  1350                                                    new String[]{null}));
  1368                     Runtime.getRuntime().exec(new String[]{"foo"},
       
  1369                                               new String[]{null});}});
       
  1370         } catch (Throwable t) { unexpected(t); }
  1351         } catch (Throwable t) { unexpected(t); }
  1371 
  1352 
  1372         //----------------------------------------------------------------
  1353         //----------------------------------------------------------------
  1373         // Non-String types in environment updates generate ClassCastException
  1354         // Non-String types in environment updates generate ClassCastException
  1374         //----------------------------------------------------------------
  1355         //----------------------------------------------------------------
  1375         try {
  1356         try {
  1376             final Map<String,String> env = new ProcessBuilder().environment();
  1357             final Map<String,String> env = new ProcessBuilder().environment();
  1377             THROWS(ClassCastException.class,
  1358             THROWS(ClassCastException.class,
  1378                 new Fun(){void f(){ env.remove(TRUE);}},
  1359                    () -> env.remove(TRUE),
  1379                 new Fun(){void f(){ env.keySet().remove(TRUE);}},
  1360                    () -> env.keySet().remove(TRUE),
  1380                 new Fun(){void f(){ env.values().remove(TRUE);}},
  1361                    () -> env.values().remove(TRUE),
  1381                 new Fun(){void f(){ env.entrySet().remove(TRUE);}});
  1362                    () -> env.entrySet().remove(TRUE));
  1382         } catch (Throwable t) { unexpected(t); }
  1363         } catch (Throwable t) { unexpected(t); }
  1383 
  1364 
  1384         //----------------------------------------------------------------
  1365         //----------------------------------------------------------------
  1385         // Check query operations on environment maps
  1366         // Check query operations on environment maps
  1386         //----------------------------------------------------------------
  1367         //----------------------------------------------------------------
  1392             for (final Map<String,String> env : envs) {
  1373             for (final Map<String,String> env : envs) {
  1393                 //----------------------------------------------------------------
  1374                 //----------------------------------------------------------------
  1394                 // Nulls in environment queries are forbidden.
  1375                 // Nulls in environment queries are forbidden.
  1395                 //----------------------------------------------------------------
  1376                 //----------------------------------------------------------------
  1396                 THROWS(NullPointerException.class,
  1377                 THROWS(NullPointerException.class,
  1397                     new Fun(){void f(){ getenv(null);}},
  1378                        () -> getenv(null),
  1398                     new Fun(){void f(){ env.get(null);}},
  1379                        () -> env.get(null),
  1399                     new Fun(){void f(){ env.containsKey(null);}},
  1380                        () -> env.containsKey(null),
  1400                     new Fun(){void f(){ env.containsValue(null);}},
  1381                        () -> env.containsValue(null),
  1401                     new Fun(){void f(){ env.keySet().contains(null);}},
  1382                        () -> env.keySet().contains(null),
  1402                     new Fun(){void f(){ env.values().contains(null);}});
  1383                        () -> env.values().contains(null));
  1403 
  1384 
  1404                 //----------------------------------------------------------------
  1385                 //----------------------------------------------------------------
  1405                 // Non-String types in environment queries are forbidden.
  1386                 // Non-String types in environment queries are forbidden.
  1406                 //----------------------------------------------------------------
  1387                 //----------------------------------------------------------------
  1407                 THROWS(ClassCastException.class,
  1388                 THROWS(ClassCastException.class,
  1408                     new Fun(){void f(){ env.get(TRUE);}},
  1389                        () -> env.get(TRUE),
  1409                     new Fun(){void f(){ env.containsKey(TRUE);}},
  1390                        () -> env.containsKey(TRUE),
  1410                     new Fun(){void f(){ env.containsValue(TRUE);}},
  1391                        () -> env.containsValue(TRUE),
  1411                     new Fun(){void f(){ env.keySet().contains(TRUE);}},
  1392                        () -> env.keySet().contains(TRUE),
  1412                     new Fun(){void f(){ env.values().contains(TRUE);}});
  1393                        () -> env.values().contains(TRUE));
  1413 
  1394 
  1414                 //----------------------------------------------------------------
  1395                 //----------------------------------------------------------------
  1415                 // Illegal String values in environment queries are (grumble) OK
  1396                 // Illegal String values in environment queries are (grumble) OK
  1416                 //----------------------------------------------------------------
  1397                 //----------------------------------------------------------------
  1417                 equal(env.get("\u0000"), null);
  1398                 equal(env.get("\u0000"), null);
  1425 
  1406 
  1426         try {
  1407         try {
  1427             final Set<Map.Entry<String,String>> entrySet =
  1408             final Set<Map.Entry<String,String>> entrySet =
  1428                 new ProcessBuilder().environment().entrySet();
  1409                 new ProcessBuilder().environment().entrySet();
  1429             THROWS(NullPointerException.class,
  1410             THROWS(NullPointerException.class,
  1430                    new Fun(){void f(){ entrySet.contains(null);}});
  1411                    () -> entrySet.contains(null));
  1431             THROWS(ClassCastException.class,
  1412             THROWS(ClassCastException.class,
  1432                 new Fun(){void f(){ entrySet.contains(TRUE);}},
  1413                    () -> entrySet.contains(TRUE),
  1433                 new Fun(){void f(){
  1414                    () -> entrySet.contains(
  1434                     entrySet.contains(
  1415                              new SimpleImmutableEntry<Boolean,String>(TRUE,"")));
  1435                         new SimpleImmutableEntry<Boolean,String>(TRUE,""));}});
       
  1436 
  1416 
  1437             check(! entrySet.contains
  1417             check(! entrySet.contains
  1438                   (new SimpleImmutableEntry<String,String>("", "")));
  1418                   (new SimpleImmutableEntry<String,String>("", "")));
  1439         } catch (Throwable t) { unexpected(t); }
  1419         } catch (Throwable t) { unexpected(t); }
  1440 
  1420 
  1900                 new File("suBdiR").mkdirs();
  1880                 new File("suBdiR").mkdirs();
  1901                 copy("/bin/true", "suBdiR/unliKely");
  1881                 copy("/bin/true", "suBdiR/unliKely");
  1902                 final ProcessBuilder pb =
  1882                 final ProcessBuilder pb =
  1903                     new ProcessBuilder(new String[]{"unliKely"});
  1883                     new ProcessBuilder(new String[]{"unliKely"});
  1904                 pb.environment().put("PATH", "suBdiR");
  1884                 pb.environment().put("PATH", "suBdiR");
  1905                 THROWS(IOException.class,
  1885                 THROWS(IOException.class, () -> pb.start());
  1906                        new Fun() {void f() throws Throwable {pb.start();}});
       
  1907             } catch (Throwable t) { unexpected(t);
  1886             } catch (Throwable t) { unexpected(t);
  1908             } finally {
  1887             } finally {
  1909                 new File("suBdiR/unliKely").delete();
  1888                 new File("suBdiR/unliKely").delete();
  1910                 new File("suBdiR").delete();
  1889                 new File("suBdiR").delete();
  1911             }
  1890             }
  1974             print4095(p.getOutputStream(), (byte) '!'); // Might hang!
  1953             print4095(p.getOutputStream(), (byte) '!'); // Might hang!
  1975             p.waitFor();                                // Might hang!
  1954             p.waitFor();                                // Might hang!
  1976             equal(SIZE, p.getInputStream().available());
  1955             equal(SIZE, p.getInputStream().available());
  1977             equal(SIZE, p.getErrorStream().available());
  1956             equal(SIZE, p.getErrorStream().available());
  1978             THROWS(IOException.class,
  1957             THROWS(IOException.class,
  1979                    new Fun(){void f() throws IOException {
  1958                    () -> { p.getOutputStream().write((byte) '!');
  1980                        p.getOutputStream().write((byte) '!');
  1959                            p.getOutputStream().flush();});
  1981                        p.getOutputStream().flush();
       
  1982                        }});
       
  1983 
  1960 
  1984             final byte[] bytes = new byte[SIZE + 1];
  1961             final byte[] bytes = new byte[SIZE + 1];
  1985             equal(SIZE, p.getInputStream().read(bytes));
  1962             equal(SIZE, p.getInputStream().read(bytes));
  1986             for (int i = 0; i < SIZE; i++)
  1963             for (int i = 0; i < SIZE; i++)
  1987                 equal((byte) '!', bytes[i]);
  1964                 equal((byte) '!', bytes[i]);
  2004             try { p.getOutputStream().close(); } catch (IOException flushFailed) { }
  1981             try { p.getOutputStream().close(); } catch (IOException flushFailed) { }
  2005 
  1982 
  2006             InputStream[] streams = { p.getInputStream(), p.getErrorStream() };
  1983             InputStream[] streams = { p.getInputStream(), p.getErrorStream() };
  2007             for (final InputStream in : streams) {
  1984             for (final InputStream in : streams) {
  2008                 Fun[] ops = {
  1985                 Fun[] ops = {
  2009                     new Fun(){void f() throws IOException {
  1986                     () -> in.read(),
  2010                         in.read(); }},
  1987                     () -> in.read(bytes),
  2011                     new Fun(){void f() throws IOException {
  1988                     () -> in.available()
  2012                         in.read(bytes); }},
       
  2013                     new Fun(){void f() throws IOException {
       
  2014                         in.available(); }}
       
  2015                 };
  1989                 };
  2016                 for (Fun op : ops) {
  1990                 for (Fun op : ops) {
  2017                     try {
  1991                     try {
  2018                         op.f();
  1992                         op.f();
  2019                         fail();
  1993                         fail();
  2213             new ProcessBuilder("env").directory(new File("dir")).directory();
  2187             new ProcessBuilder("env").directory(new File("dir")).directory();
  2214             new ProcessBuilder("env").command("??").command();
  2188             new ProcessBuilder("env").command("??").command();
  2215         } catch (Throwable t) { unexpected(t); }
  2189         } catch (Throwable t) { unexpected(t); }
  2216 
  2190 
  2217         THROWS(SecurityException.class,
  2191         THROWS(SecurityException.class,
  2218             new Fun() { void f() throws IOException {
  2192                () -> { policy.setPermissions(/* Nothing */);
  2219                 policy.setPermissions(/* Nothing */);
  2193                        System.getenv("foo");},
  2220                 System.getenv("foo");}},
  2194                () -> { policy.setPermissions(/* Nothing */);
  2221             new Fun() { void f() throws IOException {
  2195                        System.getenv();},
  2222                 policy.setPermissions(/* Nothing */);
  2196                () -> { policy.setPermissions(/* Nothing */);
  2223                 System.getenv();}},
  2197                        new ProcessBuilder("echo").start();},
  2224             new Fun() { void f() throws IOException {
  2198                () -> { policy.setPermissions(/* Nothing */);
  2225                 policy.setPermissions(/* Nothing */);
  2199                        Runtime.getRuntime().exec("echo");},
  2226                 new ProcessBuilder("echo").start();}},
  2200                () -> { policy.setPermissions(
  2227             new Fun() { void f() throws IOException {
  2201                                new RuntimePermission("getenv.bar"));
  2228                 policy.setPermissions(/* Nothing */);
  2202                        System.getenv("foo");});
  2229                 Runtime.getRuntime().exec("echo");}},
       
  2230             new Fun() { void f() throws IOException {
       
  2231                 policy.setPermissions(new RuntimePermission("getenv.bar"));
       
  2232                 System.getenv("foo");}});
       
  2233 
  2203 
  2234         try {
  2204         try {
  2235             policy.setPermissions(new RuntimePermission("getenv.foo"));
  2205             policy.setPermissions(new RuntimePermission("getenv.foo"));
  2236             System.getenv("foo");
  2206             System.getenv("foo");
  2237 
  2207 
  2244 
  2214 
  2245         final Permission execPermission
  2215         final Permission execPermission
  2246             = new FilePermission("<<ALL FILES>>", "execute");
  2216             = new FilePermission("<<ALL FILES>>", "execute");
  2247 
  2217 
  2248         THROWS(SecurityException.class,
  2218         THROWS(SecurityException.class,
  2249             new Fun() { void f() throws IOException {
  2219                () -> { // environment permission by itself insufficient
  2250                 // environment permission by itself insufficient
  2220                        policy.setPermissions(new RuntimePermission("getenv.*"));
  2251                 policy.setPermissions(new RuntimePermission("getenv.*"));
  2221                        ProcessBuilder pb = new ProcessBuilder("env");
  2252                 ProcessBuilder pb = new ProcessBuilder("env");
  2222                        pb.environment().put("foo","bar");
  2253                 pb.environment().put("foo","bar");
  2223                        pb.start();},
  2254                 pb.start();}},
  2224                () -> { // exec permission by itself insufficient
  2255             new Fun() { void f() throws IOException {
  2225                        policy.setPermissions(execPermission);
  2256                  // exec permission by itself insufficient
  2226                        ProcessBuilder pb = new ProcessBuilder("env");
  2257                  policy.setPermissions(execPermission);
  2227                        pb.environment().put("foo","bar");
  2258                  ProcessBuilder pb = new ProcessBuilder("env");
  2228                        pb.start();});
  2259                  pb.environment().put("foo","bar");
       
  2260                  pb.start();}});
       
  2261 
  2229 
  2262         try {
  2230         try {
  2263             // Both permissions? OK.
  2231             // Both permissions? OK.
  2264             policy.setPermissions(new RuntimePermission("getenv.*"),
  2232             policy.setPermissions(new RuntimePermission("getenv.*"),
  2265                                   execPermission);
  2233                                   execPermission);
  2583 
  2551 
  2584     public static void main(String[] args) throws Throwable {
  2552     public static void main(String[] args) throws Throwable {
  2585         try {realMain(args);} catch (Throwable t) {unexpected(t);}
  2553         try {realMain(args);} catch (Throwable t) {unexpected(t);}
  2586         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
  2554         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
  2587         if (failed > 0) throw new AssertionError("Some tests failed");}
  2555         if (failed > 0) throw new AssertionError("Some tests failed");}
  2588     private static abstract class Fun {abstract void f() throws Throwable;}
  2556     interface Fun {void f() throws Throwable;}
  2589     static void THROWS(Class<? extends Throwable> k, Fun... fs) {
  2557     static void THROWS(Class<? extends Throwable> k, Fun... fs) {
  2590         for (Fun f : fs)
  2558         for (Fun f : fs)
  2591             try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
  2559             try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
  2592             catch (Throwable t) {
  2560             catch (Throwable t) {
  2593                 if (k.isAssignableFrom(t.getClass())) pass();
  2561                 if (k.isAssignableFrom(t.getClass())) pass();