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