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