1 /*
2  * Copyright (c) 2011, 2015, 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 javax.swing.*;
25 import java.awt.*;
26 import java.awt.event.*;
27 import java.awt.image.BufferedImage;
28 import java.util.ArrayList;
29 import java.util.LinkedList;
30 import java.util.List;
31 import java.util.concurrent.Callable;
32 
33 /**
34  * <p>This class contains utilities useful for regression testing.
35  * <p>When using jtreg you would include this class via something like:
36  * <pre>
37  *
38  * @library ../../regtesthelpers
39  * @build Util
40  * </pre>
41  */
42 
43 public class Util {
44     /**
45      * Convert a rectangle from coordinate system of Component c to
46      * screen coordinate system.
47      *
48      * @param r a non-null Rectangle
49      * @param c a Component whose coordinate system is used for conversion
50      */
convertRectToScreen(Rectangle r, Component c)51     public static void convertRectToScreen(Rectangle r, Component c) {
52         Point p = new Point(r.x, r.y);
53         SwingUtilities.convertPointToScreen(p, c);
54         r.x = p.x;
55         r.y = p.y;
56     }
57 
58     /**
59      * Compares two bufferedImages pixel-by-pixel.
60      * return true if all pixels in the two areas are identical
61      */
compareBufferedImages(BufferedImage bufferedImage0, BufferedImage bufferedImage1)62     public static boolean compareBufferedImages(BufferedImage bufferedImage0, BufferedImage bufferedImage1) {
63         int width = bufferedImage0.getWidth();
64         int height = bufferedImage0.getHeight();
65 
66         if (width != bufferedImage1.getWidth() || height != bufferedImage1.getHeight()) {
67             return false;
68         }
69 
70         for (int y = 0; y < height; y++) {
71             for (int x = 0; x < width; x++) {
72                 if (bufferedImage0.getRGB(x, y) != bufferedImage1.getRGB(x, y)) {
73                     return false;
74                 }
75             }
76         }
77 
78         return true;
79     }
80 
81     /**
82      * Fills the heap until OutOfMemoryError occurs. This method is useful for
83      * WeakReferences removing.
84      */
generateOOME()85     public static void generateOOME() {
86         List<Object> bigLeak = new LinkedList<Object>();
87 
88         boolean oome = false;
89 
90         System.out.print("Filling the heap");
91 
92         try {
93             for(int i = 0; true ; i++) {
94                 // Now, use up all RAM
95                 bigLeak.add(new byte[1024 * 1024]);
96 
97                 System.out.print(".");
98 
99                 // Give the GC a change at that weakref
100                 if (i % 10 == 0) {
101                     System.gc();
102                     try {
103                         Thread.sleep(100);
104                     } catch (InterruptedException e) {
105                         e.printStackTrace();
106                     }
107                 }
108             }
109         } catch (OutOfMemoryError e) {
110             bigLeak = null;
111             oome = true;
112         }
113 
114         System.out.println("");
115 
116         if (!oome) {
117             throw new RuntimeException("Problem with test case - never got OOME");
118         }
119 
120         System.out.println("Got OOME");
121     }
122 
123     /**
124      * Find a sub component by class name.
125      * Always run this method on the EDT thread
126      */
findSubComponent(Component parent, String className)127     public static Component findSubComponent(Component parent, String className) {
128         String parentClassName = parent.getClass().getName();
129 
130         if (parentClassName.contains(className)) {
131             return parent;
132         }
133 
134         if (parent instanceof Container) {
135             for (Component child : ((Container) parent).getComponents()) {
136                 Component subComponent = findSubComponent(child, className);
137 
138                 if (subComponent != null) {
139                     return subComponent;
140                 }
141             }
142         }
143 
144         return null;
145     }
146 
147      /**
148      * Hits mnemonics by robot.
149      */
hitMnemonics(Robot robot, int... keys)150     public static void hitMnemonics(Robot robot, int... keys) {
151 
152         ArrayList<Integer> mnemonicKeyCodes = getSystemMnemonicKeyCodes();
153         for (Integer mnemonic : mnemonicKeyCodes) {
154             robot.keyPress(mnemonic);
155         }
156 
157         hitKeys(robot, keys);
158 
159         for (Integer mnemonic : mnemonicKeyCodes) {
160             robot.keyRelease(mnemonic);
161         }
162     }
163 
164      /**
165      * Hits keys by robot.
166      */
hitKeys(Robot robot, int... keys)167     public static void hitKeys(Robot robot, int... keys) {
168         for (int i = 0; i < keys.length; i++) {
169             robot.keyPress(keys[i]);
170         }
171 
172         for (int i = keys.length - 1; i >= 0; i--) {
173             robot.keyRelease(keys[i]);
174         }
175     }
176 
177     /**
178      * Moves mouse smoothly from (x0, y0) to (x1, y1).
179      */
glide(Robot robot, int x0, int y0, int x1, int y1)180     public static void glide(Robot robot, int x0, int y0, int x1, int y1) throws AWTException {
181         float dmax = (float) Math.max(Math.abs(x1 - x0), Math.abs(y1 - y0));
182         float dx = (x1 - x0) / dmax;
183         float dy = (y1 - y0) / dmax;
184 
185         for (int i = 0; i <= dmax; i += 10) {
186             robot.mouseMove((int) (x0 + dx * i), (int) (y0 + dy * i));
187         }
188     }
189 
190     /**
191      * Gets component center point
192      *
193      * @return center point of the <code>component</code>
194      */
getCenterPoint(final Component component)195     public static Point getCenterPoint(final Component component) throws Exception {
196         return Util.invokeOnEDT(new Callable<Point>() {
197 
198             @Override
199             public Point call() throws Exception {
200                 Point p = component.getLocationOnScreen();
201                 Dimension size = component.getSize();
202                 return new Point(p.x + size.width / 2, p.y + size.height / 2);
203             }
204         });
205     }
206 
207     /**
208      * Invokes the <code>task</code> on the EDT thread.
209      *
210      * @return result of the <code>task</code>
211      */
212     public static <T> T invokeOnEDT(final Callable<T> task) throws Exception {
213         final List<T> result = new ArrayList<>(1);
214         final Exception[] exception = new Exception[1];
215 
216         SwingUtilities.invokeAndWait(new Runnable() {
217             @Override
218             public void run() {
219                 try {
220                     result.add(task.call());
221                 } catch (Exception e) {
222                     exception[0] = e;
223                 }
224             }
225         });
226 
227         if (exception[0] != null) {
228             throw exception[0];
229         }
230 
231         return result.get(0);
232     }
233 
234     /**
235      * Gets the key codes list from modifiers
236      * @param modifiers an integer combination of the modifier constants
237      * @return key codes list
238      */
239     public static ArrayList<Integer> getKeyCodesFromKeyMask(int modifiers) {
240         ArrayList<Integer> result = new ArrayList<>();
241         if ((modifiers & InputEvent.CTRL_MASK) != 0) {
242             result.add(KeyEvent.VK_CONTROL);
243         }
244         if ((modifiers & InputEvent.ALT_MASK) != 0) {
245             result.add(KeyEvent.VK_ALT);
246         }
247         if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
248             result.add(KeyEvent.VK_SHIFT);
249         }
250         if ((modifiers & InputEvent.META_MASK) != 0) {
251             result.add(KeyEvent.VK_META);
252         }
253         return result;
254     }
255 
256     /**
257      * Gets key codes from system mnemonic key mask
258      * @return key codes list
259      */
260     public static ArrayList<Integer> getSystemMnemonicKeyCodes() {
261         String osName = System.getProperty("os.name");
262         ArrayList<Integer> result = new ArrayList<>();
263         if (osName.contains("OS X")) {
264             result.add(KeyEvent.VK_CONTROL);
265         }
266         result.add(KeyEvent.VK_ALT);
267         return result;
268     }
269 }
270