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