HierarchyBoundsListenerMixingTest.java revision 14851:980da45565c8
1/* 2 * Copyright (c) 2014, 2016, 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 25import java.awt.*; 26import java.awt.event.*; 27import java.lang.reflect.InvocationTargetException; 28import javax.swing.SwingUtilities; 29import java.io.*; 30 31/** 32 * AWT Mixing test for HierarchyBoundsListener ancestors. 33 * <p>See <a href="https://bugs.openjdk.java.net/browse/JDK-6768230">CR6768230</a> for details. 34 */ 35/* 36 * @test 37 * @key headful 38 * @bug 6768230 39 * @summary Mixing test for HierarchyBoundsListener ancestors 40 * @build FrameBorderCounter 41 * @run main HierarchyBoundsListenerMixingTest 42 */ 43public class HierarchyBoundsListenerMixingTest { 44 45 protected void prepareControls() { 46 dummy = new Frame(); 47 dummy.setSize(100, 100); 48 dummy.setLocation(0, 350); 49 dummy.setVisible(true); 50 51 frame = new Frame("Test Frame"); 52 frame.setLayout(new FlowLayout()); 53 54 panel = new Panel(); 55 button = new Button("Button"); 56 label = new Label("Label"); 57 list = new List(); 58 list.add("One"); 59 list.add("Two"); 60 list.add("Three"); 61 choice = new Choice(); 62 choice.add("Red"); 63 choice.add("Orange"); 64 choice.add("Yellow"); 65 checkbox = new Checkbox("Checkbox"); 66 scrollbar = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, 255); 67 textfield = new TextField(15); 68 textarea = new TextArea(5, 15); 69 70 components = new Component[] { 71 panel, button, label, list, choice, checkbox, scrollbar, textfield, textarea 72 }; 73 ancestorResized = new boolean[components.length]; 74 ancestorMoved = new boolean[components.length]; 75 76 frame.addWindowListener(new WindowAdapter() { 77 @Override 78 public void windowClosing(WindowEvent event) { 79 System.err.println("User closed the window"); 80 } 81 }); 82 83 HierarchyBoundsListener listener = new HierarchyBoundsListenerImpl(); 84 for (int i = 0; i < components.length; i++) { 85 components[i].addHierarchyBoundsListener(listener); 86 frame.add(components[i]); 87 } 88 frame.setSize(300, 300); 89 frame.setVisible(true); 90 } 91 92 private int frameBorderCounter() { 93 String JAVA_HOME = System.getProperty("java.home"); 94 95 try { 96 Process p = Runtime.getRuntime().exec(JAVA_HOME + "/bin/java FrameBorderCounter"); 97 try { 98 p.waitFor(); 99 } catch (InterruptedException e) { 100 e.printStackTrace(); 101 throw new RuntimeException(e); 102 } 103 if (p.exitValue() != 0) { 104 throw new RuntimeException("FrameBorderCounter exited with not null code!\n" + readInputStream(p.getErrorStream())); 105 } 106 return Integer.parseInt(readInputStream(p.getInputStream()).trim()); 107 } catch (IOException e) { 108 e.printStackTrace(); 109 throw new RuntimeException(e); 110 } 111 } 112 113 private String readInputStream(InputStream is) throws IOException { 114 byte[] buffer = new byte[4096]; 115 int len = 0; 116 StringBuilder sb = new StringBuilder(); 117 try (InputStreamReader isr = new InputStreamReader(is)) { 118 while ((len = is.read(buffer)) > 0) { 119 sb.append(new String(buffer, 0, len)); 120 } 121 } 122 return sb.toString(); 123 } 124 125 protected boolean performTest() { 126 int BORDER_SHIFT = frameBorderCounter(); 127 BORDER_SHIFT = Math.abs(BORDER_SHIFT) == 1 ? BORDER_SHIFT : BORDER_SHIFT / 2; 128 Robot robot = null; 129 try { 130 robot = new Robot(); 131 Thread.sleep(delay * 10); 132 } catch (Exception e) { 133 e.printStackTrace(); 134 throw new RuntimeException("Robot creation exception."); 135 } 136 137 robot.mouseMove((int) components[0].getLocationOnScreen().x + components[0].getSize().width / 2, 138 (int) components[0].getLocationOnScreen().y + components[0].getSize().height / 2); 139 robot.delay(delay); 140 robot.mousePress(InputEvent.BUTTON1_MASK); 141 robot.delay(delay); 142 robot.mouseRelease(InputEvent.BUTTON1_MASK); 143 robot.delay(delay); 144 145 resetValues(); 146 try { 147 EventQueue.invokeAndWait(new Runnable() { 148 public void run() { 149 frame.setSize(new Dimension(frame.getSize().width + 10, frame.getSize().height + 10)); 150 frame.invalidate(); 151 frame.validate(); 152 } 153 }); 154 } catch (Exception e) { 155 e.printStackTrace(); 156 passed = false; 157 } 158 if (! resizeTriggered) { 159 synchronized (resizeLock) { 160 try { 161 resizeLock.wait(delay * 10); 162 } catch (Exception e) { 163 } 164 } 165 } 166 for (int i = 0; i < components.length; i++) { 167 if (! ancestorResized[i]) { 168 System.err.println("FAIL: Frame resized using API call. " + 169 "Ancestor resized event did not occur for " + components[i].getClass()); 170 passed = false; 171 } 172 } 173 if (moveCount > 0) { 174 System.err.println("FAIL: Ancestor moved event occured when Frame resized using API"); 175 passed = false; 176 } 177 robot.delay(delay * 5); 178 179 resetValues(); 180 int x = (int) frame.getLocationOnScreen().x; 181 int y = (int) frame.getLocationOnScreen().y; 182 int w = frame.getSize().width; 183 int h = frame.getSize().height; 184 185 robot.mouseMove(x + w + BORDER_SHIFT, y + h / 2); 186 robot.delay(delay); 187 robot.mousePress(InputEvent.BUTTON1_MASK); 188 robot.delay(delay); 189 for (int i = 0; i < 20; i++) { 190 robot.mouseMove(x + w + i + BORDER_SHIFT, y + h / 2); 191 robot.delay(50); 192 } 193 robot.delay(delay); 194 robot.mouseRelease(InputEvent.BUTTON1_MASK); 195 196 if (! resizeTriggered) { 197 synchronized (resizeLock) { 198 try { 199 resizeLock.wait(delay * 10); 200 } catch (Exception e) { 201 } 202 } 203 } 204 205 for (int i = 0; i < components.length; i++) { 206 if (! ancestorResized[i]) { 207 System.err.println("FAIL: Frame resized using mouse action. " + 208 "Ancestor resized event did not occur for " + 209 components[i].getClass()); 210 passed = false; 211 } 212 } 213 if (moveCount > 0) { 214 System.err.println("FAIL: Ancestor moved event occured when Frame resized using mouse"); 215 passed = false; 216 } 217 218 resetValues(); 219 try { 220 EventQueue.invokeAndWait(new Runnable() { 221 public void run() { 222 frame.setLocation(frame.getLocation().x + 20, frame.getLocation().y + 20); 223 frame.invalidate(); 224 frame.validate(); 225 } 226 }); 227 } catch (Exception e) { 228 e.printStackTrace(); 229 passed = false; 230 } 231 if (! moveTriggered) { 232 synchronized (moveLock) { 233 try { 234 moveLock.wait(delay * 10); 235 } catch (Exception e) { 236 } 237 } 238 } 239 for (int i = 0; i < components.length; i++) { 240 if (! ancestorMoved[i]) { 241 System.err.println("FAIL: Frame moved using API call. " + 242 "Ancestor moved event did not occur for " + components[i].getClass()); 243 passed = false; 244 } 245 } 246 if (resizeCount > 0) { 247 System.err.println("FAIL: Ancestor resized event occured when Frame moved using API"); 248 passed = false; 249 } 250 robot.delay(delay * 10); 251 252 resetValues(); 253 x = (int) frame.getLocationOnScreen().x; 254 y = (int) frame.getLocationOnScreen().y; 255 w = frame.getSize().width; 256 h = frame.getSize().height; 257 258 //Click on the dummy frame so that the test frame loses focus. This is to workaround 259 //a bug in Linux AS. 260 robot.mouseMove((int) dummy.getLocationOnScreen().x + dummy.getSize().width / 2, 261 (int) dummy.getLocationOnScreen().y + dummy.getSize().height / 2); 262 robot.delay(delay); 263 robot.mousePress(InputEvent.BUTTON1_MASK); 264 robot.delay(delay); 265 robot.mouseRelease(InputEvent.BUTTON1_MASK); 266 robot.delay(delay); 267 268 robot.mouseMove(x + w / 2, y + 10); 269 robot.delay(delay); 270 robot.mousePress(InputEvent.BUTTON1_MASK); 271 robot.delay(delay); 272 for (int i = 1; i <= 20; i++) { 273 robot.mouseMove(x + w / 2 + i, y + 10); 274 robot.delay(50); 275 } 276 robot.delay(delay); 277 robot.mouseRelease(InputEvent.BUTTON1_MASK); 278 279 if (! moveTriggered) { 280 synchronized (moveLock) { 281 try { 282 moveLock.wait(delay * 10); 283 } catch (Exception e) { 284 } 285 } 286 } 287 288 for (int i = 0; i < components.length; i++) { 289 if (! ancestorMoved[i]) { 290 System.err.println("FAIL: Frame moved using mouse action. " + 291 "Ancestor moved event did not occur for " + components[i].getClass()); 292 passed = false; 293 } 294 } 295 if (resizeCount > 0) { 296 System.err.println("FAIL: Ancestor resized event occured when Frame moved using mouse"); 297 passed = false; 298 } 299 300 return passed; 301 } 302 303 private void resetValues() { 304 moveTriggered = false; 305 resizeTriggered = false; 306 moveCount = 0; 307 resizeCount = 0; 308 for (int i = 0; i < ancestorResized.length; i++) { 309 ancestorResized[i] = false; 310 ancestorMoved[i] = false; 311 } 312 } 313 314 private void keyType(int key, Robot robot) throws Exception { 315 robot.keyPress(key); 316 robot.delay(keyDelay); 317 robot.keyRelease(key); 318 robot.delay(keyDelay); 319 } 320 321 class HierarchyBoundsListenerImpl implements HierarchyBoundsListener { 322 // checks for Ancestor_Moved events 323 public void ancestorMoved(HierarchyEvent ce) { 324 if (check) { 325 System.out.println("Moved " + ce.getComponent()); 326 } 327 for (int i = 0; i < components.length; i++) { 328 if (components[i].equals(ce.getComponent())) { 329 //setting this array for purpose of checking ancestor_moved. 330 ancestorMoved[i] = true; 331 moveCount++; 332 if (moveCount == components.length) { 333 moveTriggered = true; 334 synchronized (moveLock) { 335 try { 336 moveLock.notifyAll(); 337 } catch (Exception e) { 338 } 339 } 340 } 341 } 342 } 343 } 344 // checks for Ancestor_Moved events 345 public void ancestorResized(HierarchyEvent ce) { 346 if (check) { 347 System.out.println("Resized " + ce.getComponent()); 348 } 349 for (int i = 0; i < components.length; i++) { 350 if (components[i].equals(ce.getComponent())) { 351 if (! frame.equals(ce.getChanged()) || ce.getChangedParent() != null) { 352 System.err.println("FAIL: Invalid value of HierarchyEvent.getXXX"); 353 System.err.println("ce.getChanged() : " + ce.getChanged()); 354 System.err.println("ce.getChangedParent() : " + ce.getChangedParent()); 355 passed = false; 356 } 357 //setting this array for purpose of checking ancestor_resized 358 ancestorResized[i] = true; 359 resizeCount++; 360 if (resizeCount == components.length) { 361 resizeTriggered = true; 362 synchronized (resizeLock) { 363 try { 364 resizeLock.notifyAll(); 365 } catch (Exception e) { 366 } 367 } 368 } 369 } 370 } 371 } 372 } 373 374 private Frame frame, dummy; 375 private Panel panel; 376 private Button button; 377 private Label label; 378 private List list; 379 private Choice choice; 380 private Checkbox checkbox; 381 private Scrollbar scrollbar; 382 private TextField textfield; 383 private TextArea textarea; 384 private Component[] components; 385 private boolean[] ancestorResized; 386 private boolean[] ancestorMoved; 387 388 private int delay = 500; 389 private int keyDelay = 50; 390 private int moveCount = 0; 391 private int resizeCount = 0; 392 393 private boolean passed = true; 394 private boolean moveTriggered = false; 395 private boolean resizeTriggered = false; 396 private final Object moveLock = new Object(); 397 private final Object resizeLock = new Object(); 398 399 private boolean check = false; 400 401 private void invoke() throws InterruptedException { 402 try { 403 SwingUtilities.invokeAndWait(new Runnable() { 404 405 public void run() { 406 prepareControls(); 407 } 408 }); 409 try { 410 Thread.sleep(1000); // wait for graphic effects on systems like Win7 411 } catch (InterruptedException ex) { 412 } 413 if (!performTest()) { 414 fail("Test failed"); 415 } 416 } catch (InvocationTargetException ex) { 417 fail(ex.getMessage()); 418 } 419 } 420 421 /***************************************************** 422 * Standard Test Machinery Section 423 * DO NOT modify anything in this section -- it's a 424 * standard chunk of code which has all of the 425 * synchronisation necessary for the test harness. 426 * By keeping it the same in all tests, it is easier 427 * to read and understand someone else's test, as 428 * well as insuring that all tests behave correctly 429 * with the test harness. 430 * There is a section following this for test- 431 * classes 432 ******************************************************/ 433 private static void init() throws InterruptedException { 434 //*** Create instructions for the user here *** 435 //System.setProperty("sun.awt.disableMixing", "true"); 436 437 String[] instructions = { 438 "This is an AUTOMATIC test, simply wait until it is done.", 439 "The result (passed or failed) will be shown in the", 440 "message window below." 441 }; 442 Sysout.createDialog(); 443 Sysout.printInstructions(instructions); 444 445 HierarchyBoundsListenerMixingTest instance = new HierarchyBoundsListenerMixingTest(); 446 447 instance.invoke(); 448 449 pass(); 450 }//End init() 451 private static boolean theTestPassed = false; 452 private static boolean testGeneratedInterrupt = false; 453 private static String failureMessage = ""; 454 private static Thread mainThread = null; 455 private static int sleepTime = 300000; 456 457 // Not sure about what happens if multiple of this test are 458 // instantiated in the same VM. Being static (and using 459 // static vars), it aint gonna work. Not worrying about 460 // it for now. 461 public static void main(String args[]) throws InterruptedException { 462 mainThread = Thread.currentThread(); 463 try { 464 init(); 465 } catch (TestPassedException e) { 466 //The test passed, so just return from main and harness will 467 // interepret this return as a pass 468 return; 469 } 470 //At this point, neither test pass nor test fail has been 471 // called -- either would have thrown an exception and ended the 472 // test, so we know we have multiple threads. 473 474 //Test involves other threads, so sleep and wait for them to 475 // called pass() or fail() 476 try { 477 Thread.sleep(sleepTime); 478 //Timed out, so fail the test 479 throw new RuntimeException("Timed out after " + sleepTime / 1000 + " seconds"); 480 } catch (InterruptedException e) { 481 //The test harness may have interrupted the test. If so, rethrow the exception 482 // so that the harness gets it and deals with it. 483 if (!testGeneratedInterrupt) { 484 throw e; 485 } 486 487 //reset flag in case hit this code more than once for some reason (just safety) 488 testGeneratedInterrupt = false; 489 490 if (theTestPassed == false) { 491 throw new RuntimeException(failureMessage); 492 } 493 } 494 495 }//main 496 497 public static synchronized void setTimeoutTo(int seconds) { 498 sleepTime = seconds * 1000; 499 } 500 501 public static synchronized void pass() { 502 Sysout.println("The test passed."); 503 Sysout.println("The test is over, hit Ctl-C to stop Java VM"); 504 //first check if this is executing in main thread 505 if (mainThread == Thread.currentThread()) { 506 //Still in the main thread, so set the flag just for kicks, 507 // and throw a test passed exception which will be caught 508 // and end the test. 509 theTestPassed = true; 510 throw new TestPassedException(); 511 } 512 theTestPassed = true; 513 testGeneratedInterrupt = true; 514 mainThread.interrupt(); 515 }//pass() 516 517 public static synchronized void fail() { 518 //test writer didn't specify why test failed, so give generic 519 fail("it just plain failed! :-)"); 520 } 521 522 public static synchronized void fail(String whyFailed) { 523 Sysout.println("The test failed: " + whyFailed); 524 Sysout.println("The test is over, hit Ctl-C to stop Java VM"); 525 //check if this called from main thread 526 if (mainThread == Thread.currentThread()) { 527 //If main thread, fail now 'cause not sleeping 528 throw new RuntimeException(whyFailed); 529 } 530 theTestPassed = false; 531 testGeneratedInterrupt = true; 532 failureMessage = whyFailed; 533 mainThread.interrupt(); 534 }//fail() 535}// class LWComboBox 536class TestPassedException extends RuntimeException { 537} 538 539//*********** End Standard Test Machinery Section ********** 540//************ Begin classes defined for the test **************** 541// if want to make listeners, here is the recommended place for them, then instantiate 542// them in init() 543 544/* Example of a class which may be written as part of a test 545class NewClass implements anInterface 546{ 547static int newVar = 0; 548 549public void eventDispatched(AWTEvent e) 550{ 551//Counting events to see if we get enough 552eventCount++; 553 554if( eventCount == 20 ) 555{ 556//got enough events, so pass 557 558LWComboBox.pass(); 559} 560else if( tries == 20 ) 561{ 562//tried too many times without getting enough events so fail 563 564LWComboBox.fail(); 565} 566 567}// eventDispatched() 568 569}// NewClass class 570 571 */ 572//************** End classes defined for the test ******************* 573/**************************************************** 574Standard Test Machinery 575DO NOT modify anything below -- it's a standard 576chunk of code whose purpose is to make user 577interaction uniform, and thereby make it simpler 578to read and understand someone else's test. 579 ****************************************************/ 580/** 581This is part of the standard test machinery. 582It creates a dialog (with the instructions), and is the interface 583for sending text messages to the user. 584To print the instructions, send an array of strings to Sysout.createDialog 585WithInstructions method. Put one line of instructions per array entry. 586To display a message for the tester to see, simply call Sysout.println 587with the string to be displayed. 588This mimics System.out.println but works within the test harness as well 589as standalone. 590 */ 591class Sysout { 592 593 private static TestDialog dialog; 594 595 public static void createDialogWithInstructions(String[] instructions) { 596 dialog = new TestDialog(new Frame(), "Instructions"); 597 dialog.printInstructions(instructions); 598 //dialog.setVisible(true); 599 println("Any messages for the tester will display here."); 600 } 601 602 public static void createDialog() { 603 dialog = new TestDialog(new Frame(), "Instructions"); 604 String[] defInstr = {"Instructions will appear here. ", ""}; 605 dialog.printInstructions(defInstr); 606 //dialog.setVisible(true); 607 println("Any messages for the tester will display here."); 608 } 609 610 public static void printInstructions(String[] instructions) { 611 dialog.printInstructions(instructions); 612 } 613 614 public static void println(String messageIn) { 615 dialog.displayMessage(messageIn); 616 System.out.println(messageIn); 617 } 618}// Sysout class 619 620/** 621This is part of the standard test machinery. It provides a place for the 622test instructions to be displayed, and a place for interactive messages 623to the user to be displayed. 624To have the test instructions displayed, see Sysout. 625To have a message to the user be displayed, see Sysout. 626Do not call anything in this dialog directly. 627 */ 628class TestDialog extends Dialog { 629 630 TextArea instructionsText; 631 TextArea messageText; 632 int maxStringLength = 80; 633 634 //DO NOT call this directly, go through Sysout 635 public TestDialog(Frame frame, String name) { 636 super(frame, name); 637 int scrollBoth = TextArea.SCROLLBARS_BOTH; 638 instructionsText = new TextArea("", 15, maxStringLength, scrollBoth); 639 add("North", instructionsText); 640 641 messageText = new TextArea("", 5, maxStringLength, scrollBoth); 642 add("Center", messageText); 643 644 pack(); 645 646 //setVisible(true); 647 }// TestDialog() 648 649 //DO NOT call this directly, go through Sysout 650 public void printInstructions(String[] instructions) { 651 //Clear out any current instructions 652 instructionsText.setText(""); 653 654 //Go down array of instruction strings 655 656 String printStr, remainingStr; 657 for (int i = 0; i < instructions.length; i++) { 658 //chop up each into pieces maxSringLength long 659 remainingStr = instructions[i]; 660 while (remainingStr.length() > 0) { 661 //if longer than max then chop off first max chars to print 662 if (remainingStr.length() >= maxStringLength) { 663 //Try to chop on a word boundary 664 int posOfSpace = remainingStr.lastIndexOf(' ', maxStringLength - 1); 665 666 if (posOfSpace <= 0) { 667 posOfSpace = maxStringLength - 1; 668 } 669 670 printStr = remainingStr.substring(0, posOfSpace + 1); 671 remainingStr = remainingStr.substring(posOfSpace + 1); 672 } //else just print 673 else { 674 printStr = remainingStr; 675 remainingStr = ""; 676 } 677 678 instructionsText.append(printStr + "\n"); 679 680 }// while 681 682 }// for 683 684 }//printInstructions() 685 686 //DO NOT call this directly, go through Sysout 687 public void displayMessage(String messageIn) { 688 messageText.append(messageIn + "\n"); 689 System.out.println(messageIn); 690 } 691}// TestDialog class 692 693