1 /*
   2  * Copyright (c) 2006, 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 /*
  25   @test
  26   @key headful
  27   @bug 6382144
  28   @summary REGRESSION: InputVerifier and JOptionPane
  29   @author oleg.sukhodolsky: area=awt.focus
  30   @run main EndlessLoopTest
  31 */
  32 
  33 /**
  34  * EndlessLoopTest.java
  35  *
  36  * summary: REGRESSION: InputVerifier and JOptionPane
  37  */
  38 
  39 import java.awt.AWTException;
  40 import java.awt.BorderLayout;
  41 import java.awt.Component;
  42 import java.awt.Dialog;
  43 import java.awt.Frame;
  44 import java.awt.Point;
  45 import java.awt.Robot;
  46 import java.awt.TextArea;
  47 import java.awt.Toolkit;
  48 
  49 import java.awt.event.ActionEvent;
  50 import java.awt.event.ActionListener;
  51 import java.awt.event.InputEvent;
  52 import java.awt.event.KeyEvent;
  53 
  54 import javax.swing.InputVerifier;
  55 import javax.swing.JButton;
  56 import javax.swing.JComponent;
  57 import javax.swing.JDialog;
  58 import javax.swing.JFrame;
  59 import javax.swing.JTextField;
  60 
  61 public class EndlessLoopTest
  62 {
  63 
  64     //*** test-writer defined static variables go here ***
  65     static volatile int n_iv_calls;
  66 
  67 
  68     private static void init()
  69     {
  70         //*** Create instructions for the user here ***
  71 
  72         String[] instructions =
  73         {
  74             "This is an AUTOMATIC test, simply wait until it is done.",
  75             "The result (passed or failed) will be shown in the",
  76             "message window below."
  77         };
  78         Sysout.createDialog( );
  79         Sysout.printInstructions( instructions );
  80 
  81         JFrame frame = new JFrame();
  82         final JDialog dialog = new JDialog(frame, true);
  83         JButton button = new JButton("press me");
  84         button.addActionListener(new ActionListener() {
  85                 public void actionPerformed(ActionEvent ae) {
  86                     dialog.dispose();
  87                 }
  88             });
  89         dialog.getContentPane().add(button);
  90         dialog.pack();
  91 
  92         JTextField t1 = new JTextField();
  93         t1.setInputVerifier(new InputVerifier() {
  94             public boolean verify(JComponent input) {
  95                 n_iv_calls++;
  96                 if (n_iv_calls == 1) {
  97                     dialog.setVisible(true);
  98                 }
  99                 return true;
 100             }
 101         });
 102         JTextField t2 = new JTextField();
 103 
 104 
 105         frame.getContentPane().add(t1, BorderLayout.NORTH);
 106         frame.getContentPane().add(t2, BorderLayout.SOUTH);
 107         frame.setSize(200, 200);
 108         frame.setVisible(true);
 109 
 110         Robot r = null;
 111         try {
 112             r = new Robot();
 113         } catch (AWTException e) {
 114             EndlessLoopTest.fail(e);
 115         }
 116 
 117         try {
 118             r.waitForIdle();
 119 
 120             mouseClickOnComp(r, t1);
 121             r.waitForIdle();
 122 
 123             if (!t1.isFocusOwner()) {
 124                 throw new RuntimeException("t1 is not a focus owner");
 125             }
 126             n_iv_calls = 0;
 127             r.keyPress(KeyEvent.VK_TAB);
 128             r.delay(10);
 129             r.keyRelease(KeyEvent.VK_TAB);
 130             r.waitForIdle();
 131 
 132             mouseClickOnComp(r, button);
 133             r.waitForIdle();
 134         } catch (Exception e) {
 135             EndlessLoopTest.fail(e);
 136         }
 137 
 138         if (n_iv_calls != 1) {
 139             EndlessLoopTest.fail(new RuntimeException("InputVerifier was called " + n_iv_calls + " times"));
 140         }
 141 
 142         EndlessLoopTest.pass();
 143 
 144     }//End  init()
 145 
 146 
 147     static void mouseClickOnComp(Robot r, Component comp) {
 148         Point loc = comp.getLocationOnScreen();
 149         loc.x += comp.getWidth() / 2;
 150         loc.y += comp.getHeight() / 2;
 151         r.mouseMove(loc.x, loc.y);
 152         r.delay(10);
 153         r.mousePress(InputEvent.BUTTON1_MASK);
 154         r.delay(10);
 155         r.mouseRelease(InputEvent.BUTTON1_MASK);
 156     }
 157 
 158     /*****************************************************
 159      * Standard Test Machinery Section
 160      * DO NOT modify anything in this section -- it's a
 161      * standard chunk of code which has all of the
 162      * synchronisation necessary for the test harness.
 163      * By keeping it the same in all tests, it is easier
 164      * to read and understand someone else's test, as
 165      * well as insuring that all tests behave correctly
 166      * with the test harness.
 167      * There is a section following this for test-
 168      * classes
 169      ******************************************************/
 170     private static boolean theTestPassed = false;
 171     private static boolean testGeneratedInterrupt = false;
 172     private static String failureMessage = "";
 173 
 174     private static Thread mainThread = null;
 175 
 176     private static int sleepTime = 300000;
 177 
 178     // Not sure about what happens if multiple of this test are
 179     //  instantiated in the same VM.  Being static (and using
 180     //  static vars), it aint gonna work.  Not worrying about
 181     //  it for now.
 182     public static void main( String args[] ) throws InterruptedException
 183     {
 184         mainThread = Thread.currentThread();
 185         try
 186         {
 187             init();
 188         }
 189         catch( TestPassedException e )
 190         {
 191             //The test passed, so just return from main and harness will
 192             // interepret this return as a pass
 193             return;
 194         }
 195         //At this point, neither test pass nor test fail has been
 196         // called -- either would have thrown an exception and ended the
 197         // test, so we know we have multiple threads.
 198 
 199         //Test involves other threads, so sleep and wait for them to
 200         // called pass() or fail()
 201         try
 202         {
 203             Thread.sleep( sleepTime );
 204             //Timed out, so fail the test
 205             throw new RuntimeException( "Timed out after " + sleepTime/1000 + " seconds" );
 206         }
 207         catch (InterruptedException e)
 208         {
 209             //The test harness may have interrupted the test.  If so, rethrow the exception
 210             // so that the harness gets it and deals with it.
 211             if( ! testGeneratedInterrupt ) throw e;
 212 
 213             //reset flag in case hit this code more than once for some reason (just safety)
 214             testGeneratedInterrupt = false;
 215 
 216             if ( theTestPassed == false )
 217             {
 218                 throw new RuntimeException( failureMessage );
 219             }
 220         }
 221 
 222     }//main
 223 
 224     public static synchronized void setTimeoutTo( int seconds )
 225     {
 226         sleepTime = seconds * 1000;
 227     }
 228 
 229     public static synchronized void pass()
 230     {
 231         Sysout.println( "The test passed." );
 232         Sysout.println( "The test is over, hit  Ctl-C to stop Java VM" );
 233         //first check if this is executing in main thread
 234         if ( mainThread == Thread.currentThread() )
 235         {
 236             //Still in the main thread, so set the flag just for kicks,
 237             // and throw a test passed exception which will be caught
 238             // and end the test.
 239             theTestPassed = true;
 240             throw new TestPassedException();
 241         }
 242         theTestPassed = true;
 243         testGeneratedInterrupt = true;
 244         mainThread.interrupt();
 245     }//pass()
 246 
 247     public static synchronized void fail( Exception whyFailed )
 248     {
 249         Sysout.println( "The test failed: " + whyFailed );
 250         Sysout.println( "The test is over, hit  Ctl-C to stop Java VM" );
 251         //check if this called from main thread
 252         if ( mainThread == Thread.currentThread() )
 253         {
 254             //If main thread, fail now 'cause not sleeping
 255             throw new RuntimeException( whyFailed );
 256         }
 257         theTestPassed = false;
 258         testGeneratedInterrupt = true;
 259         failureMessage = whyFailed.toString();
 260         mainThread.interrupt();
 261     }//fail()
 262 
 263 }// class EndlessLoopTest
 264 
 265 //This exception is used to exit from any level of call nesting
 266 // when it's determined that the test has passed, and immediately
 267 // end the test.
 268 class TestPassedException extends RuntimeException
 269 {
 270 }
 271 
 272 //*********** End Standard Test Machinery Section **********
 273 
 274 /****************************************************
 275  Standard Test Machinery
 276  DO NOT modify anything below -- it's a standard
 277   chunk of code whose purpose is to make user
 278   interaction uniform, and thereby make it simpler
 279   to read and understand someone else's test.
 280  ****************************************************/
 281 
 282 /**
 283  This is part of the standard test machinery.
 284  It creates a dialog (with the instructions), and is the interface
 285   for sending text messages to the user.
 286  To print the instructions, send an array of strings to Sysout.createDialog
 287   WithInstructions method.  Put one line of instructions per array entry.
 288  To display a message for the tester to see, simply call Sysout.println
 289   with the string to be displayed.
 290  This mimics System.out.println but works within the test harness as well
 291   as standalone.
 292  */
 293 
 294 class Sysout
 295 {
 296     private static TestDialog dialog;
 297 
 298     public static void createDialogWithInstructions( String[] instructions )
 299     {
 300         dialog = new TestDialog( new Frame(), "Instructions" );
 301         dialog.printInstructions( instructions );
 302         dialog.setVisible(true);
 303         println( "Any messages for the tester will display here." );
 304     }
 305 
 306     public static void createDialog( )
 307     {
 308         dialog = new TestDialog( new Frame(), "Instructions" );
 309         String[] defInstr = { "Instructions will appear here. ", "" } ;
 310         dialog.printInstructions( defInstr );
 311         dialog.setVisible(true);
 312         println( "Any messages for the tester will display here." );
 313     }
 314 
 315 
 316     public static void printInstructions( String[] instructions )
 317     {
 318         dialog.printInstructions( instructions );
 319     }
 320 
 321 
 322     public static void println( String messageIn )
 323     {
 324         dialog.displayMessage( messageIn );
 325         System.out.println(messageIn);
 326     }
 327 
 328 }// Sysout  class
 329 
 330 /**
 331   This is part of the standard test machinery.  It provides a place for the
 332    test instructions to be displayed, and a place for interactive messages
 333    to the user to be displayed.
 334   To have the test instructions displayed, see Sysout.
 335   To have a message to the user be displayed, see Sysout.
 336   Do not call anything in this dialog directly.
 337   */
 338 class TestDialog extends Dialog
 339 {
 340 
 341     TextArea instructionsText;
 342     TextArea messageText;
 343     int maxStringLength = 80;
 344 
 345     //DO NOT call this directly, go through Sysout
 346     public TestDialog( Frame frame, String name )
 347     {
 348         super( frame, name );
 349         int scrollBoth = TextArea.SCROLLBARS_BOTH;
 350         instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth );
 351         add( "North", instructionsText );
 352 
 353         messageText = new TextArea( "", 5, maxStringLength, scrollBoth );
 354         add("Center", messageText);
 355 
 356         pack();
 357 
 358         setVisible(true);
 359     }// TestDialog()
 360 
 361     //DO NOT call this directly, go through Sysout
 362     public void printInstructions( String[] instructions )
 363     {
 364         //Clear out any current instructions
 365         instructionsText.setText( "" );
 366 
 367         //Go down array of instruction strings
 368 
 369         String printStr, remainingStr;
 370         for( int i=0; i < instructions.length; i++ )
 371         {
 372             //chop up each into pieces maxSringLength long
 373             remainingStr = instructions[ i ];
 374             while( remainingStr.length() > 0 )
 375             {
 376                 //if longer than max then chop off first max chars to print
 377                 if( remainingStr.length() >= maxStringLength )
 378                 {
 379                     //Try to chop on a word boundary
 380                     int posOfSpace = remainingStr.
 381                         lastIndexOf( ' ', maxStringLength - 1 );
 382 
 383                     if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1;
 384 
 385                     printStr = remainingStr.substring( 0, posOfSpace + 1 );
 386                     remainingStr = remainingStr.substring( posOfSpace + 1 );
 387                 }
 388                 //else just print
 389                 else
 390                 {
 391                     printStr = remainingStr;
 392                     remainingStr = "";
 393                 }
 394 
 395                 instructionsText.append( printStr + "\n" );
 396 
 397             }// while
 398 
 399         }// for
 400 
 401     }//printInstructions()
 402 
 403     //DO NOT call this directly, go through Sysout
 404     public void displayMessage( String messageIn )
 405     {
 406         messageText.append( messageIn + "\n" );
 407         System.out.println(messageIn);
 408     }
 409 
 410 }// TestDialog  class