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