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
54import java.applet.Applet;
55import java.awt.*;
56import java.awt.datatransfer.*;
57import java.awt.dnd.*;
58import java.awt.event.*;
59import 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
73public 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
203class 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
236class 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
266class 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
294class 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
374class 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  */
417class 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
489