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 /*
  25   test
  26   @bug 4870762
  27   @summary tests that a drop target JVM doesn't crash if the source doesn't export
  28            data in native formats.
  29   @author das@sparc.spb.su area=dnd
  30   @compile NoFormatsCrashTest.java
  31   @run applet NoFormatsCrashTest.html
  32 */
  33 
  34 // Note there is no @ in front of test above.  This is so that the
  35 //  harness will not mistake this file as a test file.  It should
  36 //  only see the html file as a test file. (the harness runs all
  37 //  valid test files, so it would run this test twice if this file
  38 //  were valid as well as the html file.)
  39 // Also, note the area= after Your Name in the author tag.  Here, you
  40 //  should put which functional area the test falls in.  See the
  41 //  AWT-core home page -> test areas and/or -> AWT team  for a list of
  42 //  areas.
  43 // Note also the 'NoFormatsCrashTest.html' in the run tag.  This should
  44 //  be changed to the name of the test.
  45 
  46 
  47 /**
  48  * NoFormatsCrashTest.java
  49  *
  50  * summary: tests that a drop target JVM doesn't crash if the source doesn't export
  51  *          data in native formats.
  52  */
  53 
  54 import java.applet.Applet;
  55 import java.awt.*;
  56 import java.awt.datatransfer.*;
  57 import java.awt.dnd.*;
  58 import java.awt.event.*;
  59 import java.io.*;
  60 
  61 
  62 //Automated tests should run as applet tests if possible because they
  63 // get their environments cleaned up, including AWT threads, any
  64 // test created threads, and any system resources used by the test
  65 // such as file descriptors.  (This is normally not a problem as
  66 // main tests usually run in a separate VM, however on some platforms
  67 // such as the Mac, separate VMs are not possible and non-applet
  68 // tests will cause problems).  Also, you don't have to worry about
  69 // synchronisation stuff in Applet tests they way you do in main
  70 // tests...
  71 
  72 
  73 public class NoFormatsCrashTest extends Applet {
  74 
  75     final Frame frame = new Frame();
  76     private volatile Process process;
  77 
  78     static final int FRAME_ACTIVATION_TIMEOUT = 2000;
  79 
  80     public static void main(String[] args) {
  81         NoFormatsCrashTest test = new NoFormatsCrashTest();
  82         test.run(args);
  83     }
  84 
  85     public void run(String[] args) {
  86         try {
  87             if (args.length != 4) {
  88                 throw new RuntimeException("Incorrect command line arguments.");
  89             }
  90 
  91             int x = Integer.parseInt(args[0]);
  92             int y = Integer.parseInt(args[1]);
  93             int w = Integer.parseInt(args[2]);
  94             int h = Integer.parseInt(args[3]);
  95 
  96             Panel panel = new DragSourcePanel();
  97 
  98             frame.setTitle("Drag source frame");
  99             frame.setLocation(500, 200);
 100             frame.add(panel);
 101             frame.pack();
 102             frame.setVisible(true);
 103 
 104             Thread.sleep(FRAME_ACTIVATION_TIMEOUT);
 105 
 106             Point sourcePoint = panel.getLocationOnScreen();
 107             Dimension d = panel.getSize();
 108             sourcePoint.translate(d.width / 2, d.height / 2);
 109 
 110             Point targetPoint = new Point(x + w / 2, y + h / 2);
 111 
 112             Robot robot = new Robot();
 113             robot.mouseMove(sourcePoint.x, sourcePoint.y);
 114             robot.keyPress(KeyEvent.VK_CONTROL);
 115             robot.mousePress(InputEvent.BUTTON1_MASK);
 116             for (; !sourcePoint.equals(targetPoint);
 117                  sourcePoint.translate(sign(targetPoint.x - sourcePoint.x),
 118                                        sign(targetPoint.y - sourcePoint.y))) {
 119                 robot.mouseMove(sourcePoint.x, sourcePoint.y);
 120                 Thread.sleep(50);
 121             }
 122             robot.mouseRelease(InputEvent.BUTTON1_MASK);
 123             robot.keyRelease(KeyEvent.VK_CONTROL);
 124 
 125             Thread.sleep(FRAME_ACTIVATION_TIMEOUT);
 126 
 127             if (process.isAlive()) {
 128                 process.destroy();
 129             }
 130         } catch (Throwable e) {
 131             e.printStackTrace();
 132             throw new RuntimeException(e);
 133         }
 134     } // run()
 135 
 136     public void init() {
 137         //Create instructions for the user here, as well as set up
 138         // the environment -- set the layout manager, add buttons,
 139         // etc.
 140 
 141         String[] instructions =
 142         {
 143             "This is an AUTOMATIC test",
 144             "simply wait until it is done"
 145         };
 146         Sysout.createDialog( );
 147         Sysout.printInstructions( instructions );
 148 
 149         frame.setTitle("Drop target frame");
 150         frame.setLocation(200, 200);
 151 
 152     } // init()
 153 
 154     public void start() {
 155         DropTargetPanel panel = new DropTargetPanel();
 156         frame.add(panel);
 157         frame.pack();
 158         frame.setVisible(true);
 159 
 160         try {
 161             Thread.sleep(FRAME_ACTIVATION_TIMEOUT);
 162 
 163             Point p = frame.getLocationOnScreen();
 164             Dimension d = frame.getSize();
 165 
 166             String javaPath = System.getProperty("java.home", "");
 167             String command = javaPath + File.separator + "bin" +
 168                 File.separator + "java -cp " + System.getProperty("test.classes", ".") +
 169                 " NoFormatsCrashTest " +
 170                 p.x + " " + p.y + " " + d.width + " " + d.height;
 171 
 172             process = Runtime.getRuntime().exec(command);
 173             ProcessResults pres = ProcessResults.doWaitFor(process);
 174             System.err.println("Child VM return code: " + pres.exitValue);
 175 
 176             if (pres.stderr != null && pres.stderr.length() > 0) {
 177                 System.err.println("========= Child VM System.err ========");
 178                 System.err.print(pres.stderr);
 179                 System.err.println("======================================");
 180             }
 181 
 182             if (pres.stdout != null && pres.stdout.length() > 0) {
 183                 System.err.println("========= Child VM System.out ========");
 184                 System.err.print(pres.stdout);
 185                 System.err.println("======================================");
 186             }
 187 
 188         } catch (Throwable e) {
 189             e.printStackTrace();
 190             throw new RuntimeException(e);
 191         }
 192 
 193         if (panel.isTestFailed()) {
 194             throw new RuntimeException();
 195         }
 196     } // start()
 197 
 198     public static int sign(int n) {
 199         return n < 0 ? -1 : n > 0 ? 1 : 0;
 200     }
 201 } // class NoFormatsCrashTest
 202 
 203 class TestTransferable implements Transferable {
 204 
 205     public static DataFlavor dataFlavor = null;
 206     static final Object data = new Object();
 207 
 208     static {
 209         DataFlavor df = null;
 210         try {
 211             df = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType +
 212                                 "; class=java.lang.Object");
 213         } catch (ClassNotFoundException e) {
 214             throw new ExceptionInInitializerError(e);
 215         }
 216         dataFlavor = df;
 217     }
 218 
 219     public DataFlavor[] getTransferDataFlavors() {
 220         return new DataFlavor[] { dataFlavor };
 221     }
 222 
 223     public boolean isDataFlavorSupported(DataFlavor df) {
 224         return dataFlavor.equals(df);
 225     }
 226 
 227     public Object getTransferData(DataFlavor df)
 228       throws UnsupportedFlavorException, IOException {
 229         if (!isDataFlavorSupported(df)) {
 230             throw new UnsupportedFlavorException(df);
 231         }
 232         return data;
 233     }
 234 }
 235 
 236 class DragSourcePanel extends Panel {
 237     public DragSourcePanel() {
 238         final Transferable t = new TestTransferable();
 239         final DragSourceListener dsl = new DragSourceAdapter() {
 240                 public void dragDropEnd(DragSourceDropEvent dtde) {
 241                     try {
 242                         Thread.sleep(100);
 243                     } catch (InterruptedException e) {
 244                         e.printStackTrace();
 245                     }
 246                     // This finishes child VM
 247                     System.exit(0);
 248                 }
 249             };
 250         final DragGestureListener dgl = new DragGestureListener() {
 251                 public void dragGestureRecognized(DragGestureEvent dge) {
 252                     dge.startDrag(null, t, dsl);
 253                 }
 254             };
 255         final DragSource ds = DragSource.getDefaultDragSource();
 256         final DragGestureRecognizer dgr =
 257             ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY,
 258                                                   dgl);
 259     }
 260 
 261     public Dimension getPreferredSize() {
 262         return new Dimension(100, 100);
 263     }
 264 }
 265 
 266 class DropTargetPanel extends Panel {
 267     private boolean testFailed = false;
 268     public DropTargetPanel() {
 269         final DropTargetListener dtl = new DropTargetAdapter() {
 270                 public void dragOver(DropTargetDragEvent dtde) {
 271                     try {
 272                         dtde.getCurrentDataFlavorsAsList();
 273                     } catch (Exception e) {
 274                         testFailed = true;
 275                         e.printStackTrace();
 276                     }
 277                 }
 278                 public void drop(DropTargetDropEvent dtde) {
 279                     dtde.rejectDrop();
 280                 }
 281             };
 282         final DropTarget dt = new DropTarget(this, dtl);
 283     }
 284 
 285     public boolean isTestFailed() {
 286         return testFailed;
 287     }
 288 
 289     public Dimension getPreferredSize() {
 290         return new Dimension(100, 100);
 291     }
 292 }
 293 
 294 class ProcessResults {
 295     public int exitValue;
 296     public String stdout;
 297     public String stderr;
 298 
 299     public ProcessResults() {
 300         exitValue = -1;
 301         stdout = "";
 302         stderr = "";
 303     }
 304 
 305     /**
 306      * Method to perform a "wait" for a process and return its exit value.
 307      * This is a workaround for <code>Process.waitFor()</code> never returning.
 308      */
 309     public static ProcessResults doWaitFor(Process p) {
 310         ProcessResults pres = new ProcessResults();
 311 
 312         InputStream in = null;
 313         InputStream err = null;
 314 
 315         try {
 316             in = p.getInputStream();
 317             err = p.getErrorStream();
 318 
 319             boolean finished = false;
 320 
 321             while (!finished) {
 322                 try {
 323                     while (in.available() > 0) {
 324                         pres.stdout += (char)in.read();
 325                     }
 326                     while (err.available() > 0) {
 327                         pres.stderr += (char)err.read();
 328                     }
 329                     // Ask the process for its exitValue. If the process
 330                     // is not finished, an IllegalThreadStateException
 331                     // is thrown. If it is finished, we fall through and
 332                     // the variable finished is set to true.
 333                     pres.exitValue = p.exitValue();
 334                     finished  = true;
 335                 }
 336                 catch (IllegalThreadStateException e) {
 337                     // Process is not finished yet;
 338                     // Sleep a little to save on CPU cycles
 339                     Thread.currentThread().sleep(500);
 340                 }
 341             }
 342             if (in != null) in.close();
 343             if (err != null) err.close();
 344         }
 345         catch (Throwable e) {
 346             System.err.println("doWaitFor(): unexpected exception");
 347             e.printStackTrace();
 348             throw new RuntimeException(e);
 349         }
 350         return pres;
 351     }
 352 }
 353 
 354 /****************************************************
 355  Standard Test Machinery
 356  DO NOT modify anything below -- it's a standard
 357   chunk of code whose purpose is to make user
 358   interaction uniform, and thereby make it simpler
 359   to read and understand someone else's test.
 360  ****************************************************/
 361 
 362 /**
 363  This is part of the standard test machinery.
 364  It creates a dialog (with the instructions), and is the interface
 365   for sending text messages to the user.
 366  To print the instructions, send an array of strings to Sysout.createDialog
 367   WithInstructions method.  Put one line of instructions per array entry.
 368  To display a message for the tester to see, simply call Sysout.println
 369   with the string to be displayed.
 370  This mimics System.out.println but works within the test harness as well
 371   as standalone.
 372  */
 373 
 374 class Sysout
 375  {
 376    private static TestDialog dialog;
 377 
 378    public static void createDialogWithInstructions( String[] instructions )
 379     {
 380       dialog = new TestDialog( new Frame(), "Instructions" );
 381       dialog.printInstructions( instructions );
 382       dialog.show();
 383       println( "Any messages for the tester will display here." );
 384     }
 385 
 386    public static void createDialog( )
 387     {
 388       dialog = new TestDialog( new Frame(), "Instructions" );
 389       String[] defInstr = { "Instructions will appear here. ", "" } ;
 390       dialog.printInstructions( defInstr );
 391       dialog.show();
 392       println( "Any messages for the tester will display here." );
 393     }
 394 
 395 
 396    public static void printInstructions( String[] instructions )
 397     {
 398       dialog.printInstructions( instructions );
 399     }
 400 
 401 
 402    public static void println( String messageIn )
 403     {
 404       dialog.displayMessage( messageIn );
 405     }
 406 
 407  }// Sysout  class
 408 
 409 /**
 410   This is part of the standard test machinery.  It provides a place for the
 411    test instructions to be displayed, and a place for interactive messages
 412    to the user to be displayed.
 413   To have the test instructions displayed, see Sysout.
 414   To have a message to the user be displayed, see Sysout.
 415   Do not call anything in this dialog directly.
 416   */
 417 class TestDialog extends Dialog
 418  {
 419 
 420    TextArea instructionsText;
 421    TextArea messageText;
 422    int maxStringLength = 80;
 423 
 424    //DO NOT call this directly, go through Sysout
 425    public TestDialog( Frame frame, String name )
 426     {
 427       super( frame, name );
 428       int scrollBoth = TextArea.SCROLLBARS_BOTH;
 429       instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth );
 430       add( "North", instructionsText );
 431 
 432       messageText = new TextArea( "", 5, maxStringLength, scrollBoth );
 433       add("South", messageText);
 434 
 435       pack();
 436 
 437       show();
 438     }// TestDialog()
 439 
 440    //DO NOT call this directly, go through Sysout
 441    public void printInstructions( String[] instructions )
 442     {
 443       //Clear out any current instructions
 444       instructionsText.setText( "" );
 445 
 446       //Go down array of instruction strings
 447 
 448       String printStr, remainingStr;
 449       for( int i=0; i < instructions.length; i++ )
 450        {
 451          //chop up each into pieces maxSringLength long
 452          remainingStr = instructions[ i ];
 453          while( remainingStr.length() > 0 )
 454           {
 455             //if longer than max then chop off first max chars to print
 456             if( remainingStr.length() >= maxStringLength )
 457              {
 458                //Try to chop on a word boundary
 459                int posOfSpace = remainingStr.
 460                   lastIndexOf( ' ', maxStringLength - 1 );
 461 
 462                if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1;
 463 
 464                printStr = remainingStr.substring( 0, posOfSpace + 1 );
 465                remainingStr = remainingStr.substring( posOfSpace + 1 );
 466              }
 467             //else just print
 468             else
 469              {
 470                printStr = remainingStr;
 471                remainingStr = "";
 472              }
 473 
 474             instructionsText.append( printStr + "\n" );
 475 
 476           }// while
 477 
 478        }// for
 479 
 480     }//printInstructions()
 481 
 482    //DO NOT call this directly, go through Sysout
 483    public void displayMessage( String messageIn )
 484     {
 485       messageText.append( messageIn + "\n" );
 486     }
 487 
 488  }// TestDialog  class