1 /*
2  * Copyright (c) 2013, 2019, 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 import java.security.CodeSource;
25 import java.security.Permission;
26 import java.security.PermissionCollection;
27 import java.security.Permissions;
28 import java.security.Policy;
29 import java.security.ProtectionDomain;
30 import java.util.EnumSet;
31 import java.util.HashMap;
32 import java.util.Map;
33 import java.util.logging.LogManager;
34 import java.util.logging.Logger;
35 import java.util.logging.LoggingPermission;
36 import jdk.internal.access.JavaAWTAccess;
37 import jdk.internal.access.SharedSecrets;
38 
39 /*
40  * @test
41  * @bug 8017174 8010727 8019945
42  * @summary  NPE when using Logger.getAnonymousLogger or
43  *           LogManager.getLogManager().getLogger
44  *
45  * @modules java.base/jdk.internal.access
46  *          java.logging
47  * @run main/othervm -Dtest.security=off TestAppletLoggerContext LoadingApplet
48  * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext  LoadingApplet
49  * @run main/othervm -Dtest.security=off TestAppletLoggerContext LoadingMain
50  * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext  LoadingMain
51  * @run main/othervm -Dtest.security=off TestAppletLoggerContext One
52  * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext  One
53  * @run main/othervm -Dtest.security=off TestAppletLoggerContext Two
54  * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext  Two
55  * @run main/othervm -Dtest.security=off TestAppletLoggerContext Three
56  * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext  Three
57  * @run main/othervm -Dtest.security=off TestAppletLoggerContext Four
58  * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext  Four
59  * @run main/othervm -Dtest.security=off TestAppletLoggerContext Five
60  * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext  Five
61  * @run main/othervm -Dtest.security=off TestAppletLoggerContext Six
62  * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext  Six
63  * @run main/othervm -Dtest.security=off TestAppletLoggerContext Seven
64  * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext  Seven
65  * @run main/othervm -Dtest.security=off TestAppletLoggerContext
66  * @run main/othervm -Djava.security.manager=allow -Dtest.security=on TestAppletLoggerContext
67  */
68 
69 // NOTE: We run in other VM in order to 1. switch security manager and 2. cause
70 // LogManager class to be loaded anew.
71 public class TestAppletLoggerContext {
72 
73     // Avoids the hassle of dealing with files and system props...
74     static class SimplePolicy extends Policy {
75 
76         static final Policy DEFAULT_POLICY = Policy.getPolicy();
77 
78         private final Permissions perms;
SimplePolicy(Permission... permissions)79         public SimplePolicy(Permission... permissions) {
80             perms = new Permissions();
81             for (Permission permission : permissions) {
82                 perms.add(permission);
83             }
84         }
85         @Override
getPermissions(CodeSource cs)86         public PermissionCollection getPermissions(CodeSource cs) {
87             return perms;
88         }
89         @Override
getPermissions(ProtectionDomain pd)90         public PermissionCollection getPermissions(ProtectionDomain pd) {
91             return perms;
92         }
93         @Override
implies(ProtectionDomain pd, Permission p)94         public boolean implies(ProtectionDomain pd, Permission p) {
95            return perms.implies(p) || DEFAULT_POLICY.implies(pd, p);
96         }
97     }
98 
99     // The bridge class initializes the logging system.
100     // It stubs the applet context in order to simulate context changes.
101     //
102     public static class Bridge {
103 
104         private static class JavaAWTAccessStub implements JavaAWTAccess {
105             boolean active = true;
106 
107             private static class TestExc {
108                 private final Map<Object, Object> map = new HashMap<>();
put(Object key, Object v)109                 void put(Object key, Object v) { map.put(key, v); }
get(Object key)110                 Object get(Object key) { return map.get(key); }
remove(Object o)111                 void remove(Object o) { map.remove(o); }
exc(Object o)112                 public static TestExc exc(Object o) {
113                     return TestExc.class.cast(o);
114                 }
115             }
116 
117             TestExc exc;
118 
119             @Override
getAppletContext()120             public Object getAppletContext() { return active ? exc : null; }
121         }
122 
123         static final JavaAWTAccessStub javaAwtAccess = new JavaAWTAccessStub();
init()124         public static void init() {
125             SharedSecrets.setJavaAWTAccess(javaAwtAccess);
126             if (System.getProperty("test.security", "on").equals("on")) {
127                 Policy p = new SimplePolicy(new LoggingPermission("control", null),
128                     new RuntimePermission("setContextClassLoader"),
129                     new RuntimePermission("shutdownHooks"));
130                 Policy.setPolicy(p);
131                 System.setSecurityManager(new SecurityManager());
132             }
133         }
134 
changeContext()135         public static void changeContext() {
136             System.out.println("... Switching to a new applet context ...");
137             javaAwtAccess.active = true;
138             javaAwtAccess.exc = new JavaAWTAccessStub.TestExc();
139         }
140 
desactivate()141         public static void desactivate() {
142             System.out.println("... Running with no applet context ...");
143             javaAwtAccess.exc = null;
144             javaAwtAccess.active = false;
145         }
146 
147         public static class CustomAnonymousLogger extends Logger {
CustomAnonymousLogger()148             public CustomAnonymousLogger() {
149                 this("");
150             }
CustomAnonymousLogger(String name)151             public CustomAnonymousLogger(String name) {
152                 super(null, null);
153                 System.out.println( " LogManager: " +LogManager.getLogManager());
154                 System.out.println( " getLogger: " +LogManager.getLogManager().getLogger(name));
155                 setParent(LogManager.getLogManager().getLogger(name));
156             }
157         }
158 
159         public static class CustomLogger extends Logger {
CustomLogger(String name)160             CustomLogger(String name) {
161                 super(name, null);
162             }
163         }
164     }
165 
166     public static enum TestCase {
167         LoadingApplet, LoadingMain, One, Two, Three, Four, Five, Six, Seven;
test()168         public void test() {
169             switch(this) {
170                 // When run - each of these two tests must be
171                 // run before any other tests and before each other.
172                 case LoadingApplet: testLoadingApplet(); break;
173                 case LoadingMain:   testLoadingMain(); break;
174                 case One:   testOne(); break;
175                 case Two:   testTwo(); break;
176                 case Three: testThree(); break;
177                 case Four:  testFour(); break;
178                 case Five:  testFive(); break;
179                 case Six:   testSix(); break;
180                 case Seven: testSeven(); break;
181             }
182         }
describe()183         public String describe() {
184             switch(this) {
185                 case LoadingApplet:
186                     return "Test that when the LogManager class is"
187                         + " loaded in  an applet thread first,"
188                         + "\n all LoggerContexts are correctly initialized";
189                 case LoadingMain:
190                     return "Test that when the LogManager class is"
191                         + " loaded in  the main thread first,"
192                         + "\n all LoggerContexts are correctly initialized";
193                 case One:
194                     return "Test that Logger.getAnonymousLogger()"
195                         + " and new CustomAnonymousLogger() don't throw NPE";
196                 case Two:
197                     return "Test that Logger.getLogger(\"\")"
198                             + " does not return null nor throws NPE";
199                 case Three:
200                     return "Test that LogManager.getLogManager().getLogger(\"\")"
201                             + " does not return null nor throws NPE";
202                 case Four:
203                     return "Test that Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)"
204                             + " does not return null,\n and that"
205                             + " new CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME)"
206                             + " does not throw NPE";
207                 case Five:
208                     return "Test that LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME)"
209                             + "\n does not return null nor throws NPE";
210                 case Six:
211                     return "Test that manager.getLogger(Logger.GLOBAL_LOGGER_NAME)"
212                             + " returns null\n when manager is not the default"
213                             + " LogManager instance.\n"
214                             + "Test adding a new logger named \"global\" in that"
215                             + " non default instance.";
216                 case Seven: return "Test that manager.getLogger(\"\")"
217                             + " returns null\n when manager is not the default"
218                             + " LogManager instance.\n"
219                             + "Test adding a new logger named \"\" in that"
220                             + " non default instance.";
221                 default: return "Undefined";
222             }
223         }
224     };
225 
226     /**
227      * @param args the command line arguments
228      */
main(String[] args)229     public static void main(String[] args) {
230         Bridge.init();
231         EnumSet<TestCase> tests = EnumSet.noneOf(TestCase.class);
232         for (String arg : args) {
233             tests.add(TestCase.valueOf(arg));
234         }
235         if (args.length == 0) {
236             tests = EnumSet.complementOf(EnumSet.of(TestCase.LoadingMain));
237         }
238         final EnumSet<TestCase> loadingTests =
239             EnumSet.of(TestCase.LoadingApplet, TestCase.LoadingMain);
240         int testrun = 0;
241         for (TestCase test : tests) {
242             if (loadingTests.contains(test)) {
243                 if (testrun > 0) {
244                     throw new UnsupportedOperationException("Test case "
245                           + test + " must be executed first!");
246                 }
247             }
248             System.out.println("Testing "+ test+": ");
249             System.out.println(test.describe());
250             try {
251                 test.test();
252             } catch (Exception x) {
253                throw new Error(String.valueOf(test)
254                    + (System.getSecurityManager() == null ? " without " : " with ")
255                    + "security failed: "+x+"\n "+"FAILED: "+test.describe()+"\n", x);
256             } finally {
257                 testrun++;
258             }
259             Bridge.changeContext();
260             System.out.println("PASSED: "+ test);
261         }
262     }
263 
testLoadingApplet()264     public static void testLoadingApplet() {
265         Bridge.changeContext();
266 
267         Logger bar = new Bridge.CustomLogger("com.foo.Bar");
268         LogManager.getLogManager().addLogger(bar);
269         assertNotNull(bar.getParent());
270         testParent(bar);
271         testParent(LogManager.getLogManager().getLogger("global"));
272         testParent(LogManager.getLogManager().getLogger(bar.getName()));
273 
274         Bridge.desactivate();
275 
276         Logger foo = new Bridge.CustomLogger("com.foo.Foo");
277         boolean b = LogManager.getLogManager().addLogger(foo);
278         assertEquals(Boolean.TRUE, Boolean.valueOf(b));
279         assertNotNull(foo.getParent());
280         testParent(foo);
281         testParent(LogManager.getLogManager().getLogger("global"));
282         testParent(LogManager.getLogManager().getLogger(foo.getName()));
283     }
284 
testLoadingMain()285     public static void testLoadingMain() {
286         Bridge.desactivate();
287 
288         Logger bar = new Bridge.CustomLogger("com.foo.Bar");
289         LogManager.getLogManager().addLogger(bar);
290         assertNotNull(bar.getParent());
291         testParent(bar);
292         testParent(LogManager.getLogManager().getLogger("global"));
293         testParent(LogManager.getLogManager().getLogger(bar.getName()));
294 
295         Bridge.changeContext();
296 
297         Logger foo = new Bridge.CustomLogger("com.foo.Foo");
298         boolean b = LogManager.getLogManager().addLogger(foo);
299         assertEquals(Boolean.TRUE, Boolean.valueOf(b));
300         assertNotNull(foo.getParent());
301         testParent(foo);
302         testParent(LogManager.getLogManager().getLogger("global"));
303         testParent(LogManager.getLogManager().getLogger(foo.getName()));
304 
305     }
306 
testOne()307     public static void testOne() {
308         for (int i=0; i<3 ; i++) {
309             Logger logger1 = Logger.getAnonymousLogger();
310             Logger logger1b = Logger.getAnonymousLogger();
311             Bridge.changeContext();
312             Logger logger2 = Logger.getAnonymousLogger();
313             Logger logger2b = Logger.getAnonymousLogger();
314             Bridge.changeContext();
315             Logger logger3 = new Bridge.CustomAnonymousLogger();
316             Logger logger3b = new Bridge.CustomAnonymousLogger();
317             Bridge.changeContext();
318             Logger logger4 = new Bridge.CustomAnonymousLogger();
319             Logger logger4b = new Bridge.CustomAnonymousLogger();
320         }
321     }
322 
323 
testTwo()324     public static void testTwo() {
325         for (int i=0; i<3 ; i++) {
326             Logger logger1 = Logger.getLogger("");
327             Logger logger1b = Logger.getLogger("");
328             assertNotNull(logger1);
329             assertNotNull(logger1b);
330             assertEquals(logger1, logger1b);
331             Bridge.changeContext();
332             Logger logger2 = Logger.getLogger("");
333             Logger logger2b = Logger.getLogger("");
334             assertNotNull(logger2);
335             assertNotNull(logger2b);
336             assertEquals(logger2, logger2b);
337             assertEquals(logger1, logger2);
338         }
339     }
340 
testThree()341     public static void testThree() {
342         for (int i=0; i<3 ; i++) {
343             Logger logger1 = LogManager.getLogManager().getLogger("");
344             Logger logger1b = LogManager.getLogManager().getLogger("");
345             assertNotNull(logger1);
346             assertNotNull(logger1b);
347             assertEquals(logger1, logger1b);
348             Bridge.changeContext();
349             Logger logger2 = LogManager.getLogManager().getLogger("");
350             Logger logger2b = LogManager.getLogManager().getLogger("");
351             assertNotNull(logger2);
352             assertNotNull(logger2b);
353             assertEquals(logger2, logger2b);
354             assertEquals(logger1, logger2);
355         }
356     }
357 
testFour()358     public static void testFour() {
359         for (int i=0; i<3 ; i++) {
360             Logger logger1 = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
361             Logger logger1b = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
362             assertNotNull(logger1);
363             assertNotNull(logger1b);
364             assertEquals(logger1, logger1b);
365             Bridge.changeContext();
366 
367             Logger logger2 = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
368             Logger logger2b = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
369             assertNotNull(logger2);
370             assertNotNull(logger2b);
371             assertEquals(logger2, logger2b);
372 
373             assertEquals(logger1, logger2);
374 
375             Bridge.changeContext();
376             Logger logger3 = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME);
377             Logger logger3b = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME);
378             Bridge.changeContext();
379             Logger logger4 = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME);
380             Logger logger4b = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME);
381         }
382     }
383 
testFive()384     public static void testFive() {
385         for (int i=0; i<3 ; i++) {
386             Logger logger1 = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME);
387             Logger logger1b = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME);
388             assertNotNull(logger1);
389             assertNotNull(logger1b);
390             assertEquals(logger1, logger1b);
391 
392             Bridge.changeContext();
393 
394             Logger logger2 = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME);
395             Logger logger2b = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME);
396             assertNotNull(logger2);
397             assertNotNull(logger2b);
398             assertEquals(logger2, logger2b);
399 
400             assertEquals(logger1, logger2);
401         }
402     }
403 
404     /**
405      * This test is designed to test the behavior of additional LogManager instances.
406      * It must be noted that if the security manager is off, then calling
407      * Bridge.changeContext() has actually no effect - which explains why we have
408      * some differences between the cases security manager on & security manager
409      * off.
410      **/
testSix()411     public static void testSix() {
412         for (int i=0; i<3 ; i++) {
413             Bridge.desactivate();
414             LogManager manager = new LogManager() {};
415             Logger logger1 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
416             Logger logger1b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
417             assertNull(logger1);
418             assertNull(logger1b);
419             Logger global = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
420             manager.addLogger(global);
421             Logger logger2 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
422             Logger logger2b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
423             assertNotNull(logger2);
424             assertNotNull(logger2b);
425             assertEquals(logger2, global);
426             assertEquals(logger2b, global);
427             assertNull(manager.getLogger(""));
428             assertNull(manager.getLogger(""));
429 
430             for (int j = 0; j<3; j++) {
431                 Bridge.changeContext();
432 
433                 // this is not a supported configuration:
434                 // We are in an applet context with several log managers.
435                 // We however need to check our assumptions...
436 
437                 // Applet context => root logger and global logger should also be null.
438 
439                 Logger expected = (System.getSecurityManager() == null ? global : null);
440                 Logger logger3 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
441                 Logger logger3b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
442                 assertEquals(expected, logger3);
443                 assertEquals(expected, logger3b);
444                 Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
445                 manager.addLogger(global2);
446                 Logger logger4 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
447                 Logger logger4b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
448                 assertNotNull(logger4);
449                 assertNotNull(logger4b);
450                 expected = (System.getSecurityManager() == null ? global : global2);;
451                 assertEquals(logger4,  expected);
452                 assertEquals(logger4b, expected);
453 
454                 Logger logger5 = manager.getLogger("");
455                 Logger logger5b = manager.getLogger("");
456                 Logger expectedRoot = null;
457                 assertEquals(logger5, expectedRoot);
458                 assertEquals(logger5b, expectedRoot);
459             }
460 
461         }
462     }
463 
464     /**
465      * This test is designed to test the behavior of additional LogManager instances.
466      * It must be noted that if the security manager is off, then calling
467      * Bridge.changeContext() has actually no effect - which explains why we have
468      * some differences between the cases security manager on & security manager
469      * off.
470      **/
testSeven()471     public static void testSeven() {
472         for (int i=0; i<3 ; i++) {
473             Bridge.desactivate();
474             LogManager manager = new LogManager() {};
475             Logger logger1 = manager.getLogger("");
476             Logger logger1b = manager.getLogger("");
477             assertNull(logger1);
478             assertNull(logger1b);
479             Logger global = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
480             manager.addLogger(global);
481             Logger logger2 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
482             Logger logger2b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
483             assertNotNull(logger2);
484             assertNotNull(logger2b);
485             assertEquals(logger2, global);
486             assertEquals(logger2b, global);
487             Logger logger3 = manager.getLogger("");
488             Logger logger3b = manager.getLogger("");
489             assertNull(logger3);
490             assertNull(logger3b);
491             Logger root = new Bridge.CustomLogger("");
492             manager.addLogger(root);
493             Logger logger4 = manager.getLogger("");
494             Logger logger4b = manager.getLogger("");
495             assertNotNull(logger4);
496             assertNotNull(logger4b);
497             assertEquals(logger4, root);
498             assertEquals(logger4b, root);
499 
500             for (int j = 0 ; j < 3 ; j++) {
501                 Bridge.changeContext();
502 
503                 // this is not a supported configuration:
504                 // We are in an applet context with several log managers.
505                 // We however need to check our assumptions...
506 
507                 // Applet context => root logger and global logger should also be null.
508 
509                 Logger logger5 = manager.getLogger("");
510                 Logger logger5b = manager.getLogger("");
511                 Logger expectedRoot = (System.getSecurityManager() == null ? root : null);
512                 assertEquals(logger5, expectedRoot);
513                 assertEquals(logger5b, expectedRoot);
514 
515                 if (System.getSecurityManager() != null) {
516                     assertNull(manager.getLogger(Logger.GLOBAL_LOGGER_NAME));
517                 } else {
518                     assertEquals(global, manager.getLogger(Logger.GLOBAL_LOGGER_NAME));
519                 }
520 
521                 Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
522                 manager.addLogger(global2);
523                 Logger logger6 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
524                 Logger logger6b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
525                 Logger expectedGlobal = (System.getSecurityManager() == null ? global : global2);
526 
527                 assertNotNull(logger6);
528                 assertNotNull(logger6b);
529                 assertEquals(logger6, expectedGlobal);
530                 assertEquals(logger6b, expectedGlobal);
531                 if (System.getSecurityManager() != null) {
532                     assertNull(manager.getLogger(""));
533                 } else {
534                     assertEquals(root, manager.getLogger(""));
535                 }
536 
537                 Logger root2 = new Bridge.CustomLogger("");
538                 manager.addLogger(root2);
539                 expectedRoot = (System.getSecurityManager() == null ? root : root2);
540                 Logger logger7 = manager.getLogger("");
541                 Logger logger7b = manager.getLogger("");
542                 assertNotNull(logger7);
543                 assertNotNull(logger7b);
544                 assertEquals(logger7, expectedRoot);
545                 assertEquals(logger7b, expectedRoot);
546             }
547         }
548     }
549 
testParent(Logger logger)550     public static void testParent(Logger logger) {
551         Logger l = logger;
552         while (l.getParent() != null) {
553             l = l.getParent();
554         }
555         assertEquals("", l.getName());
556     }
557 
558     public static class TestError extends RuntimeException {
TestError(String msg)559         public TestError(String msg) {
560             super(msg);
561         }
562     }
563 
assertNotNull(Object obj)564     public static void assertNotNull(Object obj) {
565         if (obj == null) throw new NullPointerException();
566     }
567 
assertNull(Object obj)568     public static void assertNull(Object obj) {
569         if (obj != null) throw new TestError("Null expected, got "+obj);
570     }
571 
assertEquals(Object o1, Object o2)572     public static void assertEquals(Object o1, Object o2) {
573         if (o1 != o2) {
574             throw new TestError(o1 + " != " + o2);
575         }
576     }
577 
assertNotEquals(Object o1, Object o2)578     public static void assertNotEquals(Object o1, Object o2) {
579         if (o1 == o2) {
580             throw new TestError(o1 + " == " + o2);
581         }
582     }
583 }
584