/* * Copyright (c) 2014, 2018, 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. */ import java.awt.*; import java.awt.event.*; import java.awt.peer.ComponentPeer; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import javax.swing.*; import sun.awt.AWTAccessor; import sun.awt.EmbeddedFrame; import java.io.*; import test.java.awt.regtesthelpers.Util; /** *
This class provides basis for AWT Mixing testing. *
It provides all standard test machinery and should be used by * extending and overriding next methods: *
Current AWT component should be added to the tested UI by {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) ()}. * There AWT components are prepared to be tested as being overlayed by other (e.g. Swing) components - they are colored to * {@link OverlappingTestBase#AWT_BACKGROUND_COLOR} and throws failure on catching mouse event. *
Validation of component being overlayed should be tested by {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point) } * See each method javadoc for more details. * *
Due to test machinery limitations all test should be run from their own main() by calling next coe
*
* public static void main(String args[]) throws InterruptedException {
* instance = new YourTestInstance();
* OverlappingTestBase.doMain(args);
* }
*
*
* @author Sergey Grinev
*/
public abstract class OverlappingTestBase {
// working variables
private static volatile boolean wasHWClicked = false;
private static volatile boolean passed = true;
// constants
/**
* Default color for AWT component used for validate correct drawing of overlapping. Never use it for lightweight components.
*/
protected static final Color AWT_BACKGROUND_COLOR = new Color(21, 244, 54);
protected static Color AWT_VERIFY_COLOR = AWT_BACKGROUND_COLOR;
protected static final int ROBOT_DELAY = 500;
private static final String[] simpleAwtControls = {"Button", "Checkbox", "Label", "TextArea"};
/**
* Generic strings array. To be used for population of List based controls.
*/
protected static final String[] petStrings = {"Bird", "Cat", "Dog", "Rabbit", "Rhynocephalia Granda", "Bear", "Tiger", "Mustang"};
// "properties"
/**
* Tests customization. Set this variable to test only control from java.awt
*
Usage of this variable should be marked with CR being the reason. *
Do not use this variable simultaneously with {@link OverlappingTestBase#skipClassNames} */ protected String onlyClassName = null; /** * For customizing tests. List classes' simple names to skip them from testings. *
Usage of this variable should be marked with CR being the reason.
*/
protected String[] skipClassNames = null;
/**
* Set to false to avoid event delivery validation
* @see OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean)
*/
protected boolean useClickValidation = true;
/**
* Set to false if test doesn't supposed to verify EmbeddedFrame
*/
protected boolean testEmbeddedFrame = false;
/**
* Set this variable to true if testing embedded frame is impossible (on Mac, for instance, for now).
* The testEmbeddedFrame is explicitly set to true in dozen places.
*/
protected boolean skipTestingEmbeddedFrame = false;
public static final boolean isMac = System.getProperty("os.name").toLowerCase().contains("os x");
private boolean isFrameBorderCalculated;
private int borderShift;
{ if (Toolkit.getDefaultToolkit().getClass().getName().matches(".*L.*Toolkit")) {
// No EmbeddedFrame in LWToolkit/LWCToolkit, yet
// And it should be programmed some other way, too, in any case
//System.err.println("skipTestingEmbeddedFrame");
//skipTestingEmbeddedFrame = true;
}else {
System.err.println("do not skipTestingEmbeddedFrame");
}
}
protected int frameBorderCounter() {
if (!isFrameBorderCalculated) {
try {
new FrameBorderCounter(); // force compilation by jtreg
String JAVA_HOME = System.getProperty("java.home");
Process p = Runtime.getRuntime().exec(JAVA_HOME + "/bin/java FrameBorderCounter");
try {
p.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
if (p.exitValue() != 0) {
throw new RuntimeException("FrameBorderCounter exited with not null code!\n" + readInputStream(p.getErrorStream()));
}
borderShift = Integer.parseInt(readInputStream(p.getInputStream()).trim());
isFrameBorderCalculated = true;
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Problem calculating a native border size");
}
}
return borderShift;
}
public void getVerifyColor() {
try {
final int size = 200;
final Point[] p = new Point[1];
SwingUtilities.invokeAndWait(new Runnable() {
public void run(){
JFrame frame = new JFrame("set back");
frame.getContentPane().setBackground(AWT_BACKGROUND_COLOR);
frame.setSize(size, size);
frame.setUndecorated(true);
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
p[0] = frame.getLocation();
}
});
Robot robot = new Robot();
robot.waitForIdle();
Thread.sleep(ROBOT_DELAY);
AWT_VERIFY_COLOR = robot.getPixelColor(p[0].x+size/2, p[0].y+size/2);
System.out.println("Color will be compared with " + AWT_VERIFY_COLOR + " instead of " + AWT_BACKGROUND_COLOR);
} catch (Exception e) {
System.err.println("Cannot get verify color: "+e.getMessage());
}
}
private String readInputStream(InputStream is) throws IOException {
byte[] buffer = new byte[4096];
int len = 0;
StringBuilder sb = new StringBuilder();
try (InputStreamReader isr = new InputStreamReader(is)) {
while ((len = is.read(buffer)) > 0) {
sb.append(new String(buffer, 0, len));
}
}
return sb.toString();
}
private void setupControl(final Component control) {
if (useClickValidation) {
control.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
System.err.println("ERROR: " + control.getClass() + " received mouse click.");
wasHWClicked = true;
}
});
}
control.setBackground(AWT_BACKGROUND_COLOR);
control.setForeground(AWT_BACKGROUND_COLOR);
control.setPreferredSize(new Dimension(150, 150));
control.setFocusable(false);
}
private void addAwtControl(java.util.List N.B.: if testEmbeddedFrame == true this method will also add EmbeddedFrame over Canvas
* and it should be called after Frame.setVisible(true) call
* @param container container to hold AWT component
*/
protected final void propagateAWTControls(Container container) {
if (currentAwtControl != null) {
container.add(currentAwtControl);
} else { // embedded frame
try {
//create embedder
Canvas embedder = new Canvas();
embedder.setBackground(Color.RED);
embedder.setPreferredSize(new Dimension(150, 150));
container.add(embedder);
container.setVisible(true); // create peer
long frameWindow = 0;
String getWindowMethodName = null;
String eframeClassName = null;
if (Toolkit.getDefaultToolkit().getClass().getName().contains("XToolkit")) {
java.awt.Helper.addExports("sun.awt.X11", OverlappingTestBase.class.getModule());
getWindowMethodName = "getWindow";
eframeClassName = "sun.awt.X11.XEmbeddedFrame";
}else if (Toolkit.getDefaultToolkit().getClass().getName().contains(".WToolkit")) {
java.awt.Helper.addExports("sun.awt.windows", OverlappingTestBase.class.getModule());
getWindowMethodName = "getHWnd";
eframeClassName = "sun.awt.windows.WEmbeddedFrame";
}else if (isMac) {
java.awt.Helper.addExports("sun.lwawt", OverlappingTestBase.class.getModule());
java.awt.Helper.addExports("sun.lwawt.macosx", OverlappingTestBase.class.getModule());
eframeClassName = "sun.lwawt.macosx.CViewEmbeddedFrame";
}
ComponentPeer peer = AWTAccessor.getComponentAccessor()
.getPeer(embedder);
if (!isMac) {
Method getWindowMethod = peer.getClass().getMethod(getWindowMethodName);
frameWindow = (Long) getWindowMethod.invoke(peer);
} else {
Method m_getPlatformWindowMethod = peer.getClass().getMethod("getPlatformWindow");
Object platformWindow = m_getPlatformWindowMethod.invoke(peer);
Class classPlatformWindow = Class.forName("sun.lwawt.macosx.CPlatformWindow");
Method m_getContentView = classPlatformWindow.getMethod("getContentView");
Object contentView = m_getContentView.invoke(platformWindow);
Class classContentView = Class.forName("sun.lwawt.macosx.CPlatformView");
Method m_getAWTView = classContentView.getMethod("getAWTView");
frameWindow = (Long) m_getAWTView.invoke(contentView);
}
Class eframeClass = Class.forName(eframeClassName);
Constructor eframeCtor = eframeClass.getConstructor(long.class);
EmbeddedFrame eframe = (EmbeddedFrame) eframeCtor.newInstance(frameWindow);
setupControl(eframe);
eframe.setSize(new Dimension(150, 150));
eframe.setVisible(true);
// System.err.println(eframe.getSize());
} catch (Exception ex) {
ex.printStackTrace();
fail("Failed to instantiate EmbeddedFrame: " + ex.getMessage());
}
}
}
private static final Font hugeFont = new Font("Arial", Font.BOLD, 70);
private java.util.List Firstly, verifies point by color pixel check
* Secondly, verifies event delivery by mouse click
* @param robot AWT Robot. Usually created by {@link Util#createRobot() }
* @param lLoc point to verify
* @param defaultShift if true verified position will be shifted by {@link OverlappingTestBase#shift }.
*/
protected void clickAndBlink(Robot robot, Point lLoc, boolean defaultShift) {
Point loc = lLoc.getLocation();
//check color
Util.waitForIdle(robot);
try{
Thread.sleep(500);
}catch(Exception exx){
exx.printStackTrace();
}
if (defaultShift) {
loc.translate(shift.x, shift.y);
}
if (!(System.getProperty("os.name").toLowerCase().contains("os x"))) {
Color c = robot.getPixelColor(loc.x, loc.y);
System.out.println("C&B. color: "+c+" compare with "+AWT_VERIFY_COLOR);
if (c.equals(AWT_VERIFY_COLOR)) {
fail(failMessageColorCheck);
passed = false;
}
// perform click
Util.waitForIdle(robot);
}
robot.mouseMove(loc.x, loc.y);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
Util.waitForIdle(robot);
}
/**
* This method should be overriden with code which setups UI for testing.
* Code in this method will be called only from AWT thread so Swing operations can be called directly.
*
* @see {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) } for instructions about adding tested AWT control to UI
*/
protected abstract void prepareControls();
/**
* This method should be overriden with test execution. It will not be called from AWT thread so all Swing operations should be treated accordingly.
* @return true if test passed. Otherwise fail with default fail message.
* @see {@link OverlappingTestBase#failMessage} default fail message
*/
protected abstract boolean performTest();
/**
* This method can be overriden with cleanup routines. It will be called from AWT thread so all Swing operations should be treated accordingly.
*/
protected void cleanup() {
// intentionally do nothing
}
/**
* Currect tested AWT Control. Usually shouldn't be accessed directly.
*
* @see {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) } for instructions about adding tested AWT control to UI
*/
protected Component currentAwtControl;
private void testComponent(Component component) throws InterruptedException, InvocationTargetException {
Robot robot = null;
try {
robot = new Robot();
}catch(Exception ignorex) {
}
currentAwtControl = component;
System.out.println("Testing " + currentAwtControl.getClass().getSimpleName());
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
prepareControls();
}
});
if (component != null) {
Util.waitTillShown(component);
}
Util.waitForIdle(robot);
try {
Thread.sleep(500); // wait for graphic effects on systems like Win7
} catch (InterruptedException ex) {
}
if (!instance.performTest()) {
fail(failMessage);
passed = false;
}
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
cleanup();
}
});
}
private void testEmbeddedFrame() throws InvocationTargetException, InterruptedException {
Robot robot = null;
try {
robot = new Robot();
}catch(Exception ignorex) {
}
System.out.println("Testing EmbeddedFrame");
currentAwtControl = null;
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
prepareControls();
}
});
Util.waitForIdle(robot);
try {
Thread.sleep(500); // wait for graphic effects on systems like Win7
} catch (InterruptedException ex) {
}
if (!instance.performTest()) {
fail(failMessage);
passed = false;
}
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
cleanup();
}
});
}
private void testAwtControls() throws InterruptedException {
try {
for (Component component : getAWTControls()) {
testComponent(component);
}
if (testEmbeddedFrame && !skipTestingEmbeddedFrame) {
testEmbeddedFrame();
}
} catch (InvocationTargetException ex) {
ex.printStackTrace();
fail(ex.getMessage());
}
}
/**
* Used by standard test machinery. See usage at {@link OverlappingTestBase }
*/
protected static OverlappingTestBase instance;
protected OverlappingTestBase() {
getVerifyColor();
}
/*****************************************************
* Standard Test Machinery Section
* DO NOT modify anything in this section -- it's a
* standard chunk of code which has all of the
* synchronisation necessary for the test harness.
* By keeping it the same in all tests, it is easier
* to read and understand someone else's test, as
* well as insuring that all tests behave correctly
* with the test harness.
* There is a section following this for test-
* classes
******************************************************/
private static void init() throws InterruptedException {
//System.setProperty("sun.awt.disableMixing", "true");
instance.testAwtControls();
if (wasHWClicked) {
fail("HW component received the click.");
passed = false;
}
if (passed) {
pass();
}
}//End init()
private static boolean theTestPassed = false;
private static boolean testGeneratedInterrupt = false;
private static String failureMessage = "";
private static Thread mainThread = null;
private static int sleepTime = 300000;
// Not sure about what happens if multiple of this test are
// instantiated in the same VM. Being static (and using
// static vars), it aint gonna work. Not worrying about
// it for now.
/**
* Starting point for test runs. See usage at {@link OverlappingTestBase }
* @param args regular main args, not used.
* @throws InterruptedException
*/
public static void doMain(String args[]) throws InterruptedException {
mainThread = Thread.currentThread();
try {
init();
} catch (TestPassedException e) {
//The test passed, so just return from main and harness will
// interepret this return as a pass
return;
}
//At this point, neither test pass nor test fail has been
// called -- either would have thrown an exception and ended the
// test, so we know we have multiple threads.
//Test involves other threads, so sleep and wait for them to
// called pass() or fail()
try {
Thread.sleep(sleepTime);
//Timed out, so fail the test
throw new RuntimeException("Timed out after " + sleepTime / 1000 + " seconds");
} catch (InterruptedException e) {
//The test harness may have interrupted the test. If so, rethrow the exception
// so that the harness gets it and deals with it.
if (!testGeneratedInterrupt) {
throw e;
}
//reset flag in case hit this code more than once for some reason (just safety)
testGeneratedInterrupt = false;
if (theTestPassed == false) {
throw new RuntimeException(failureMessage);
}
}
}//main
/**
* Test will fail if not passed after this timeout. Default timeout is 300 seconds.
* @param seconds timeout in seconds
*/
public static synchronized void setTimeoutTo(int seconds) {
sleepTime = seconds * 1000;
}
/**
* Set test as passed. Usually shoudn't be called directly.
*/
public static synchronized void pass() {
System.out.println("The test passed.");
System.out.println("The test is over, hit Ctl-C to stop Java VM");
//first check if this is executing in main thread
if (mainThread == Thread.currentThread()) {
//Still in the main thread, so set the flag just for kicks,
// and throw a test passed exception which will be caught
// and end the test.
theTestPassed = true;
throw new TestPassedException();
}
theTestPassed = true;
testGeneratedInterrupt = true;
mainThread.interrupt();
}//pass()
/**
* Fail test generic message.
*/
public static synchronized void fail() {
//test writer didn't specify why test failed, so give generic
fail("it just plain failed! :-)");
}
/**
* Fail test providing specific reason.
* @param whyFailed reason
*/
public static synchronized void fail(String whyFailed) {
System.out.println("The test failed: " + whyFailed);
System.out.println("The test is over, hit Ctl-C to stop Java VM");
//check if this called from main thread
if (mainThread == Thread.currentThread()) {
//If main thread, fail now 'cause not sleeping
throw new RuntimeException(whyFailed);
}
theTestPassed = false;
testGeneratedInterrupt = true;
failureMessage = whyFailed;
mainThread.interrupt();
}//fail()
}// class LWComboBox
class TestPassedException extends RuntimeException {
}
defaultShift == true
for {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean) }.
* This method is used to verify controls by providing just their plain screen coordinates.
* @param robot AWT Robot. Usually created by {@link Util#createRobot() }
* @param lLoc point to verify
* @see OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean)
*/
protected void clickAndBlink(Robot robot, Point lLoc) {
clickAndBlink(robot, lLoc, true);
}
/**
* Default failure message for color check
* @see OverlappingTestBase#performTest()
*/
protected String failMessageColorCheck = "The LW component did not pass pixel color check and is overlapped";
/**
* Default failure message event check
* @see OverlappingTestBase#performTest()
*/
protected String failMessage = "The LW component did not received the click.";
private static boolean isValidForPixelCheck(Component component) {
if ((component instanceof java.awt.Scrollbar) || isMac && (component instanceof java.awt.Button)) {
return false;
}
return true;
}
/**
* Preliminary validation - should be run before overlapping happens to ensure test is correct.
* @param robot AWT Robot. Usually created by {@link Util#createRobot() }
* @param lLoc point to validate to be of {@link OverlappingTestBase#AWT_BACKGROUND_COLOR}
* @param component tested component, should be pointed out as not all components are valid for pixel check.
*/
protected void pixelPreCheck(Robot robot, Point lLoc, Component component) {
if (isValidForPixelCheck(component)) {
int tries = 10;
Color c = null;
while (tries-- > 0) {
c = robot.getPixelColor(lLoc.x, lLoc.y);
System.out.println("Precheck. color: "+c+" compare with "+AWT_VERIFY_COLOR);
if (c.equals(AWT_VERIFY_COLOR)) {
return;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
System.err.println(lLoc + ": " + c);
fail("Dropdown test setup failure, colored part of AWT component is not located at click area");
}
}
/**
* Verifies point using specified AWT Robot.
*