jdk/test/java/awt/Mixing/AWT_Mixing/OverlappingTestBase.java
changeset 24539 f0250a79028b
child 25129 3961e8fcb668
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Mixing/AWT_Mixing/OverlappingTestBase.java	Tue Apr 29 14:32:38 2014 +0400
@@ -0,0 +1,800 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.peer.ComponentPeer;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import javax.swing.*;
+import sun.awt.*;
+import java.io.*;
+
+/**
+ * <p>This class provides basis for AWT Mixing testing.
+ * <p>It provides all standard test machinery and should be used by
+ * extending and overriding next methods:
+ * <li> {@link OverlappingTestBase#prepareControls()} - setup UI components
+ * <li> {@link OverlappingTestBase#performTest()} -  run particular test
+ * Those methods would be run in the loop for each AWT component.
+ * <p>Current AWT component should be added to the tested UI by {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) ()}.
+ * There AWT components are prepared to be tested as being overlayed by other (e.g. Swing) components - they are colored to
+ * {@link OverlappingTestBase#AWT_BACKGROUND_COLOR} and throws failure on catching mouse event.
+ * <p> Validation of component being overlayed should be tested by {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point) }
+ * See each method javadoc for more details.
+ *
+ * <p>Due to test machinery limitations all test should be run from their own main() by calling next coe
+ * <code>
+ *     public static void main(String args[]) throws InterruptedException {
+ *        instance = new YourTestInstance();
+ *        OverlappingTestBase.doMain(args);
+ *     }
+ * </code>
+ *
+ * @author Sergey Grinev
+ */
+public abstract class OverlappingTestBase {
+    // working variables
+    private static volatile boolean wasHWClicked = false;
+    private static volatile boolean passed = true;
+    // constants
+    /**
+     * Default color for AWT component used for validate correct drawing of overlapping. <b>Never</b> use it for lightweight components.
+     */
+    protected static final Color AWT_BACKGROUND_COLOR = new Color(21, 244, 54);
+    protected static Color AWT_VERIFY_COLOR = AWT_BACKGROUND_COLOR;
+    protected static final int ROBOT_DELAY = 500;
+    private static final String[] simpleAwtControls = {"Button", "Checkbox", "Label", "TextArea"};
+    /**
+     * Generic strings array. To be used for population of List based controls.
+     */
+    protected static final String[] petStrings = {"Bird", "Cat", "Dog", "Rabbit", "Rhynocephalia Granda", "Bear", "Tiger", "Mustang"};
+    // "properties"
+    /**
+     * Tests customization. Set this variable to test only control from java.awt
+     * <p>Usage of this variable should be marked with CR being the reason.
+     * <p>Do not use this variable simultaneously with {@link OverlappingTestBase#skipClassNames}
+     */
+    protected String onlyClassName = null;
+    /**
+     * For customizing tests. List classes' simple names to skip them from testings.
+     * <p>Usage of this variable should be marked with CR being the reason.
+     */
+    protected String[] skipClassNames = null;
+    /**
+     * Set to false to avoid event delivery validation
+     * @see OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean)
+     */
+    protected boolean useClickValidation = true;
+    /**
+     * Set to false if test doesn't supposed to verify EmbeddedFrame
+     */
+    protected boolean testEmbeddedFrame = false;
+    /**
+     * Set this variable to true if testing embedded frame is impossible (on Mac, for instance, for now).
+     * The testEmbeddedFrame is explicitly set to true in dozen places.
+     */
+    protected boolean skipTestingEmbeddedFrame = false;
+
+    public static final boolean isMac = System.getProperty("os.name").toLowerCase().contains("os x");
+    private boolean isFrameBorderCalculated;
+    private int borderShift;
+
+    {    if (Toolkit.getDefaultToolkit().getClass().getName().matches(".*L.*Toolkit")) {
+             // No EmbeddedFrame in LWToolkit/LWCToolkit, yet
+             // And it should be programmed some other way, too, in any case
+             System.err.println("skipTestingEmbeddedFrame");
+             skipTestingEmbeddedFrame = true;
+         }else {
+             System.err.println("do not skipTestingEmbeddedFrame");
+         }
+    }
+
+    protected int frameBorderCounter() {
+        if (!isFrameBorderCalculated) {
+            try {
+                new FrameBorderCounter(); // force compilation by jtreg
+                String JAVA_HOME = System.getProperty("java.home");
+                Process p = Runtime.getRuntime().exec(JAVA_HOME + "/bin/java FrameBorderCounter");
+                try {
+                    p.waitFor();
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                    throw new RuntimeException(e);
+                }
+                if (p.exitValue() != 0) {
+                    throw new RuntimeException("FrameBorderCounter exited with not null code!\n" + readInputStream(p.getErrorStream()));
+                }
+                borderShift = Integer.parseInt(readInputStream(p.getInputStream()).trim());
+                isFrameBorderCalculated = true;
+            } catch (IOException e) {
+                e.printStackTrace();
+                System.exit(1);
+            }
+        }
+        return borderShift;
+    }
+
+    public void getVerifyColor() {
+        try {
+            final int size = 200;
+            final SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
+            final Point[] p = new Point[1];
+            SwingUtilities.invokeAndWait(new Runnable() {
+                public void run(){
+                    JFrame frame = new JFrame("set back");
+                    frame.getContentPane().setBackground(AWT_BACKGROUND_COLOR);
+                    frame.setSize(size, size);
+                    frame.setUndecorated(true);
+                    frame.setVisible(true);
+                    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+                    p[0] = frame.getLocation();
+                }
+            });
+            Robot robot = new Robot();
+            toolkit.realSync();
+            Thread.sleep(ROBOT_DELAY);
+            AWT_VERIFY_COLOR = robot.getPixelColor(p[0].x+size/2, p[0].y+size/2);
+            System.out.println("Color will be compared with " + AWT_VERIFY_COLOR + " instead of " + AWT_BACKGROUND_COLOR);
+        } catch (Exception e) {
+            System.err.println("Cannot get verify color: "+e.getMessage());
+        }
+    }
+
+    private String readInputStream(InputStream is) throws IOException {
+        byte[] buffer = new byte[4096];
+        int len = 0;
+        StringBuilder sb = new StringBuilder();
+        try (InputStreamReader isr = new InputStreamReader(is)) {
+            while ((len = is.read(buffer)) > 0) {
+                sb.append(new String(buffer, 0, len));
+            }
+        }
+        return sb.toString();
+    }
+
+    private void setupControl(final Component control) {
+        if (useClickValidation) {
+            control.addMouseListener(new MouseAdapter() {
+                @Override
+                public void mouseClicked(MouseEvent e) {
+                    System.err.println("ERROR: " + control.getClass() + " received mouse click.");
+                    wasHWClicked = true;
+                }
+            });
+        }
+        control.setBackground(AWT_BACKGROUND_COLOR);
+        control.setForeground(AWT_BACKGROUND_COLOR);
+        control.setPreferredSize(new Dimension(150, 150));
+        control.setFocusable(false);
+    }
+
+    private void addAwtControl(java.util.List<Component> container, final Component control) {
+        String simpleName = control.getClass().getSimpleName();
+        if (onlyClassName != null && !simpleName.equals(onlyClassName)) {
+            return;
+        }
+        if (skipClassNames != null) {
+            for (String skipMe : skipClassNames) {
+                if (simpleName.equals(skipMe)) {
+                    return;
+                }
+            }
+        }
+        setupControl(control);
+        container.add(control);
+    }
+
+    private void addSimpleAwtControl(java.util.List<Component> container, String className) {
+        try {
+            Class definition = Class.forName("java.awt." + className);
+            Constructor constructor = definition.getConstructor(new Class[]{String.class});
+            java.awt.Component component = (java.awt.Component) constructor.newInstance(new Object[]{"AWT Component " + className});
+            addAwtControl(container, component);
+        } catch (Exception ex) {
+            System.err.println(ex.getMessage());
+            fail("Setup error, this jdk doesn't have awt conrol " + className);
+        }
+    }
+
+    /**
+     * Adds current AWT control to container
+     * <p>N.B.: if testEmbeddedFrame == true this method will also add EmbeddedFrame over Canvas
+     * and it should be called <b>after</b> Frame.setVisible(true) call
+     * @param container container to hold AWT component
+     */
+    protected final void propagateAWTControls(Container container) {
+        if (currentAwtControl != null) {
+            container.add(currentAwtControl);
+        } else { // embedded frame
+            try {
+
+                //create embedder
+                Canvas embedder = new Canvas();
+                embedder.setBackground(Color.RED);
+                embedder.setPreferredSize(new Dimension(150, 150));
+                container.add(embedder);
+                container.setVisible(true); // create peer
+
+                long frameWindow = 0;
+                String getWindowMethodName = "getHWnd";
+                if (Toolkit.getDefaultToolkit().getClass().getName().contains("XToolkit")) {
+                    getWindowMethodName = "getWindow";
+                }
+                ComponentPeer peer = embedder.getPeer();
+//                System.err.println("Peer: " + peer);
+                Method getWindowMethod = peer.getClass().getMethod(getWindowMethodName);
+                frameWindow = (Long) getWindowMethod.invoke(peer);
+//                System.err.println("frame peer ID: " + frameWindow);
+
+                String eframeClassName = "sun.awt.windows.WEmbeddedFrame";
+                if (Toolkit.getDefaultToolkit().getClass().getName().contains("XToolkit")) {
+                    eframeClassName = "sun.awt.X11.XEmbeddedFrame";
+                }
+                Class eframeClass = Class.forName(eframeClassName);
+                Constructor eframeCtor = eframeClass.getConstructor(long.class);
+                EmbeddedFrame eframe = (EmbeddedFrame) eframeCtor.newInstance(frameWindow);
+                setupControl(eframe);
+                eframe.setSize(new Dimension(150, 150));
+                eframe.setVisible(true);
+//                System.err.println(eframe.getSize());
+            } catch (Exception ex) {
+                ex.printStackTrace();
+                fail("Failed to instantiate EmbeddedFrame: " + ex.getMessage());
+            }
+        }
+    }
+    private static final Font hugeFont = new Font("Arial", Font.BOLD, 70);
+
+    private java.util.List<Component> getAWTControls() {
+        java.util.List<Component> components = new ArrayList<Component>();
+
+        for (String clazz : simpleAwtControls) {
+            addSimpleAwtControl(components, clazz);
+        }
+
+        TextField tf = new TextField();
+        tf.setFont(hugeFont);
+        addAwtControl(components, tf);
+
+        // more complex controls
+        Choice c = new Choice();
+        for (int i = 0; i < petStrings.length; i++) {
+            c.add(petStrings[i]);
+        }
+        addAwtControl(components, c);
+        c.setPreferredSize(null);
+        c.setFont(hugeFont); // to make control bigger as setPrefferedSize don't do his job here
+
+        List l = new List(petStrings.length);
+        for (int i = 0; i < petStrings.length; i++) {
+            l.add(petStrings[i]);
+        }
+        addAwtControl(components, l);
+
+        Canvas canvas = new Canvas();
+        canvas.setSize(100, 200);
+        addAwtControl(components, canvas);
+
+        Scrollbar sb = new Scrollbar(Scrollbar.VERTICAL, 500, 1, 0, 500);
+        addAwtControl(components, sb);
+
+        Scrollbar sb2 = new Scrollbar(Scrollbar.HORIZONTAL, 500, 1, 0, 500);
+        addAwtControl(components, sb2);
+
+        return components;
+    }
+    /**
+     * Default shift for {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point) }
+     */
+    protected static Point shift = new Point(16, 16);
+
+    /**
+     * Verifies point using specified AWT Robot. Supposes <code>defaultShift == true</code> for {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean) }.
+     * This method is used to verify controls by providing just their plain screen coordinates.
+     * @param robot AWT Robot. Usually created by {@link Util#createRobot() }
+     * @param lLoc point to verify
+     * @see OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean)
+     */
+    protected void clickAndBlink(Robot robot, Point lLoc) {
+        clickAndBlink(robot, lLoc, true);
+    }
+    /**
+     * Default failure message for color check
+     * @see OverlappingTestBase#performTest()
+     */
+    protected String failMessageColorCheck = "The LW component did not pass pixel color check and is overlapped";
+    /**
+     * Default failure message event check
+     * @see OverlappingTestBase#performTest()
+     */
+    protected String failMessage = "The LW component did not received the click.";
+
+    private static boolean isValidForPixelCheck(Component component) {
+        if ((component instanceof java.awt.Scrollbar) || isMac && (component instanceof java.awt.Button)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Preliminary validation - should be run <b>before</b> overlapping happens to ensure test is correct.
+     * @param robot AWT Robot. Usually created by {@link Util#createRobot() }
+     * @param lLoc point to validate to be <b>of</b> {@link OverlappingTestBase#AWT_BACKGROUND_COLOR}
+     * @param component tested component, should be pointed out as not all components are valid for pixel check.
+     */
+    protected void pixelPreCheck(Robot robot, Point lLoc, Component component) {
+        if (isValidForPixelCheck(component)) {
+            int tries = 10;
+            Color c = null;
+            while (tries-- > 0) {
+                c = robot.getPixelColor(lLoc.x, lLoc.y);
+                System.out.println("Precheck. color: "+c+" compare with "+AWT_VERIFY_COLOR);
+                if (c.equals(AWT_VERIFY_COLOR)) {
+                    return;
+                }
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                }
+            }
+            System.err.println(lLoc + ": " + c);
+            fail("Dropdown test setup failure, colored part of AWT component is not located at click area");
+        }
+    }
+
+    /**
+     * Verifies point using specified AWT Robot.
+     * <p>Firstly, verifies point by color pixel check
+     * <p>Secondly, verifies event delivery by mouse click
+     * @param robot AWT Robot. Usually created by {@link Util#createRobot() }
+     * @param lLoc point to verify
+     * @param defaultShift if true verified position will be shifted by {@link OverlappingTestBase#shift }.
+     */
+    protected void clickAndBlink(Robot robot, Point lLoc, boolean defaultShift) {
+        Point loc = lLoc.getLocation();
+        //check color
+        Util.waitForIdle(robot);
+        try{
+            Thread.sleep(500);
+        }catch(Exception exx){
+            exx.printStackTrace();
+        }
+
+        if (defaultShift) {
+            loc.translate(shift.x, shift.y);
+        }
+        if (!(System.getProperty("os.name").toLowerCase().contains("os x"))) {
+            Color c = robot.getPixelColor(loc.x, loc.y);
+            System.out.println("C&B. color: "+c+" compare with "+AWT_VERIFY_COLOR);
+            if (c.equals(AWT_VERIFY_COLOR)) {
+                fail(failMessageColorCheck);
+                passed = false;
+            }
+
+            // perform click
+            Util.waitForIdle(robot);
+        }
+
+        robot.mouseMove(loc.x, loc.y);
+
+        robot.mousePress(InputEvent.BUTTON1_MASK);
+        robot.mouseRelease(InputEvent.BUTTON1_MASK);
+        Util.waitForIdle(robot);
+    }
+
+    /**
+     * This method should be overriden with code which setups UI for testing.
+     * Code in this method <b>will</b> be called only from AWT thread so Swing operations can be called directly.
+     *
+     * @see {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) } for instructions about adding tested AWT control to UI
+     */
+    protected abstract void prepareControls();
+
+    /**
+     * 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.
+     * @return true if test passed. Otherwise fail with default fail message.
+     * @see {@link OverlappingTestBase#failMessage} default fail message
+     */
+    protected abstract boolean performTest();
+    /**
+     * This method can be overriden with cleanup routines. It will be called from AWT thread so all Swing operations should be treated accordingly.
+     */
+    protected void cleanup() {
+        // intentionally do nothing
+    }
+    /**
+     * Currect tested AWT Control. Usually shouldn't be accessed directly.
+     *
+     * @see {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) } for instructions about adding tested AWT control to UI
+     */
+    protected Component currentAwtControl;
+
+    private void testComponent(Component component) throws InterruptedException, InvocationTargetException {
+        currentAwtControl = component;
+        System.out.println("Testing " + currentAwtControl.getClass().getSimpleName());
+        SwingUtilities.invokeAndWait(new Runnable() {
+            public void run() {
+                prepareControls();
+            }
+        });
+        if (component != null) {
+            Util.waitTillShown(component);
+        }
+        Util.waitForIdle(null);
+        try {
+            Thread.sleep(500); // wait for graphic effects on systems like Win7
+        } catch (InterruptedException ex) {
+        }
+        if (!instance.performTest()) {
+            fail(failMessage);
+            passed = false;
+        }
+        SwingUtilities.invokeAndWait(new Runnable() {
+            public void run() {
+                cleanup();
+            }
+        });
+    }
+
+    private void testEmbeddedFrame() throws InvocationTargetException, InterruptedException {
+        System.out.println("Testing EmbeddedFrame");
+        currentAwtControl = null;
+        SwingUtilities.invokeAndWait(new Runnable() {
+            public void run() {
+                prepareControls();
+            }
+        });
+        Util.waitForIdle(null);
+        try {
+            Thread.sleep(500); // wait for graphic effects on systems like Win7
+        } catch (InterruptedException ex) {
+        }
+        if (!instance.performTest()) {
+            fail(failMessage);
+            passed = false;
+        }
+        SwingUtilities.invokeAndWait(new Runnable() {
+            public void run() {
+                cleanup();
+            }
+        });
+    }
+
+    private void testAwtControls() throws InterruptedException {
+        try {
+            for (Component component : getAWTControls()) {
+                testComponent(component);
+            }
+            if (testEmbeddedFrame && !skipTestingEmbeddedFrame) {
+                testEmbeddedFrame();
+            }
+        } catch (InvocationTargetException ex) {
+            ex.printStackTrace();
+            fail(ex.getMessage());
+        }
+    }
+    /**
+     * Used by standard test machinery. See usage at {@link OverlappingTestBase }
+     */
+    protected static OverlappingTestBase instance;
+
+    protected OverlappingTestBase() {
+        getVerifyColor();
+    }
+
+    /*****************************************************
+     * Standard Test Machinery Section
+     * DO NOT modify anything in this section -- it's a
+     * standard chunk of code which has all of the
+     * synchronisation necessary for the test harness.
+     * By keeping it the same in all tests, it is easier
+     * to read and understand someone else's test, as
+     * well as insuring that all tests behave correctly
+     * with the test harness.
+     * There is a section following this for test-
+     * classes
+     ******************************************************/
+    private static void init() throws InterruptedException {
+        //*** Create instructions for the user here ***
+        //System.setProperty("sun.awt.disableMixing", "true");
+
+        String[] instructions = {
+            "This is an AUTOMATIC test, simply wait until it is done.",
+            "The result (passed or failed) will be shown in the",
+            "message window below."
+        };
+        Sysout.createDialog();
+        Sysout.printInstructions(instructions);
+
+        instance.testAwtControls();
+
+        if (wasHWClicked) {
+            fail("HW component received the click.");
+            passed = false;
+        }
+        if (passed) {
+            pass();
+        }
+    }//End  init()
+    private static boolean theTestPassed = false;
+    private static boolean testGeneratedInterrupt = false;
+    private static String failureMessage = "";
+    private static Thread mainThread = null;
+    private static int sleepTime = 300000;
+
+    // Not sure about what happens if multiple of this test are
+    //  instantiated in the same VM.  Being static (and using
+    //  static vars), it aint gonna work.  Not worrying about
+    //  it for now.
+    /**
+     * Starting point for test runs. See usage at {@link OverlappingTestBase }
+     * @param args regular main args, not used.
+     * @throws InterruptedException
+     */
+    public static void doMain(String args[]) throws InterruptedException {
+        mainThread = Thread.currentThread();
+        try {
+            init();
+        } catch (TestPassedException e) {
+            //The test passed, so just return from main and harness will
+            // interepret this return as a pass
+            return;
+        }
+        //At this point, neither test pass nor test fail has been
+        // called -- either would have thrown an exception and ended the
+        // test, so we know we have multiple threads.
+
+        //Test involves other threads, so sleep and wait for them to
+        // called pass() or fail()
+        try {
+            Thread.sleep(sleepTime);
+            //Timed out, so fail the test
+            throw new RuntimeException("Timed out after " + sleepTime / 1000 + " seconds");
+        } catch (InterruptedException e) {
+            //The test harness may have interrupted the test.  If so, rethrow the exception
+            // so that the harness gets it and deals with it.
+            if (!testGeneratedInterrupt) {
+                throw e;
+            }
+
+            //reset flag in case hit this code more than once for some reason (just safety)
+            testGeneratedInterrupt = false;
+
+            if (theTestPassed == false) {
+                throw new RuntimeException(failureMessage);
+            }
+        }
+
+    }//main
+
+    /**
+     * Test will fail if not passed after this timeout. Default timeout is 300 seconds.
+     * @param seconds timeout in seconds
+     */
+    public static synchronized void setTimeoutTo(int seconds) {
+        sleepTime = seconds * 1000;
+    }
+
+    /**
+     * Set test as passed. Usually shoudn't be called directly.
+     */
+    public static synchronized void pass() {
+        Sysout.println("The test passed.");
+        Sysout.println("The test is over, hit  Ctl-C to stop Java VM");
+        //first check if this is executing in main thread
+        if (mainThread == Thread.currentThread()) {
+            //Still in the main thread, so set the flag just for kicks,
+            // and throw a test passed exception which will be caught
+            // and end the test.
+            theTestPassed = true;
+            throw new TestPassedException();
+        }
+        theTestPassed = true;
+        testGeneratedInterrupt = true;
+        mainThread.interrupt();
+    }//pass()
+
+    /**
+     * Fail test generic message.
+     */
+    public static synchronized void fail() {
+        //test writer didn't specify why test failed, so give generic
+        fail("it just plain failed! :-)");
+    }
+
+    /**
+     * Fail test providing specific reason.
+     * @param whyFailed reason
+     */
+    public static synchronized void fail(String whyFailed) {
+        Sysout.println("The test failed: " + whyFailed);
+        Sysout.println("The test is over, hit  Ctl-C to stop Java VM");
+        //check if this called from main thread
+        if (mainThread == Thread.currentThread()) {
+            //If main thread, fail now 'cause not sleeping
+            throw new RuntimeException(whyFailed);
+        }
+        theTestPassed = false;
+        testGeneratedInterrupt = true;
+        failureMessage = whyFailed;
+        mainThread.interrupt();
+    }//fail()
+}// class LWComboBox
+class TestPassedException extends RuntimeException {
+}
+
+//*********** End Standard Test Machinery Section **********
+//************ Begin classes defined for the test ****************
+// if want to make listeners, here is the recommended place for them, then instantiate
+//  them in init()
+
+/* Example of a class which may be written as part of a test
+class NewClass implements anInterface
+{
+static int newVar = 0;
+
+public void eventDispatched(AWTEvent e)
+{
+//Counting events to see if we get enough
+eventCount++;
+
+if( eventCount == 20 )
+{
+//got enough events, so pass
+
+LWComboBox.pass();
+}
+else if( tries == 20 )
+{
+//tried too many times without getting enough events so fail
+
+LWComboBox.fail();
+}
+
+}// eventDispatched()
+
+}// NewClass class
+
+ */
+//************** End classes defined for the test *******************
+/****************************************************
+Standard Test Machinery
+DO NOT modify anything below -- it's a standard
+chunk of code whose purpose is to make user
+interaction uniform, and thereby make it simpler
+to read and understand someone else's test.
+ ****************************************************/
+/**
+This is part of the standard test machinery.
+It creates a dialog (with the instructions), and is the interface
+for sending text messages to the user.
+To print the instructions, send an array of strings to Sysout.createDialog
+WithInstructions method.  Put one line of instructions per array entry.
+To display a message for the tester to see, simply call Sysout.println
+with the string to be displayed.
+This mimics System.out.println but works within the test harness as well
+as standalone.
+ */
+class Sysout {
+    private static TestDialog dialog;
+
+    public static void createDialogWithInstructions(String[] instructions) {
+        dialog = new TestDialog(new Frame(), "Instructions");
+        dialog.printInstructions(instructions);
+        //dialog.setVisible(true);
+        println("Any messages for the tester will display here.");
+    }
+
+    public static void createDialog() {
+        dialog = new TestDialog(new Frame(), "Instructions");
+        String[] defInstr = {"Instructions will appear here. ", ""};
+        dialog.printInstructions(defInstr);
+        //dialog.setVisible(true);
+        println("Any messages for the tester will display here.");
+    }
+
+    public static void printInstructions(String[] instructions) {
+        dialog.printInstructions(instructions);
+    }
+
+    public static void println(String messageIn) {
+        dialog.displayMessage(messageIn);
+        System.out.println(messageIn);
+    }
+}// Sysout  class
+
+/**
+This is part of the standard test machinery.  It provides a place for the
+test instructions to be displayed, and a place for interactive messages
+to the user to be displayed.
+To have the test instructions displayed, see Sysout.
+To have a message to the user be displayed, see Sysout.
+Do not call anything in this dialog directly.
+ */
+class TestDialog extends Dialog {
+    TextArea instructionsText;
+    TextArea messageText;
+    int maxStringLength = 80;
+
+    //DO NOT call this directly, go through Sysout
+    public TestDialog(Frame frame, String name) {
+        super(frame, name);
+        int scrollBoth = TextArea.SCROLLBARS_BOTH;
+        instructionsText = new TextArea("", 15, maxStringLength, scrollBoth);
+        add("North", instructionsText);
+
+        messageText = new TextArea("", 5, maxStringLength, scrollBoth);
+        add("Center", messageText);
+
+        pack();
+
+       //setVisible(true);
+    }// TestDialog()
+
+    //DO NOT call this directly, go through Sysout
+    public void printInstructions(String[] instructions) {
+        //Clear out any current instructions
+        instructionsText.setText("");
+
+        //Go down array of instruction strings
+
+        String printStr, remainingStr;
+        for (int i = 0; i < instructions.length; i++) {
+            //chop up each into pieces maxSringLength long
+            remainingStr = instructions[i];
+            while (remainingStr.length() > 0) {
+                //if longer than max then chop off first max chars to print
+                if (remainingStr.length() >= maxStringLength) {
+                    //Try to chop on a word boundary
+                    int posOfSpace = remainingStr.lastIndexOf(' ', maxStringLength - 1);
+
+                    if (posOfSpace <= 0) {
+                        posOfSpace = maxStringLength - 1;
+                    }
+
+                    printStr = remainingStr.substring(0, posOfSpace + 1);
+                    remainingStr = remainingStr.substring(posOfSpace + 1);
+                } //else just print
+                else {
+                    printStr = remainingStr;
+                    remainingStr = "";
+                }
+
+                instructionsText.append(printStr + "\n");
+
+            }// while
+
+        }// for
+
+    }//printInstructions()
+
+    //DO NOT call this directly, go through Sysout
+    public void displayMessage(String messageIn) {
+        messageText.append(messageIn + "\n");
+        System.out.println(messageIn);
+    }
+}// TestDialog  class
+