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.*; 33 import java.io.*; 34 35 /** 36 * <p>This class provides basis for AWT Mixing testing. 37 * <p>It provides all standard test machinery and should be used by 38 * extending and overriding next methods: 39 * <li> {@link OverlappingTestBase#prepareControls()} - setup UI components 40 * <li> {@link OverlappingTestBase#performTest()} - run particular test 41 * Those methods would be run in the loop for each AWT component. 42 * <p>Current AWT component should be added to the tested UI by {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) ()}. 43 * There AWT components are prepared to be tested as being overlayed by other (e.g. Swing) components - they are colored to 44 * {@link OverlappingTestBase#AWT_BACKGROUND_COLOR} and throws failure on catching mouse event. 45 * <p> Validation of component being overlayed should be tested by {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point) } 46 * See each method javadoc for more details. 47 * 48 * <p>Due to test machinery limitations all test should be run from their own main() by calling next coe 49 * <code> 50 * public static void main(String args[]) throws InterruptedException { 51 * instance = new YourTestInstance(); 52 * OverlappingTestBase.doMain(args); 53 * } 54 * </code> 55 * 56 * @author Sergey Grinev 57 */ 58 public abstract class OverlappingTestBase { 59 // working variables 60 private static volatile boolean wasHWClicked = false; 61 private static volatile boolean passed = true; 62 // constants 63 /** 64 * Default color for AWT component used for validate correct drawing of overlapping. <b>Never</b> use it for lightweight components. 65 */ 66 protected static final Color AWT_BACKGROUND_COLOR = new Color(21, 244, 54); 67 protected static Color AWT_VERIFY_COLOR = AWT_BACKGROUND_COLOR; 68 protected static final int ROBOT_DELAY = 500; 69 private static final String[] simpleAwtControls = {"Button", "Checkbox", "Label", "TextArea"}; 70 /** 71 * Generic strings array. To be used for population of List based controls. 72 */ 73 protected static final String[] petStrings = {"Bird", "Cat", "Dog", "Rabbit", "Rhynocephalia Granda", "Bear", "Tiger", "Mustang"}; 74 // "properties" 75 /** 76 * Tests customization. Set this variable to test only control from java.awt 77 * <p>Usage of this variable should be marked with CR being the reason. 78 * <p>Do not use this variable simultaneously with {@link OverlappingTestBase#skipClassNames} 79 */ 80 protected String onlyClassName = null; 81 /** 82 * For customizing tests. List classes' simple names to skip them from testings. 83 * <p>Usage of this variable should be marked with CR being the reason. 84 */ 85 protected String[] skipClassNames = null; 86 /** 87 * Set to false to avoid event delivery validation 88 * @see OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean) 89 */ 90 protected boolean useClickValidation = true; 91 /** 92 * Set to false if test doesn't supposed to verify EmbeddedFrame 93 */ 94 protected boolean testEmbeddedFrame = false; 95 /** 96 * Set this variable to true if testing embedded frame is impossible (on Mac, for instance, for now). 97 * The testEmbeddedFrame is explicitly set to true in dozen places. 98 */ 99 protected boolean skipTestingEmbeddedFrame = false; 100 101 public static final boolean isMac = System.getProperty("os.name").toLowerCase().contains("os x"); 102 private boolean isFrameBorderCalculated; 103 private int borderShift; 104 105 { if (Toolkit.getDefaultToolkit().getClass().getName().matches(".*L.*Toolkit")) { 106 // No EmbeddedFrame in LWToolkit/LWCToolkit, yet 107 // And it should be programmed some other way, too, in any case 108 System.err.println("skipTestingEmbeddedFrame"); 109 skipTestingEmbeddedFrame = true; 110 }else { 111 System.err.println("do not skipTestingEmbeddedFrame"); 112 } 113 } 114 115 protected int frameBorderCounter() { 116 if (!isFrameBorderCalculated) { 117 try { 118 new FrameBorderCounter(); // force compilation by jtreg 119 String JAVA_HOME = System.getProperty("java.home"); 120 Process p = Runtime.getRuntime().exec(JAVA_HOME + "/bin/java FrameBorderCounter"); 121 try { 122 p.waitFor(); 123 } catch (InterruptedException e) { 124 e.printStackTrace(); 125 throw new RuntimeException(e); 126 } 127 if (p.exitValue() != 0) { 128 throw new RuntimeException("FrameBorderCounter exited with not null code!\n" + readInputStream(p.getErrorStream())); 129 } 130 borderShift = Integer.parseInt(readInputStream(p.getInputStream()).trim()); 131 isFrameBorderCalculated = true; 132 } catch (IOException e) { 133 e.printStackTrace(); 134 System.exit(1); 135 } 136 } 137 return borderShift; 138 } 139 140 public void getVerifyColor() { 141 try { 142 final int size = 200; 143 final SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); 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 toolkit.realSync(); 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 currentAwtControl = component; 437 System.out.println("Testing " + currentAwtControl.getClass().getSimpleName()); 438 SwingUtilities.invokeAndWait(new Runnable() { 439 public void run() { 440 prepareControls(); 441 } 442 }); 443 if (component != null) { 444 Util.waitTillShown(component); 445 } 446 Util.waitForIdle(null); 447 try { 448 Thread.sleep(500); // wait for graphic effects on systems like Win7 449 } catch (InterruptedException ex) { 450 } 451 if (!instance.performTest()) { 452 fail(failMessage); 453 passed = false; 454 } 455 SwingUtilities.invokeAndWait(new Runnable() { 456 public void run() { 457 cleanup(); 458 } 459 }); 460 } 461 462 private void testEmbeddedFrame() throws InvocationTargetException, InterruptedException { 463 System.out.println("Testing EmbeddedFrame"); 464 currentAwtControl = null; 465 SwingUtilities.invokeAndWait(new Runnable() { 466 public void run() { 467 prepareControls(); 468 } 469 }); 470 Util.waitForIdle(null); 471 try { 472 Thread.sleep(500); // wait for graphic effects on systems like Win7 473 } catch (InterruptedException ex) { 474 } 475 if (!instance.performTest()) { 476 fail(failMessage); 477 passed = false; 478 } 479 SwingUtilities.invokeAndWait(new Runnable() { 480 public void run() { 481 cleanup(); 482 } 483 }); 484 } 485 486 private void testAwtControls() throws InterruptedException { 487 try { 488 for (Component component : getAWTControls()) { 489 testComponent(component); 490 } 491 if (testEmbeddedFrame && !skipTestingEmbeddedFrame) { 492 testEmbeddedFrame(); 493 } 494 } catch (InvocationTargetException ex) { 495 ex.printStackTrace(); 496 fail(ex.getMessage()); 497 } 498 } 499 /** 500 * Used by standard test machinery. See usage at {@link OverlappingTestBase } 501 */ 502 protected static OverlappingTestBase instance; 503 504 protected OverlappingTestBase() { 505 getVerifyColor(); 506 } 507 508 /***************************************************** 509 * Standard Test Machinery Section 510 * DO NOT modify anything in this section -- it's a 511 * standard chunk of code which has all of the 512 * synchronisation necessary for the test harness. 513 * By keeping it the same in all tests, it is easier 514 * to read and understand someone else's test, as 515 * well as insuring that all tests behave correctly 516 * with the test harness. 517 * There is a section following this for test- 518 * classes 519 ******************************************************/ 520 private static void init() throws InterruptedException { 521 //*** Create instructions for the user here *** 522 //System.setProperty("sun.awt.disableMixing", "true"); 523 524 String[] instructions = { 525 "This is an AUTOMATIC test, simply wait until it is done.", 526 "The result (passed or failed) will be shown in the", 527 "message window below." 528 }; 529 Sysout.createDialog(); 530 Sysout.printInstructions(instructions); 531 532 instance.testAwtControls(); 533 534 if (wasHWClicked) { 535 fail("HW component received the click."); 536 passed = false; 537 } 538 if (passed) { 539 pass(); 540 } 541 }//End init() 542 private static boolean theTestPassed = false; 543 private static boolean testGeneratedInterrupt = false; 544 private static String failureMessage = ""; 545 private static Thread mainThread = null; 546 private static int sleepTime = 300000; 547 548 // Not sure about what happens if multiple of this test are 549 // instantiated in the same VM. Being static (and using 550 // static vars), it aint gonna work. Not worrying about 551 // it for now. 552 /** 553 * Starting point for test runs. See usage at {@link OverlappingTestBase } 554 * @param args regular main args, not used. 555 * @throws InterruptedException 556 */ 557 public static void doMain(String args[]) throws InterruptedException { 558 mainThread = Thread.currentThread(); 559 try { 560 init(); 561 } catch (TestPassedException e) { 562 //The test passed, so just return from main and harness will 563 // interepret this return as a pass 564 return; 565 } 566 //At this point, neither test pass nor test fail has been 567 // called -- either would have thrown an exception and ended the 568 // test, so we know we have multiple threads. 569 570 //Test involves other threads, so sleep and wait for them to 571 // called pass() or fail() 572 try { 573 Thread.sleep(sleepTime); 574 //Timed out, so fail the test 575 throw new RuntimeException("Timed out after " + sleepTime / 1000 + " seconds"); 576 } catch (InterruptedException e) { 577 //The test harness may have interrupted the test. If so, rethrow the exception 578 // so that the harness gets it and deals with it. 579 if (!testGeneratedInterrupt) { 580 throw e; 581 } 582 583 //reset flag in case hit this code more than once for some reason (just safety) 584 testGeneratedInterrupt = false; 585 586 if (theTestPassed == false) { 587 throw new RuntimeException(failureMessage); 588 } 589 } 590 591 }//main 592 593 /** 594 * Test will fail if not passed after this timeout. Default timeout is 300 seconds. 595 * @param seconds timeout in seconds 596 */ 597 public static synchronized void setTimeoutTo(int seconds) { 598 sleepTime = seconds * 1000; 599 } 600 601 /** 602 * Set test as passed. Usually shoudn't be called directly. 603 */ 604 public static synchronized void pass() { 605 Sysout.println("The test passed."); 606 Sysout.println("The test is over, hit Ctl-C to stop Java VM"); 607 //first check if this is executing in main thread 608 if (mainThread == Thread.currentThread()) { 609 //Still in the main thread, so set the flag just for kicks, 610 // and throw a test passed exception which will be caught 611 // and end the test. 612 theTestPassed = true; 613 throw new TestPassedException(); 614 } 615 theTestPassed = true; 616 testGeneratedInterrupt = true; 617 mainThread.interrupt(); 618 }//pass() 619 620 /** 621 * Fail test generic message. 622 */ 623 public static synchronized void fail() { 624 //test writer didn't specify why test failed, so give generic 625 fail("it just plain failed! :-)"); 626 } 627 628 /** 629 * Fail test providing specific reason. 630 * @param whyFailed reason 631 */ 632 public static synchronized void fail(String whyFailed) { 633 Sysout.println("The test failed: " + whyFailed); 634 Sysout.println("The test is over, hit Ctl-C to stop Java VM"); 635 //check if this called from main thread 636 if (mainThread == Thread.currentThread()) { 637 //If main thread, fail now 'cause not sleeping 638 throw new RuntimeException(whyFailed); 639 } 640 theTestPassed = false; 641 testGeneratedInterrupt = true; 642 failureMessage = whyFailed; 643 mainThread.interrupt(); 644 }//fail() 645 }// class LWComboBox 646 class TestPassedException extends RuntimeException { 647 } 648 649 //*********** End Standard Test Machinery Section ********** 650 //************ Begin classes defined for the test **************** 651 // if want to make listeners, here is the recommended place for them, then instantiate 652 // them in init() 653 654 /* Example of a class which may be written as part of a test 655 class NewClass implements anInterface 656 { 657 static int newVar = 0; 658 659 public void eventDispatched(AWTEvent e) 660 { 661 //Counting events to see if we get enough 662 eventCount++; 663 664 if( eventCount == 20 ) 665 { 666 //got enough events, so pass 667 668 LWComboBox.pass(); 669 } 670 else if( tries == 20 ) 671 { 672 //tried too many times without getting enough events so fail 673 674 LWComboBox.fail(); 675 } 676 677 }// eventDispatched() 678 679 }// NewClass class 680 681 */ 682 //************** End classes defined for the test ******************* 683 /**************************************************** 684 Standard Test Machinery 685 DO NOT modify anything below -- it's a standard 686 chunk of code whose purpose is to make user 687 interaction uniform, and thereby make it simpler 688 to read and understand someone else's test. 689 ****************************************************/ 690 /** 691 This is part of the standard test machinery. 692 It creates a dialog (with the instructions), and is the interface 693 for sending text messages to the user. 694 To print the instructions, send an array of strings to Sysout.createDialog 695 WithInstructions method. Put one line of instructions per array entry. 696 To display a message for the tester to see, simply call Sysout.println 697 with the string to be displayed. 698 This mimics System.out.println but works within the test harness as well 699 as standalone. 700 */ 701 class Sysout { 702 private static TestDialog dialog; 703 704 public static void createDialogWithInstructions(String[] instructions) { 705 dialog = new TestDialog(new Frame(), "Instructions"); 706 dialog.printInstructions(instructions); 707 //dialog.setVisible(true); 708 println("Any messages for the tester will display here."); 709 } 710 711 public static void createDialog() { 712 dialog = new TestDialog(new Frame(), "Instructions"); 713 String[] defInstr = {"Instructions will appear here. ", ""}; 714 dialog.printInstructions(defInstr); 715 //dialog.setVisible(true); 716 println("Any messages for the tester will display here."); 717 } 718 719 public static void printInstructions(String[] instructions) { 720 dialog.printInstructions(instructions); 721 } 722 723 public static void println(String messageIn) { 724 dialog.displayMessage(messageIn); 725 System.out.println(messageIn); 726 } 727 }// Sysout class 728 729 /** 730 This is part of the standard test machinery. It provides a place for the 731 test instructions to be displayed, and a place for interactive messages 732 to the user to be displayed. 733 To have the test instructions displayed, see Sysout. 734 To have a message to the user be displayed, see Sysout. 735 Do not call anything in this dialog directly. 736 */ 737 class TestDialog extends Dialog { 738 TextArea instructionsText; 739 TextArea messageText; 740 int maxStringLength = 80; 741 742 //DO NOT call this directly, go through Sysout 743 public TestDialog(Frame frame, String name) { 744 super(frame, name); 745 int scrollBoth = TextArea.SCROLLBARS_BOTH; 746 instructionsText = new TextArea("", 15, maxStringLength, scrollBoth); 747 add("North", instructionsText); 748 749 messageText = new TextArea("", 5, maxStringLength, scrollBoth); 750 add("Center", messageText); 751 752 pack(); 753 754 //setVisible(true); 755 }// TestDialog() 756 757 //DO NOT call this directly, go through Sysout 758 public void printInstructions(String[] instructions) { 759 //Clear out any current instructions 760 instructionsText.setText(""); 761 762 //Go down array of instruction strings 763 764 String printStr, remainingStr; 765 for (int i = 0; i < instructions.length; i++) { 766 //chop up each into pieces maxSringLength long 767 remainingStr = instructions[i]; 768 while (remainingStr.length() > 0) { 769 //if longer than max then chop off first max chars to print 770 if (remainingStr.length() >= maxStringLength) { 771 //Try to chop on a word boundary 772 int posOfSpace = remainingStr.lastIndexOf(' ', maxStringLength - 1); 773 774 if (posOfSpace <= 0) { 775 posOfSpace = maxStringLength - 1; 776 } 777 778 printStr = remainingStr.substring(0, posOfSpace + 1); 779 remainingStr = remainingStr.substring(posOfSpace + 1); 780 } //else just print 781 else { 782 printStr = remainingStr; 783 remainingStr = ""; 784 } 785 786 instructionsText.append(printStr + "\n"); 787 788 }// while 789 790 }// for 791 792 }//printInstructions() 793 794 //DO NOT call this directly, go through Sysout 795 public void displayMessage(String messageIn) { 796 messageText.append(messageIn + "\n"); 797 System.out.println(messageIn); 798 } 799 }// TestDialog class 800