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 
frameBorderCounter()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 
getVerifyColor()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 
readInputStream(InputStream is)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 
setupControl(final Component control)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 
addAwtControl(java.util.List<Component> container, final Component control)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 
addSimpleAwtControl(java.util.List<Component> container, String className)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      */
propagateAWTControls(Container container)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 
getAWTControls()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      */
clickAndBlink(Robot robot, Point lLoc)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 
isValidForPixelCheck(Component component)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      */
pixelPreCheck(Robot robot, Point lLoc, Component component)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      */
clickAndBlink(Robot robot, Point lLoc, boolean defaultShift)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      */
prepareControls()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      */
performTest()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      */
cleanup()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 
testComponent(Component component)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 
testEmbeddedFrame()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 
testAwtControls()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 
OverlappingTestBase()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      ******************************************************/
init()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      */
doMain(String args[])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      */
setTimeoutTo(int seconds)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      */
pass()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      */
fail()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      */
fail(String whyFailed)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 
createDialogWithInstructions(String[] instructions)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 
createDialog()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 
printInstructions(String[] instructions)729     public static void printInstructions(String[] instructions) {
730         dialog.printInstructions(instructions);
731     }
732 
println(String messageIn)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
TestDialog(Frame frame, String name)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
printInstructions(String[] instructions)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
displayMessage(String messageIn)805     public void displayMessage(String messageIn) {
806         messageText.append(messageIn + "\n");
807         System.out.println(messageIn);
808     }
809 }// TestDialog  class
810 
811