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