VisibilityValidator.java revision 15190:4e6f371bff5d
1/*
2 * Copyright (c) 2011, 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 * @summary Utility routines that wait for a window to be displayed or for
26colors to be visible
27 * @summary com.apple.junit.utils
28 */
29package test.java.awt.regtesthelpers;
30
31import java.awt.*;
32import java.awt.event.*;
33
34//import junit.framework.Assert;
35public class VisibilityValidator {
36
37    // Wait up to five seconds for our window events
38    static final int SETUP_PERIOD = 5000;
39    static final boolean DEBUG = false;
40
41    volatile Window win = null;
42    boolean activated = false;
43    boolean opened = false;
44    boolean focused = false;
45    volatile boolean valid = false;
46
47    //
48    // Utility functions that encapsulates normal usage patterns
49    //
50    public static void setVisibleAndConfirm(Frame testframe) throws Exception {
51        setVisibleAndConfirm(testframe, "Could not confirm test frame was "
52                + "visible");
53    }
54
55    public static void setVisibleAndConfirm(Frame testframe, String msg)
56            throws Exception {
57        if (testframe.isVisible()) {
58            throw new RuntimeException("Frame is already visible");
59        }
60
61        VisibilityValidator checkpoint = new VisibilityValidator(testframe);
62        testframe.setVisible(true);
63        checkpoint.requireVisible();
64        if (!checkpoint.isValid()) {
65            //System.err.println(msg);
66            throw new Exception("Frame not visible after " + SETUP_PERIOD
67                    + " milliseconds");
68        }
69    }
70
71    //
72    // Add listeners to the window
73    //
74    public VisibilityValidator(Window win) {
75        this.win = win;
76        WindowAdapter watcher = new WindowAdapter() {
77            public void windowOpened(WindowEvent e) {
78                doOpen();
79            }
80
81            public void windowActivated(WindowEvent e) {
82                doActivate();
83            }
84
85            public void windowGainedFocus(WindowEvent e) {
86                doGainedFocus();
87            }
88        };
89
90        win.addWindowListener(watcher);
91        win.addWindowFocusListener(watcher);
92    }
93
94    // Make the window visible
95    //
96    // The only way to make it through this routine is for the window to
97    // generate BOTH a windowOpened, a windowActivated event and a
98    // windowGainedFocus, or to timeout.
99    //
100    synchronized public void requireVisible() {
101        int tries = 0;
102
103        // wait for windowOpened and windowActivated events
104        try {
105            while ((opened == false)
106                    || (activated == false)
107                    || (focused == false)) {
108                if (tries < 4) {
109                    tries += 1;
110                    wait(SETUP_PERIOD);
111                } else {
112                    break;
113                }
114            }
115
116            if (opened && activated) {
117                valid = true;
118            } else {
119                valid = false;
120            }
121        } catch (InterruptedException ix) {
122            valid = false;
123        }
124
125        // Extra-super paranoid checks
126        if (win.isVisible() == false) {
127            valid = false;
128        }
129
130        if (win.isShowing() == false) {
131            valid = false;
132        }
133
134        if (win.isFocused() == false) {
135            valid = false;
136        }
137
138        if (DEBUG) {
139            if (!isValid()) {
140                System.out.println("\tactivated:" + new Boolean(activated));
141                System.out.println("\topened:" + new Boolean(opened));
142                System.out.println("\tfocused:" + new Boolean(focused));
143                System.out.println("\tvalid:" + new Boolean(valid));
144                System.out.println("\tisVisible():"
145                        + new Boolean(win.isVisible()));
146                System.out.println("\tisShowing():"
147                        + new Boolean(win.isShowing()));
148                System.out.println("\tisFocused():"
149                        + new Boolean(win.isFocused()));
150            }
151        }
152
153    }
154
155    synchronized void doOpen() {
156        opened = true;
157        notify();
158    }
159
160    synchronized void doActivate() {
161        activated = true;
162        notify();
163    }
164
165    synchronized void doGainedFocus() {
166        focused = true;
167        notify();
168    }
169
170    public boolean isValid() {
171        return valid;
172    }
173
174    public boolean isClear() {
175        return valid;
176    }
177
178    volatile static Robot robot = null;
179
180    // utility function that waits until a Component is shown with the
181    // appropriate color
182    public static boolean waitForColor(Component c,
183            Color expected) throws AWTException,
184            InterruptedException {
185        Dimension dim = c.getSize();
186        int xOff = dim.width / 2;
187        int yOff = dim.height / 2;
188        return waitForColor(c, xOff, yOff, expected);
189    }
190
191    // utility function that waits for 5 seconds for Component to be shown with
192    // the appropriate color
193    public static boolean waitForColor(Component c,
194            int xOff,
195            int yOff,
196            Color expected) throws AWTException, InterruptedException {
197        return waitForColor(c, xOff, yOff, expected, 5000L);
198    }
199
200    // utility function that waits until a Component is up with the appropriate
201    // color
202    public static boolean waitForColor(Component c,
203            int xOff,
204            int yOff,
205            Color expected,
206            long timeout) throws AWTException, InterruptedException {
207        Point p = c.getLocationOnScreen();
208        int x = (int) p.getX() + xOff;
209        int y = (int) p.getY() + yOff;
210        return waitForColor(x, y, expected, timeout);
211    }
212
213    // utility function that waits until specific screen coords have the
214    // appropriate color
215    public static boolean waitForColor(int locX,
216            int locY,
217            Color expected,
218            long timeout) throws AWTException, InterruptedException {
219        if (robot == null) {
220            robot = new Robot();
221        }
222
223        long endtime = System.currentTimeMillis() + timeout;
224        while (endtime > System.currentTimeMillis()) {
225            if (colorMatch(robot.getPixelColor(locX, locY), expected)) {
226                return true;
227            }
228            Thread.sleep(50);
229        }
230
231        return false;
232    }
233
234    // utility function that asserts that two colors are similar to each other
235    public static void assertColorEquals(final String message,
236            final Color actual,
237            final Color expected) {
238        System.out.println("actual color: " + actual);
239        System.out.println("expect color: " + expected);
240        //Assert.assertTrue(message, colorMatch(actual, expected));
241    }
242
243    // determines if two colors are close in hue and brightness
244    public static boolean colorMatch(final Color actual, final Color expected) {
245        final float[] actualHSB = getHSB(actual);
246        final float[] expectedHSB = getHSB(expected);
247
248        final float actualHue = actualHSB[0];
249        final float expectedHue = expectedHSB[0];
250        final boolean hueMatched = closeMatchHue(actualHue, expectedHue, 0.17f);
251        //System.out.println("hueMatched? " + hueMatched);
252        final float actualBrightness = actualHSB[2];
253        final float expectedBrightness = expectedHSB[2];
254        final boolean brightnessMatched = closeMatch(actualBrightness,
255                expectedBrightness, 0.15f);
256        //System.out.println("brightnessMatched? " + brightnessMatched);
257
258        // check to see if the brightness was so low or so high that the hue
259        // got clamped to red
260        if (brightnessMatched && !hueMatched) {
261            return (expectedBrightness < 0.15f);
262        }
263
264        return brightnessMatched && hueMatched;
265    }
266
267    static float[] getHSB(final Color color) {
268        final float[] hsb = new float[3];
269        Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), hsb);
270        return hsb;
271    }
272
273    // matches hues from 0.0 to 1.0, accounting for wrap-around at the 1.0/0.0
274    // boundry
275    static boolean closeMatchHue(final float actual,
276            final float expected,
277            final float tolerance) {
278        if (closeMatch(actual, expected, tolerance)) {
279            return true;
280        }
281
282        // all that remains is the overflow and underflow cases
283        final float expectedHigh = expected + tolerance;
284        final float expectedLow = expected - tolerance;
285
286        if (expectedHigh > 1.0f) {
287            // expected is too high, and actual was too low
288            //System.out.println("\thue expected too high, actual too low");
289            return closeMatch(actual + 0.5f, expected - 0.5f, tolerance);
290        }
291
292        if (expectedLow < 0.0f) {
293            // expected is too low, and actual was too high
294            //System.out.println("\thue expected too low, actual too high");
295            return closeMatch(actual - 0.5f, expected + 0.5f, tolerance);
296        }
297
298        //System.out.println("\tcloseMatchHue? " + false);
299        return false;
300    }
301
302    static boolean closeMatch(final float actual,
303            final float expected,
304            final float tolerance) {
305        return (expected + tolerance) > actual && (expected - tolerance) < actual;
306    }
307}
308