--- /dev/null 2013-02-26 17:16:58.251395135 +0400 +++ new/test/java/awt/regtesthelpers/VisibilityValidator.java 2013-02-27 17:23:10.759014700 +0400 @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @summary Utility routines that wait for a window to be displayed or for colors to be visible + * @summary com.apple.junit.utils + */ + +package test.java.awt.regtesthelpers; + +import java.awt.*; +import java.awt.event.*; + +import junit.framework.Assert; + +public class VisibilityValidator { + static final int SETUP_PERIOD = 5000; // Wait up to five seconds for our window events + static final boolean DEBUG = false; + + volatile Window win = null; + boolean activated = false; + boolean opened = false; + boolean focused = false; + volatile boolean valid = false; + + // + // Utility functions that encapsulates normal usage patterns + // + public static void setVisibleAndConfirm(Frame testframe) throws Exception { + setVisibleAndConfirm(testframe, "Could not confirm test frame was visible"); + } + + public static void setVisibleAndConfirm(Frame testframe, String msg) throws Exception { + if (testframe.isVisible()) { + throw new RuntimeException("Frame is already visible"); + } + + VisibilityValidator checkpoint = new VisibilityValidator(testframe); + testframe.setVisible(true); + checkpoint.requireVisible(); + if (!checkpoint.isValid()) { + //System.err.println(msg); + throw new Exception("Frame not visible after " + SETUP_PERIOD + " milliseconds"); + } + } + + // + // Add listeners to the window + // + public VisibilityValidator(Window win) { + this.win = win; + WindowAdapter watcher = new WindowAdapter() { + public void windowOpened(WindowEvent e) { + doOpen(); + } + + public void windowActivated(WindowEvent e) { + doActivate(); + } + + public void windowGainedFocus(WindowEvent e) { + doGainedFocus(); + } + }; + + win.addWindowListener(watcher); + win.addWindowFocusListener(watcher); + } + + // Make the window visible + // + // The only way to make it through this routine is for the window to generate BOTH + // a windowOpened, a windowActivated event and a windowGainedFocus, or to timeout. + // + synchronized public void requireVisible() { + int tries = 0; + + // wait for windowOpened and windowActivated events + try { + while ((opened == false) || (activated == false) || (focused == false)) { + if (tries < 4) { + tries += 1; + wait(SETUP_PERIOD); + } else { + break; + } + } + + if (opened && activated) { + valid = true; + } else { + valid = false; + } + } catch (InterruptedException ix) { + valid = false; + } + + // Extra-super paranoid checks + if (win.isVisible() == false) { + valid = false; + } + + if (win.isShowing() == false) { + valid = false; + } + + if (win.isFocused() == false) { + valid = false; + } + + if (DEBUG) { + if (!isValid()) { + System.out.println("\tactivated:" + new Boolean(activated)); + System.out.println("\topened:" + new Boolean(opened)); + System.out.println("\tfocused:" + new Boolean(focused)); + System.out.println("\tvalid:" + new Boolean(valid)); + System.out.println("\tisVisible():" + new Boolean(win.isVisible())); + System.out.println("\tisShowing():" + new Boolean(win.isShowing())); + System.out.println("\tisFocused():" + new Boolean(win.isFocused())); + } + } + + } + + synchronized void doOpen() { + opened = true; + notify(); + } + + synchronized void doActivate() { + activated = true; + notify(); + } + + synchronized void doGainedFocus() { + focused = true; + notify(); + } + + public boolean isValid() { + return valid; + } + + public boolean isClear() { + return valid; + } + + volatile static Robot robot = null; + + // utility function that waits until a Component is shown with the appropriate color + public static boolean waitForColor(Component c, Color expected) throws AWTException, InterruptedException { + Dimension dim = c.getSize(); + int xOff = dim.width / 2; + int yOff = dim.height / 2; + return waitForColor(c, xOff, yOff, expected); + } + + // utility function that waits for 5 seconds for Component to be shown with the appropriate color + public static boolean waitForColor(Component c, int xOff, int yOff, Color expected) throws AWTException, InterruptedException { + return waitForColor(c, xOff, yOff, expected, 5000L); + } + + // utility function that waits until a Component is up with the appropriate color + public static boolean waitForColor(Component c, int xOff, int yOff, Color expected, long timeout) throws AWTException, InterruptedException { + Point p = c.getLocationOnScreen(); + int x = (int)p.getX() + xOff; + int y = (int)p.getY() + yOff; + return waitForColor(x, y, expected, timeout); + } + + // utility function that waits until specific screen coords have the appropriate color + public static boolean waitForColor(int locX, int locY, Color expected, long timeout) throws AWTException, InterruptedException { + if (robot == null) { + robot = new Robot(); + } + + long endtime = System.currentTimeMillis() + timeout; + while (endtime > System.currentTimeMillis()) { + if (colorMatch(robot.getPixelColor(locX, locY), expected)) { + return true; + } + Thread.sleep(50); + } + + return false; + } + + // utility function that asserts that two colors are similar to each other + public static void assertColorEquals(final String message, final Color actual, final Color expected) { + //System.out.println("actual color: " + actual); + //System.out.println("expect color: " + expected); + Assert.assertTrue(message, colorMatch(actual, expected)); + } + + // determines if two colors are close in hue and brightness + public static boolean colorMatch(final Color actual, final Color expected) { + //System.out.println("colorMatch actual: " + actual + " expect: " + expected); + final float[] actualHSB = getHSB(actual); + final float[] expectedHSB = getHSB(expected); + + final float actualHue = actualHSB[0]; + final float expectedHue = expectedHSB[0]; + final boolean hueMatched = closeMatchHue(actualHue, expectedHue, 0.17f); + //System.out.println("hueMatched? " + hueMatched); + final float actualBrightness = actualHSB[2]; + final float expectedBrightness = expectedHSB[2]; + final boolean brightnessMatched = closeMatch(actualBrightness, expectedBrightness, 0.15f); + //System.out.println("brightnessMatched? " + brightnessMatched); + + // check to see if the brightness was so low or so high that the hue got clamped to red + if (brightnessMatched && !hueMatched) { + return (expectedBrightness < 0.15f); + } + + //System.out.println("colorMatched? " + (brightnessMatched && hueMatched)); + return brightnessMatched && hueMatched; + } + + static float[] getHSB(final Color color) { + final float[] hsb = new float[3]; + Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), hsb); + return hsb; + } + + // matches hues from 0.0 to 1.0, accounting for wrap-around at the 1.0/0.0 boundry + static boolean closeMatchHue(final float actual, final float expected, final float tolerance) { + if (closeMatch(actual, expected, tolerance)) return true; + + // all that remains is the overflow and underflow cases + final float expectedHigh = expected + tolerance; + final float expectedLow = expected - tolerance; + + if (expectedHigh > 1.0f) { + // expected is too high, and actual was too low + //System.out.println("\thue expected too high, actual too low"); + return closeMatch(actual + 0.5f, expected - 0.5f, tolerance); + } + + if (expectedLow < 0.0f) { + // expected is too low, and actual was too high + //System.out.println("\thue expected too low, actual too high"); + return closeMatch(actual - 0.5f, expected + 0.5f, tolerance); + } + + //System.out.println("\tcloseMatchHue? " + false); + return false; + } + + static boolean closeMatch(final float actual, final float expected, final float tolerance) { + //System.out.println("\tcloseMatch actual: " + actual + " expect: " + expected + " tolerance: " + tolerance); + //System.out.println("\tcloseMatch " + ((expected + tolerance) > actual) + " && " + ((expected - tolerance) < actual)); + return (expected + tolerance) > actual && (expected - tolerance) < actual; + } +}