1 /*
   2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.awt.*;
  25 import java.awt.event.*;
  26 import java.awt.peer.ComponentPeer;
  27 import java.lang.reflect.Constructor;
  28 import java.lang.reflect.InvocationTargetException;
  29 import java.lang.reflect.Method;
  30 import java.util.ArrayList;
  31 import javax.swing.*;
  32 import sun.awt.*;
  33 import java.io.*;
  34 import test.java.awt.regtesthelpers.Util;
  35 
  36 /**
  37  * <p>This class provides basis for AWT Mixing testing.
  38  * <p>It provides all standard test machinery and should be used by
  39  * extending and overriding next methods:
  40  * <li> {@link OverlappingTestBase#prepareControls()} - setup UI components
  41  * <li> {@link OverlappingTestBase#performTest()} -  run particular test
  42  * Those methods would be run in the loop for each AWT component.
  43  * <p>Current AWT component should be added to the tested UI by {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) ()}.
  44  * There AWT components are prepared to be tested as being overlayed by other (e.g. Swing) components - they are colored to
  45  * {@link OverlappingTestBase#AWT_BACKGROUND_COLOR} and throws failure on catching mouse event.
  46  * <p> Validation of component being overlayed should be tested by {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point) }
  47  * See each method javadoc for more details.
  48  *
  49  * <p>Due to test machinery limitations all test should be run from their own main() by calling next coe
  50  * <code>
  51  *     public static void main(String args[]) throws InterruptedException {
  52  *        instance = new YourTestInstance();
  53  *        OverlappingTestBase.doMain(args);
  54  *     }
  55  * </code>
  56  *
  57  * @author Sergey Grinev
  58  */
  59 public abstract class OverlappingTestBase {
  60     // working variables
  61     private static volatile boolean wasHWClicked = false;
  62     private static volatile boolean passed = true;
  63     // constants
  64     /**
  65      * Default color for AWT component used for validate correct drawing of overlapping. <b>Never</b> use it for lightweight components.
  66      */
  67     protected static final Color AWT_BACKGROUND_COLOR = new Color(21, 244, 54);
  68     protected static Color AWT_VERIFY_COLOR = AWT_BACKGROUND_COLOR;
  69     protected static final int ROBOT_DELAY = 500;
  70     private static final String[] simpleAwtControls = {"Button", "Checkbox", "Label", "TextArea"};
  71     /**
  72      * Generic strings array. To be used for population of List based controls.
  73      */
  74     protected static final String[] petStrings = {"Bird", "Cat", "Dog", "Rabbit", "Rhynocephalia Granda", "Bear", "Tiger", "Mustang"};
  75     // "properties"
  76     /**
  77      * Tests customization. Set this variable to test only control from java.awt
  78      * <p>Usage of this variable should be marked with CR being the reason.
  79      * <p>Do not use this variable simultaneously with {@link OverlappingTestBase#skipClassNames}
  80      */
  81     protected String onlyClassName = null;
  82     /**
  83      * For customizing tests. List classes' simple names to skip them from testings.
  84      * <p>Usage of this variable should be marked with CR being the reason.
  85      */
  86     protected String[] skipClassNames = null;
  87     /**
  88      * Set to false to avoid event delivery validation
  89      * @see OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean)
  90      */
  91     protected boolean useClickValidation = true;
  92     /**
  93      * Set to false if test doesn't supposed to verify EmbeddedFrame
  94      */
  95     protected boolean testEmbeddedFrame = false;
  96     /**
  97      * Set this variable to true if testing embedded frame is impossible (on Mac, for instance, for now).
  98      * The testEmbeddedFrame is explicitly set to true in dozen places.
  99      */
 100     protected boolean skipTestingEmbeddedFrame = false;
 101 
 102     public static final boolean isMac = System.getProperty("os.name").toLowerCase().contains("os x");
 103     private boolean isFrameBorderCalculated;
 104     private int borderShift;
 105 
 106     {    if (Toolkit.getDefaultToolkit().getClass().getName().matches(".*L.*Toolkit")) {
 107              // No EmbeddedFrame in LWToolkit/LWCToolkit, yet
 108              // And it should be programmed some other way, too, in any case
 109              System.err.println("skipTestingEmbeddedFrame");
 110              skipTestingEmbeddedFrame = true;
 111          }else {
 112              System.err.println("do not skipTestingEmbeddedFrame");
 113          }
 114     }
 115 
 116     protected int frameBorderCounter() {
 117         if (!isFrameBorderCalculated) {
 118             try {
 119                 new FrameBorderCounter(); // force compilation by jtreg
 120                 String JAVA_HOME = System.getProperty("java.home");
 121                 Process p = Runtime.getRuntime().exec(JAVA_HOME + "/bin/java FrameBorderCounter");
 122                 try {
 123                     p.waitFor();
 124                 } catch (InterruptedException e) {
 125                     e.printStackTrace();
 126                     throw new RuntimeException(e);
 127                 }
 128                 if (p.exitValue() != 0) {
 129                     throw new RuntimeException("FrameBorderCounter exited with not null code!\n" + readInputStream(p.getErrorStream()));
 130                 }
 131                 borderShift = Integer.parseInt(readInputStream(p.getInputStream()).trim());
 132                 isFrameBorderCalculated = true;
 133             } catch (IOException e) {
 134                 e.printStackTrace();
 135                 throw new RuntimeException("Problem calculating a native border size");
 136             }
 137         }
 138         return borderShift;
 139     }
 140 
 141     public void getVerifyColor() {
 142         try {
 143             final int size = 200;
 144             final SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
 145             final Point[] p = new Point[1];
 146             SwingUtilities.invokeAndWait(new Runnable() {
 147                 public void run(){
 148                     JFrame frame = new JFrame("set back");
 149                     frame.getContentPane().setBackground(AWT_BACKGROUND_COLOR);
 150                     frame.setSize(size, size);
 151                     frame.setUndecorated(true);
 152                     frame.setVisible(true);
 153                     frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
 154                     p[0] = frame.getLocation();
 155                 }
 156             });
 157             Robot robot = new Robot();
 158             toolkit.realSync();
 159             Thread.sleep(ROBOT_DELAY);
 160             AWT_VERIFY_COLOR = robot.getPixelColor(p[0].x+size/2, p[0].y+size/2);
 161             System.out.println("Color will be compared with " + AWT_VERIFY_COLOR + " instead of " + AWT_BACKGROUND_COLOR);
 162         } catch (Exception e) {
 163             System.err.println("Cannot get verify color: "+e.getMessage());
 164         }
 165     }
 166 
 167     private String readInputStream(InputStream is) throws IOException {
 168         byte[] buffer = new byte[4096];
 169         int len = 0;
 170         StringBuilder sb = new StringBuilder();
 171         try (InputStreamReader isr = new InputStreamReader(is)) {
 172             while ((len = is.read(buffer)) > 0) {
 173                 sb.append(new String(buffer, 0, len));
 174             }
 175         }
 176         return sb.toString();
 177     }
 178 
 179     private void setupControl(final Component control) {
 180         if (useClickValidation) {
 181             control.addMouseListener(new MouseAdapter() {
 182                 @Override
 183                 public void mouseClicked(MouseEvent e) {
 184                     System.err.println("ERROR: " + control.getClass() + " received mouse click.");
 185                     wasHWClicked = true;
 186                 }
 187             });
 188         }
 189         control.setBackground(AWT_BACKGROUND_COLOR);
 190         control.setForeground(AWT_BACKGROUND_COLOR);
 191         control.setPreferredSize(new Dimension(150, 150));
 192         control.setFocusable(false);
 193     }
 194 
 195     private void addAwtControl(java.util.List<Component> container, final Component control) {
 196         String simpleName = control.getClass().getSimpleName();
 197         if (onlyClassName != null && !simpleName.equals(onlyClassName)) {
 198             return;
 199         }
 200         if (skipClassNames != null) {
 201             for (String skipMe : skipClassNames) {
 202                 if (simpleName.equals(skipMe)) {
 203                     return;
 204                 }
 205             }
 206         }
 207         setupControl(control);
 208         container.add(control);
 209     }
 210 
 211     private void addSimpleAwtControl(java.util.List<Component> container, String className) {
 212         try {
 213             Class definition = Class.forName("java.awt." + className);
 214             Constructor constructor = definition.getConstructor(new Class[]{String.class});
 215             java.awt.Component component = (java.awt.Component) constructor.newInstance(new Object[]{"AWT Component " + className});
 216             addAwtControl(container, component);
 217         } catch (Exception ex) {
 218             System.err.println(ex.getMessage());
 219             fail("Setup error, this jdk doesn't have awt conrol " + className);
 220         }
 221     }
 222 
 223     /**
 224      * Adds current AWT control to container
 225      * <p>N.B.: if testEmbeddedFrame == true this method will also add EmbeddedFrame over Canvas
 226      * and it should be called <b>after</b> Frame.setVisible(true) call
 227      * @param container container to hold AWT component
 228      */
 229     protected final void propagateAWTControls(Container container) {
 230         if (currentAwtControl != null) {
 231             container.add(currentAwtControl);
 232         } else { // embedded frame
 233             try {
 234 
 235                 //create embedder
 236                 Canvas embedder = new Canvas();
 237                 embedder.setBackground(Color.RED);
 238                 embedder.setPreferredSize(new Dimension(150, 150));
 239                 container.add(embedder);
 240                 container.setVisible(true); // create peer
 241 
 242                 long frameWindow = 0;
 243                 String getWindowMethodName = "getHWnd";
 244                 if (Toolkit.getDefaultToolkit().getClass().getName().contains("XToolkit")) {
 245                     getWindowMethodName = "getWindow";
 246                 }
 247                 ComponentPeer peer = embedder.getPeer();
 248 //                System.err.println("Peer: " + peer);
 249                 Method getWindowMethod = peer.getClass().getMethod(getWindowMethodName);
 250                 frameWindow = (Long) getWindowMethod.invoke(peer);
 251 //                System.err.println("frame peer ID: " + frameWindow);
 252 
 253                 String eframeClassName = "sun.awt.windows.WEmbeddedFrame";
 254                 if (Toolkit.getDefaultToolkit().getClass().getName().contains("XToolkit")) {
 255                     eframeClassName = "sun.awt.X11.XEmbeddedFrame";
 256                 }
 257                 Class eframeClass = Class.forName(eframeClassName);
 258                 Constructor eframeCtor = eframeClass.getConstructor(long.class);
 259                 EmbeddedFrame eframe = (EmbeddedFrame) eframeCtor.newInstance(frameWindow);
 260                 setupControl(eframe);
 261                 eframe.setSize(new Dimension(150, 150));
 262                 eframe.setVisible(true);
 263 //                System.err.println(eframe.getSize());
 264             } catch (Exception ex) {
 265                 ex.printStackTrace();
 266                 fail("Failed to instantiate EmbeddedFrame: " + ex.getMessage());
 267             }
 268         }
 269     }
 270     private static final Font hugeFont = new Font("Arial", Font.BOLD, 70);
 271 
 272     private java.util.List<Component> getAWTControls() {
 273         java.util.List<Component> components = new ArrayList<Component>();
 274 
 275         for (String clazz : simpleAwtControls) {
 276             addSimpleAwtControl(components, clazz);
 277         }
 278 
 279         TextField tf = new TextField();
 280         tf.setFont(hugeFont);
 281         addAwtControl(components, tf);
 282 
 283         // more complex controls
 284         Choice c = new Choice();
 285         for (int i = 0; i < petStrings.length; i++) {
 286             c.add(petStrings[i]);
 287         }
 288         addAwtControl(components, c);
 289         c.setPreferredSize(null);
 290         c.setFont(hugeFont); // to make control bigger as setPrefferedSize don't do his job here
 291 
 292         List l = new List(petStrings.length);
 293         for (int i = 0; i < petStrings.length; i++) {
 294             l.add(petStrings[i]);
 295         }
 296         addAwtControl(components, l);
 297 
 298         Canvas canvas = new Canvas();
 299         canvas.setSize(100, 200);
 300         addAwtControl(components, canvas);
 301 
 302         Scrollbar sb = new Scrollbar(Scrollbar.VERTICAL, 500, 1, 0, 500);
 303         addAwtControl(components, sb);
 304 
 305         Scrollbar sb2 = new Scrollbar(Scrollbar.HORIZONTAL, 500, 1, 0, 500);
 306         addAwtControl(components, sb2);
 307 
 308         return components;
 309     }
 310     /**
 311      * Default shift for {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point) }
 312      */
 313     protected static Point shift = new Point(16, 16);
 314 
 315     /**
 316      * Verifies point using specified AWT Robot. Supposes <code>defaultShift == true</code> for {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean) }.
 317      * This method is used to verify controls by providing just their plain screen coordinates.
 318      * @param robot AWT Robot. Usually created by {@link Util#createRobot() }
 319      * @param lLoc point to verify
 320      * @see OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean)
 321      */
 322     protected void clickAndBlink(Robot robot, Point lLoc) {
 323         clickAndBlink(robot, lLoc, true);
 324     }
 325     /**
 326      * Default failure message for color check
 327      * @see OverlappingTestBase#performTest()
 328      */
 329     protected String failMessageColorCheck = "The LW component did not pass pixel color check and is overlapped";
 330     /**
 331      * Default failure message event check
 332      * @see OverlappingTestBase#performTest()
 333      */
 334     protected String failMessage = "The LW component did not received the click.";
 335 
 336     private static boolean isValidForPixelCheck(Component component) {
 337         if ((component instanceof java.awt.Scrollbar) || isMac && (component instanceof java.awt.Button)) {
 338             return false;
 339         }
 340         return true;
 341     }
 342 
 343     /**
 344      * Preliminary validation - should be run <b>before</b> overlapping happens to ensure test is correct.
 345      * @param robot AWT Robot. Usually created by {@link Util#createRobot() }
 346      * @param lLoc point to validate to be <b>of</b> {@link OverlappingTestBase#AWT_BACKGROUND_COLOR}
 347      * @param component tested component, should be pointed out as not all components are valid for pixel check.
 348      */
 349     protected void pixelPreCheck(Robot robot, Point lLoc, Component component) {
 350         if (isValidForPixelCheck(component)) {
 351             int tries = 10;
 352             Color c = null;
 353             while (tries-- > 0) {
 354                 c = robot.getPixelColor(lLoc.x, lLoc.y);
 355                 System.out.println("Precheck. color: "+c+" compare with "+AWT_VERIFY_COLOR);
 356                 if (c.equals(AWT_VERIFY_COLOR)) {
 357                     return;
 358                 }
 359                 try {
 360                     Thread.sleep(100);
 361                 } catch (InterruptedException e) {
 362                 }
 363             }
 364             System.err.println(lLoc + ": " + c);
 365             fail("Dropdown test setup failure, colored part of AWT component is not located at click area");
 366         }
 367     }
 368 
 369     /**
 370      * Verifies point using specified AWT Robot.
 371      * <p>Firstly, verifies point by color pixel check
 372      * <p>Secondly, verifies event delivery by mouse click
 373      * @param robot AWT Robot. Usually created by {@link Util#createRobot() }
 374      * @param lLoc point to verify
 375      * @param defaultShift if true verified position will be shifted by {@link OverlappingTestBase#shift }.
 376      */
 377     protected void clickAndBlink(Robot robot, Point lLoc, boolean defaultShift) {
 378         Point loc = lLoc.getLocation();
 379         //check color
 380         Util.waitForIdle(robot);
 381         try{
 382             Thread.sleep(500);
 383         }catch(Exception exx){
 384             exx.printStackTrace();
 385         }
 386 
 387         if (defaultShift) {
 388             loc.translate(shift.x, shift.y);
 389         }
 390         if (!(System.getProperty("os.name").toLowerCase().contains("os x"))) {
 391             Color c = robot.getPixelColor(loc.x, loc.y);
 392             System.out.println("C&B. color: "+c+" compare with "+AWT_VERIFY_COLOR);
 393             if (c.equals(AWT_VERIFY_COLOR)) {
 394                 fail(failMessageColorCheck);
 395                 passed = false;
 396             }
 397 
 398             // perform click
 399             Util.waitForIdle(robot);
 400         }
 401 
 402         robot.mouseMove(loc.x, loc.y);
 403 
 404         robot.mousePress(InputEvent.BUTTON1_MASK);
 405         robot.mouseRelease(InputEvent.BUTTON1_MASK);
 406         Util.waitForIdle(robot);
 407     }
 408 
 409     /**
 410      * This method should be overriden with code which setups UI for testing.
 411      * Code in this method <b>will</b> be called only from AWT thread so Swing operations can be called directly.
 412      *
 413      * @see {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) } for instructions about adding tested AWT control to UI
 414      */
 415     protected abstract void prepareControls();
 416 
 417     /**
 418      * This method should be overriden with test execution. It will <b>not</b> be called from AWT thread so all Swing operations should be treated accordingly.
 419      * @return true if test passed. Otherwise fail with default fail message.
 420      * @see {@link OverlappingTestBase#failMessage} default fail message
 421      */
 422     protected abstract boolean performTest();
 423     /**
 424      * This method can be overriden with cleanup routines. It will be called from AWT thread so all Swing operations should be treated accordingly.
 425      */
 426     protected void cleanup() {
 427         // intentionally do nothing
 428     }
 429     /**
 430      * Currect tested AWT Control. Usually shouldn't be accessed directly.
 431      *
 432      * @see {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) } for instructions about adding tested AWT control to UI
 433      */
 434     protected Component currentAwtControl;
 435 
 436     private void testComponent(Component component) throws InterruptedException, InvocationTargetException {
 437         currentAwtControl = component;
 438         System.out.println("Testing " + currentAwtControl.getClass().getSimpleName());
 439         SwingUtilities.invokeAndWait(new Runnable() {
 440             public void run() {
 441                 prepareControls();
 442             }
 443         });
 444         if (component != null) {
 445             Util.waitTillShown(component);
 446         }
 447         Util.waitForIdle(null);
 448         try {
 449             Thread.sleep(500); // wait for graphic effects on systems like Win7
 450         } catch (InterruptedException ex) {
 451         }
 452         if (!instance.performTest()) {
 453             fail(failMessage);
 454             passed = false;
 455         }
 456         SwingUtilities.invokeAndWait(new Runnable() {
 457             public void run() {
 458                 cleanup();
 459             }
 460         });
 461     }
 462 
 463     private void testEmbeddedFrame() throws InvocationTargetException, InterruptedException {
 464         System.out.println("Testing EmbeddedFrame");
 465         currentAwtControl = null;
 466         SwingUtilities.invokeAndWait(new Runnable() {
 467             public void run() {
 468                 prepareControls();
 469             }
 470         });
 471         Util.waitForIdle(null);
 472         try {
 473             Thread.sleep(500); // wait for graphic effects on systems like Win7
 474         } catch (InterruptedException ex) {
 475         }
 476         if (!instance.performTest()) {
 477             fail(failMessage);
 478             passed = false;
 479         }
 480         SwingUtilities.invokeAndWait(new Runnable() {
 481             public void run() {
 482                 cleanup();
 483             }
 484         });
 485     }
 486 
 487     private void testAwtControls() throws InterruptedException {
 488         try {
 489             for (Component component : getAWTControls()) {
 490                 testComponent(component);
 491             }
 492             if (testEmbeddedFrame && !skipTestingEmbeddedFrame) {
 493                 testEmbeddedFrame();
 494             }
 495         } catch (InvocationTargetException ex) {
 496             ex.printStackTrace();
 497             fail(ex.getMessage());
 498         }
 499     }
 500     /**
 501      * Used by standard test machinery. See usage at {@link OverlappingTestBase }
 502      */
 503     protected static OverlappingTestBase instance;
 504 
 505     protected OverlappingTestBase() {
 506         getVerifyColor();
 507     }
 508 
 509     /*****************************************************
 510      * Standard Test Machinery Section
 511      * DO NOT modify anything in this section -- it's a
 512      * standard chunk of code which has all of the
 513      * synchronisation necessary for the test harness.
 514      * By keeping it the same in all tests, it is easier
 515      * to read and understand someone else's test, as
 516      * well as insuring that all tests behave correctly
 517      * with the test harness.
 518      * There is a section following this for test-
 519      * classes
 520      ******************************************************/
 521     private static void init() throws InterruptedException {
 522         //*** Create instructions for the user here ***
 523         //System.setProperty("sun.awt.disableMixing", "true");
 524 
 525         String[] instructions = {
 526             "This is an AUTOMATIC test, simply wait until it is done.",
 527             "The result (passed or failed) will be shown in the",
 528             "message window below."
 529         };
 530         Sysout.createDialog();
 531         Sysout.printInstructions(instructions);
 532 
 533         instance.testAwtControls();
 534 
 535         if (wasHWClicked) {
 536             fail("HW component received the click.");
 537             passed = false;
 538         }
 539         if (passed) {
 540             pass();
 541         }
 542     }//End  init()
 543     private static boolean theTestPassed = false;
 544     private static boolean testGeneratedInterrupt = false;
 545     private static String failureMessage = "";
 546     private static Thread mainThread = null;
 547     private static int sleepTime = 300000;
 548 
 549     // Not sure about what happens if multiple of this test are
 550     //  instantiated in the same VM.  Being static (and using
 551     //  static vars), it aint gonna work.  Not worrying about
 552     //  it for now.
 553     /**
 554      * Starting point for test runs. See usage at {@link OverlappingTestBase }
 555      * @param args regular main args, not used.
 556      * @throws InterruptedException
 557      */
 558     public static void doMain(String args[]) throws InterruptedException {
 559         mainThread = Thread.currentThread();
 560         try {
 561             init();
 562         } catch (TestPassedException e) {
 563             //The test passed, so just return from main and harness will
 564             // interepret this return as a pass
 565             return;
 566         }
 567         //At this point, neither test pass nor test fail has been
 568         // called -- either would have thrown an exception and ended the
 569         // test, so we know we have multiple threads.
 570 
 571         //Test involves other threads, so sleep and wait for them to
 572         // called pass() or fail()
 573         try {
 574             Thread.sleep(sleepTime);
 575             //Timed out, so fail the test
 576             throw new RuntimeException("Timed out after " + sleepTime / 1000 + " seconds");
 577         } catch (InterruptedException e) {
 578             //The test harness may have interrupted the test.  If so, rethrow the exception
 579             // so that the harness gets it and deals with it.
 580             if (!testGeneratedInterrupt) {
 581                 throw e;
 582             }
 583 
 584             //reset flag in case hit this code more than once for some reason (just safety)
 585             testGeneratedInterrupt = false;
 586 
 587             if (theTestPassed == false) {
 588                 throw new RuntimeException(failureMessage);
 589             }
 590         }
 591 
 592     }//main
 593 
 594     /**
 595      * Test will fail if not passed after this timeout. Default timeout is 300 seconds.
 596      * @param seconds timeout in seconds
 597      */
 598     public static synchronized void setTimeoutTo(int seconds) {
 599         sleepTime = seconds * 1000;
 600     }
 601 
 602     /**
 603      * Set test as passed. Usually shoudn't be called directly.
 604      */
 605     public static synchronized void pass() {
 606         Sysout.println("The test passed.");
 607         Sysout.println("The test is over, hit  Ctl-C to stop Java VM");
 608         //first check if this is executing in main thread
 609         if (mainThread == Thread.currentThread()) {
 610             //Still in the main thread, so set the flag just for kicks,
 611             // and throw a test passed exception which will be caught
 612             // and end the test.
 613             theTestPassed = true;
 614             throw new TestPassedException();
 615         }
 616         theTestPassed = true;
 617         testGeneratedInterrupt = true;
 618         mainThread.interrupt();
 619     }//pass()
 620 
 621     /**
 622      * Fail test generic message.
 623      */
 624     public static synchronized void fail() {
 625         //test writer didn't specify why test failed, so give generic
 626         fail("it just plain failed! :-)");
 627     }
 628 
 629     /**
 630      * Fail test providing specific reason.
 631      * @param whyFailed reason
 632      */
 633     public static synchronized void fail(String whyFailed) {
 634         Sysout.println("The test failed: " + whyFailed);
 635         Sysout.println("The test is over, hit  Ctl-C to stop Java VM");
 636         //check if this called from main thread
 637         if (mainThread == Thread.currentThread()) {
 638             //If main thread, fail now 'cause not sleeping
 639             throw new RuntimeException(whyFailed);
 640         }
 641         theTestPassed = false;
 642         testGeneratedInterrupt = true;
 643         failureMessage = whyFailed;
 644         mainThread.interrupt();
 645     }//fail()
 646 }// class LWComboBox
 647 class TestPassedException extends RuntimeException {
 648 }
 649 
 650 //*********** End Standard Test Machinery Section **********
 651 //************ Begin classes defined for the test ****************
 652 // if want to make listeners, here is the recommended place for them, then instantiate
 653 //  them in init()
 654 
 655 /* Example of a class which may be written as part of a test
 656 class NewClass implements anInterface
 657 {
 658 static int newVar = 0;
 659 
 660 public void eventDispatched(AWTEvent e)
 661 {
 662 //Counting events to see if we get enough
 663 eventCount++;
 664 
 665 if( eventCount == 20 )
 666 {
 667 //got enough events, so pass
 668 
 669 LWComboBox.pass();
 670 }
 671 else if( tries == 20 )
 672 {
 673 //tried too many times without getting enough events so fail
 674 
 675 LWComboBox.fail();
 676 }
 677 
 678 }// eventDispatched()
 679 
 680 }// NewClass class
 681 
 682  */
 683 //************** End classes defined for the test *******************
 684 /****************************************************
 685 Standard Test Machinery
 686 DO NOT modify anything below -- it's a standard
 687 chunk of code whose purpose is to make user
 688 interaction uniform, and thereby make it simpler
 689 to read and understand someone else's test.
 690  ****************************************************/
 691 /**
 692 This is part of the standard test machinery.
 693 It creates a dialog (with the instructions), and is the interface
 694 for sending text messages to the user.
 695 To print the instructions, send an array of strings to Sysout.createDialog
 696 WithInstructions method.  Put one line of instructions per array entry.
 697 To display a message for the tester to see, simply call Sysout.println
 698 with the string to be displayed.
 699 This mimics System.out.println but works within the test harness as well
 700 as standalone.
 701  */
 702 class Sysout {
 703     private static TestDialog dialog;
 704 
 705     public static void createDialogWithInstructions(String[] instructions) {
 706         dialog = new TestDialog(new Frame(), "Instructions");
 707         dialog.printInstructions(instructions);
 708         //dialog.setVisible(true);
 709         println("Any messages for the tester will display here.");
 710     }
 711 
 712     public static void createDialog() {
 713         dialog = new TestDialog(new Frame(), "Instructions");
 714         String[] defInstr = {"Instructions will appear here. ", ""};
 715         dialog.printInstructions(defInstr);
 716         //dialog.setVisible(true);
 717         println("Any messages for the tester will display here.");
 718     }
 719 
 720     public static void printInstructions(String[] instructions) {
 721         dialog.printInstructions(instructions);
 722     }
 723 
 724     public static void println(String messageIn) {
 725         dialog.displayMessage(messageIn);
 726         System.out.println(messageIn);
 727     }
 728 }// Sysout  class
 729 
 730 /**
 731 This is part of the standard test machinery.  It provides a place for the
 732 test instructions to be displayed, and a place for interactive messages
 733 to the user to be displayed.
 734 To have the test instructions displayed, see Sysout.
 735 To have a message to the user be displayed, see Sysout.
 736 Do not call anything in this dialog directly.
 737  */
 738 class TestDialog extends Dialog {
 739     TextArea instructionsText;
 740     TextArea messageText;
 741     int maxStringLength = 80;
 742 
 743     //DO NOT call this directly, go through Sysout
 744     public TestDialog(Frame frame, String name) {
 745         super(frame, name);
 746         int scrollBoth = TextArea.SCROLLBARS_BOTH;
 747         instructionsText = new TextArea("", 15, maxStringLength, scrollBoth);
 748         add("North", instructionsText);
 749 
 750         messageText = new TextArea("", 5, maxStringLength, scrollBoth);
 751         add("Center", messageText);
 752 
 753         pack();
 754 
 755        //setVisible(true);
 756     }// TestDialog()
 757 
 758     //DO NOT call this directly, go through Sysout
 759     public void printInstructions(String[] instructions) {
 760         //Clear out any current instructions
 761         instructionsText.setText("");
 762 
 763         //Go down array of instruction strings
 764 
 765         String printStr, remainingStr;
 766         for (int i = 0; i < instructions.length; i++) {
 767             //chop up each into pieces maxSringLength long
 768             remainingStr = instructions[i];
 769             while (remainingStr.length() > 0) {
 770                 //if longer than max then chop off first max chars to print
 771                 if (remainingStr.length() >= maxStringLength) {
 772                     //Try to chop on a word boundary
 773                     int posOfSpace = remainingStr.lastIndexOf(' ', maxStringLength - 1);
 774 
 775                     if (posOfSpace <= 0) {
 776                         posOfSpace = maxStringLength - 1;
 777                     }
 778 
 779                     printStr = remainingStr.substring(0, posOfSpace + 1);
 780                     remainingStr = remainingStr.substring(posOfSpace + 1);
 781                 } //else just print
 782                 else {
 783                     printStr = remainingStr;
 784                     remainingStr = "";
 785                 }
 786 
 787                 instructionsText.append(printStr + "\n");
 788 
 789             }// while
 790 
 791         }// for
 792 
 793     }//printInstructions()
 794 
 795     //DO NOT call this directly, go through Sysout
 796     public void displayMessage(String messageIn) {
 797         messageText.append(messageIn + "\n");
 798         System.out.println(messageIn);
 799     }
 800 }// TestDialog  class
 801