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