Path: blob/master/test/jdk/java/awt/Mixing/AWT_Mixing/OverlappingTestBase.java
41152 views
/*1* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.awt.*;24import java.awt.event.*;25import java.awt.peer.ComponentPeer;26import java.lang.reflect.Constructor;27import java.lang.reflect.InvocationTargetException;28import java.lang.reflect.Method;29import java.util.ArrayList;30import javax.swing.*;3132import sun.awt.AWTAccessor;33import sun.awt.EmbeddedFrame;34import java.io.*;35import test.java.awt.regtesthelpers.Util;3637/**38* <p>This class provides basis for AWT Mixing testing.39* <p>It provides all standard test machinery and should be used by40* extending and overriding next methods:41* <li> {@link OverlappingTestBase#prepareControls()} - setup UI components42* <li> {@link OverlappingTestBase#performTest()} - run particular test43* Those methods would be run in the loop for each AWT component.44* <p>Current AWT component should be added to the tested UI by {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) ()}.45* There AWT components are prepared to be tested as being overlayed by other (e.g. Swing) components - they are colored to46* {@link OverlappingTestBase#AWT_BACKGROUND_COLOR} and throws failure on catching mouse event.47* <p> Validation of component being overlayed should be tested by {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point) }48* See each method javadoc for more details.49*50* <p>Due to test machinery limitations all test should be run from their own main() by calling next coe51* <code>52* public static void main(String args[]) throws InterruptedException {53* instance = new YourTestInstance();54* OverlappingTestBase.doMain(args);55* }56* </code>57*58* @author Sergey Grinev59*/60public abstract class OverlappingTestBase {61// working variables62private static volatile boolean wasHWClicked = false;63private static volatile boolean passed = true;64// constants65/**66* Default color for AWT component used for validate correct drawing of overlapping. <b>Never</b> use it for lightweight components.67*/68protected static final Color AWT_BACKGROUND_COLOR = new Color(21, 244, 54);69protected static Color AWT_VERIFY_COLOR = AWT_BACKGROUND_COLOR;70protected static final int ROBOT_DELAY = 500;71private static final String[] simpleAwtControls = {"Button", "Checkbox", "Label", "TextArea"};72/**73* Generic strings array. To be used for population of List based controls.74*/75protected static final String[] petStrings = {"Bird", "Cat", "Dog", "Rabbit", "Rhynocephalia Granda", "Bear", "Tiger", "Mustang"};76// "properties"77/**78* Tests customization. Set this variable to test only control from java.awt79* <p>Usage of this variable should be marked with CR being the reason.80* <p>Do not use this variable simultaneously with {@link OverlappingTestBase#skipClassNames}81*/82protected String onlyClassName = null;83/**84* For customizing tests. List classes' simple names to skip them from testings.85* <p>Usage of this variable should be marked with CR being the reason.86*/87protected String[] skipClassNames = null;88/**89* Set to false to avoid event delivery validation90* @see OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean)91*/92protected boolean useClickValidation = true;93/**94* Set to false if test doesn't supposed to verify EmbeddedFrame95*/96protected boolean testEmbeddedFrame = false;97/**98* Set this variable to true if testing embedded frame is impossible (on Mac, for instance, for now).99* The testEmbeddedFrame is explicitly set to true in dozen places.100*/101protected boolean skipTestingEmbeddedFrame = false;102103public static final boolean isMac = System.getProperty("os.name").toLowerCase().contains("os x");104private boolean isFrameBorderCalculated;105private int borderShift;106107{ if (Toolkit.getDefaultToolkit().getClass().getName().matches(".*L.*Toolkit")) {108// No EmbeddedFrame in LWToolkit/LWCToolkit, yet109// And it should be programmed some other way, too, in any case110//System.err.println("skipTestingEmbeddedFrame");111//skipTestingEmbeddedFrame = true;112}else {113System.err.println("do not skipTestingEmbeddedFrame");114}115}116117protected int frameBorderCounter() {118if (!isFrameBorderCalculated) {119try {120new FrameBorderCounter(); // force compilation by jtreg121String JAVA_HOME = System.getProperty("java.home");122Process p = Runtime.getRuntime().exec(JAVA_HOME + "/bin/java FrameBorderCounter");123try {124p.waitFor();125} catch (InterruptedException e) {126e.printStackTrace();127throw new RuntimeException(e);128}129if (p.exitValue() != 0) {130throw new RuntimeException("FrameBorderCounter exited with not null code!\n" + readInputStream(p.getErrorStream()));131}132borderShift = Integer.parseInt(readInputStream(p.getInputStream()).trim());133isFrameBorderCalculated = true;134} catch (IOException e) {135e.printStackTrace();136throw new RuntimeException("Problem calculating a native border size");137}138}139return borderShift;140}141142public void getVerifyColor() {143try {144final int size = 200;145final Point[] p = new Point[1];146SwingUtilities.invokeAndWait(new Runnable() {147public void run(){148JFrame frame = new JFrame("set back");149frame.getContentPane().setBackground(AWT_BACKGROUND_COLOR);150frame.setSize(size, size);151frame.setUndecorated(true);152frame.setVisible(true);153frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);154p[0] = frame.getLocation();155}156});157Robot robot = new Robot();158robot.waitForIdle();159Thread.sleep(ROBOT_DELAY);160AWT_VERIFY_COLOR = robot.getPixelColor(p[0].x+size/2, p[0].y+size/2);161System.out.println("Color will be compared with " + AWT_VERIFY_COLOR + " instead of " + AWT_BACKGROUND_COLOR);162} catch (Exception e) {163System.err.println("Cannot get verify color: "+e.getMessage());164}165}166167private String readInputStream(InputStream is) throws IOException {168byte[] buffer = new byte[4096];169int len = 0;170StringBuilder sb = new StringBuilder();171try (InputStreamReader isr = new InputStreamReader(is)) {172while ((len = is.read(buffer)) > 0) {173sb.append(new String(buffer, 0, len));174}175}176return sb.toString();177}178179private void setupControl(final Component control) {180if (useClickValidation) {181control.addMouseListener(new MouseAdapter() {182@Override183public void mouseClicked(MouseEvent e) {184System.err.println("ERROR: " + control.getClass() + " received mouse click.");185wasHWClicked = true;186}187});188}189control.setBackground(AWT_BACKGROUND_COLOR);190control.setForeground(AWT_BACKGROUND_COLOR);191control.setPreferredSize(new Dimension(150, 150));192control.setFocusable(false);193}194195private void addAwtControl(java.util.List<Component> container, final Component control) {196String simpleName = control.getClass().getSimpleName();197if (onlyClassName != null && !simpleName.equals(onlyClassName)) {198return;199}200if (skipClassNames != null) {201for (String skipMe : skipClassNames) {202if (simpleName.equals(skipMe)) {203return;204}205}206}207setupControl(control);208container.add(control);209}210211private void addSimpleAwtControl(java.util.List<Component> container, String className) {212try {213Class definition = Class.forName("java.awt." + className);214Constructor constructor = definition.getConstructor(new Class[]{String.class});215java.awt.Component component = (java.awt.Component) constructor.newInstance(new Object[]{"AWT Component " + className});216addAwtControl(container, component);217} catch (Exception ex) {218System.err.println(ex.getMessage());219fail("Setup error, this jdk doesn't have awt conrol " + className);220}221}222223/**224* Adds current AWT control to container225* <p>N.B.: if testEmbeddedFrame == true this method will also add EmbeddedFrame over Canvas226* and it should be called <b>after</b> Frame.setVisible(true) call227* @param container container to hold AWT component228*/229protected final void propagateAWTControls(Container container) {230if (currentAwtControl != null) {231container.add(currentAwtControl);232} else { // embedded frame233try {234235//create embedder236Canvas embedder = new Canvas();237embedder.setBackground(Color.RED);238embedder.setPreferredSize(new Dimension(150, 150));239container.add(embedder);240container.setVisible(true); // create peer241242long frameWindow = 0;243String getWindowMethodName = null;244String eframeClassName = null;245if (Toolkit.getDefaultToolkit().getClass().getName().contains("XToolkit")) {246java.awt.Helper.addExports("sun.awt.X11", OverlappingTestBase.class.getModule());247getWindowMethodName = "getWindow";248eframeClassName = "sun.awt.X11.XEmbeddedFrame";249}else if (Toolkit.getDefaultToolkit().getClass().getName().contains(".WToolkit")) {250java.awt.Helper.addExports("sun.awt.windows", OverlappingTestBase.class.getModule());251getWindowMethodName = "getHWnd";252eframeClassName = "sun.awt.windows.WEmbeddedFrame";253}else if (isMac) {254java.awt.Helper.addExports("sun.lwawt", OverlappingTestBase.class.getModule());255java.awt.Helper.addExports("sun.lwawt.macosx", OverlappingTestBase.class.getModule());256eframeClassName = "sun.lwawt.macosx.CViewEmbeddedFrame";257}258259ComponentPeer peer = AWTAccessor.getComponentAccessor()260.getPeer(embedder);261if (!isMac) {262Method getWindowMethod = peer.getClass().getMethod(getWindowMethodName);263frameWindow = (Long) getWindowMethod.invoke(peer);264} else {265Method m_getPlatformWindowMethod = peer.getClass().getMethod("getPlatformWindow");266Object platformWindow = m_getPlatformWindowMethod.invoke(peer);267Class classPlatformWindow = Class.forName("sun.lwawt.macosx.CPlatformWindow");268269Method m_getContentView = classPlatformWindow.getMethod("getContentView");270Object contentView = m_getContentView.invoke(platformWindow);271Class classContentView = Class.forName("sun.lwawt.macosx.CPlatformView");272273Method m_getAWTView = classContentView.getMethod("getAWTView");274frameWindow = (Long) m_getAWTView.invoke(contentView);275}276277Class eframeClass = Class.forName(eframeClassName);278Constructor eframeCtor = eframeClass.getConstructor(long.class);279EmbeddedFrame eframe = (EmbeddedFrame) eframeCtor.newInstance(frameWindow);280setupControl(eframe);281eframe.setSize(new Dimension(150, 150));282eframe.setVisible(true);283// System.err.println(eframe.getSize());284} catch (Exception ex) {285ex.printStackTrace();286fail("Failed to instantiate EmbeddedFrame: " + ex.getMessage());287}288}289}290private static final Font hugeFont = new Font("Arial", Font.BOLD, 70);291292private java.util.List<Component> getAWTControls() {293java.util.List<Component> components = new ArrayList<Component>();294295for (String clazz : simpleAwtControls) {296addSimpleAwtControl(components, clazz);297}298299TextField tf = new TextField();300tf.setFont(hugeFont);301addAwtControl(components, tf);302303// more complex controls304Choice c = new Choice();305for (int i = 0; i < petStrings.length; i++) {306c.add(petStrings[i]);307}308addAwtControl(components, c);309c.setPreferredSize(null);310c.setFont(hugeFont); // to make control bigger as setPrefferedSize don't do his job here311312List l = new List(petStrings.length);313for (int i = 0; i < petStrings.length; i++) {314l.add(petStrings[i]);315}316addAwtControl(components, l);317318Canvas canvas = new Canvas();319canvas.setSize(100, 200);320addAwtControl(components, canvas);321322Scrollbar sb = new Scrollbar(Scrollbar.VERTICAL, 500, 1, 0, 500);323addAwtControl(components, sb);324325Scrollbar sb2 = new Scrollbar(Scrollbar.HORIZONTAL, 500, 1, 0, 500);326addAwtControl(components, sb2);327328return components;329}330/**331* Default shift for {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point) }332*/333protected static Point shift = new Point(16, 16);334335/**336* Verifies point using specified AWT Robot. Supposes <code>defaultShift == true</code> for {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean) }.337* This method is used to verify controls by providing just their plain screen coordinates.338* @param robot AWT Robot. Usually created by {@link Util#createRobot() }339* @param lLoc point to verify340* @see OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean)341*/342protected void clickAndBlink(Robot robot, Point lLoc) {343clickAndBlink(robot, lLoc, true);344}345/**346* Default failure message for color check347* @see OverlappingTestBase#performTest()348*/349protected String failMessageColorCheck = "The LW component did not pass pixel color check and is overlapped";350/**351* Default failure message event check352* @see OverlappingTestBase#performTest()353*/354protected String failMessage = "The LW component did not received the click.";355356private static boolean isValidForPixelCheck(Component component) {357if ((component instanceof java.awt.Scrollbar) || isMac && (component instanceof java.awt.Button)) {358return false;359}360return true;361}362363/**364* Preliminary validation - should be run <b>before</b> overlapping happens to ensure test is correct.365* @param robot AWT Robot. Usually created by {@link Util#createRobot() }366* @param lLoc point to validate to be <b>of</b> {@link OverlappingTestBase#AWT_BACKGROUND_COLOR}367* @param component tested component, should be pointed out as not all components are valid for pixel check.368*/369protected void pixelPreCheck(Robot robot, Point lLoc, Component component) {370if (isValidForPixelCheck(component)) {371int tries = 10;372Color c = null;373while (tries-- > 0) {374c = robot.getPixelColor(lLoc.x, lLoc.y);375System.out.println("Precheck. color: "+c+" compare with "+AWT_VERIFY_COLOR);376if (c.equals(AWT_VERIFY_COLOR)) {377return;378}379try {380Thread.sleep(100);381} catch (InterruptedException e) {382}383}384System.err.println(lLoc + ": " + c);385fail("Dropdown test setup failure, colored part of AWT component is not located at click area");386}387}388389/**390* Verifies point using specified AWT Robot.391* <p>Firstly, verifies point by color pixel check392* <p>Secondly, verifies event delivery by mouse click393* @param robot AWT Robot. Usually created by {@link Util#createRobot() }394* @param lLoc point to verify395* @param defaultShift if true verified position will be shifted by {@link OverlappingTestBase#shift }.396*/397protected void clickAndBlink(Robot robot, Point lLoc, boolean defaultShift) {398Point loc = lLoc.getLocation();399//check color400Util.waitForIdle(robot);401try{402Thread.sleep(500);403}catch(Exception exx){404exx.printStackTrace();405}406407if (defaultShift) {408loc.translate(shift.x, shift.y);409}410if (!(System.getProperty("os.name").toLowerCase().contains("os x"))) {411Color c = robot.getPixelColor(loc.x, loc.y);412System.out.println("C&B. color: "+c+" compare with "+AWT_VERIFY_COLOR);413if (c.equals(AWT_VERIFY_COLOR)) {414fail(failMessageColorCheck);415passed = false;416}417418// perform click419Util.waitForIdle(robot);420}421422robot.mouseMove(loc.x, loc.y);423424robot.mousePress(InputEvent.BUTTON1_MASK);425robot.mouseRelease(InputEvent.BUTTON1_MASK);426Util.waitForIdle(robot);427}428429/**430* This method should be overriden with code which setups UI for testing.431* Code in this method <b>will</b> be called only from AWT thread so Swing operations can be called directly.432*433* @see {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) } for instructions about adding tested AWT control to UI434*/435protected abstract void prepareControls();436437/**438* This method should be overriden with test execution. It will <b>not</b> be called from AWT thread so all Swing operations should be treated accordingly.439* @return true if test passed. Otherwise fail with default fail message.440* @see {@link OverlappingTestBase#failMessage} default fail message441*/442protected abstract boolean performTest();443/**444* This method can be overriden with cleanup routines. It will be called from AWT thread so all Swing operations should be treated accordingly.445*/446protected void cleanup() {447// intentionally do nothing448}449/**450* Currect tested AWT Control. Usually shouldn't be accessed directly.451*452* @see {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) } for instructions about adding tested AWT control to UI453*/454protected Component currentAwtControl;455456private void testComponent(Component component) throws InterruptedException, InvocationTargetException {457Robot robot = null;458try {459robot = new Robot();460}catch(Exception ignorex) {461}462currentAwtControl = component;463System.out.println("Testing " + currentAwtControl.getClass().getSimpleName());464SwingUtilities.invokeAndWait(new Runnable() {465public void run() {466prepareControls();467}468});469if (component != null) {470Util.waitTillShown(component);471}472Util.waitForIdle(robot);473try {474Thread.sleep(500); // wait for graphic effects on systems like Win7475} catch (InterruptedException ex) {476}477if (!instance.performTest()) {478fail(failMessage);479passed = false;480}481SwingUtilities.invokeAndWait(new Runnable() {482public void run() {483cleanup();484}485});486}487488private void testEmbeddedFrame() throws InvocationTargetException, InterruptedException {489Robot robot = null;490try {491robot = new Robot();492}catch(Exception ignorex) {493}494System.out.println("Testing EmbeddedFrame");495currentAwtControl = null;496SwingUtilities.invokeAndWait(new Runnable() {497public void run() {498prepareControls();499}500});501Util.waitForIdle(robot);502try {503Thread.sleep(500); // wait for graphic effects on systems like Win7504} catch (InterruptedException ex) {505}506if (!instance.performTest()) {507fail(failMessage);508passed = false;509}510SwingUtilities.invokeAndWait(new Runnable() {511public void run() {512cleanup();513}514});515}516517private void testAwtControls() throws InterruptedException {518try {519for (Component component : getAWTControls()) {520testComponent(component);521}522if (testEmbeddedFrame && !skipTestingEmbeddedFrame) {523testEmbeddedFrame();524}525} catch (InvocationTargetException ex) {526ex.printStackTrace();527fail(ex.getMessage());528}529}530/**531* Used by standard test machinery. See usage at {@link OverlappingTestBase }532*/533protected static OverlappingTestBase instance;534535protected OverlappingTestBase() {536getVerifyColor();537}538539/*****************************************************540* Standard Test Machinery Section541* DO NOT modify anything in this section -- it's a542* standard chunk of code which has all of the543* synchronisation necessary for the test harness.544* By keeping it the same in all tests, it is easier545* to read and understand someone else's test, as546* well as insuring that all tests behave correctly547* with the test harness.548* There is a section following this for test-549* classes550******************************************************/551private static void init() throws InterruptedException {552//System.setProperty("sun.awt.disableMixing", "true");553554instance.testAwtControls();555556if (wasHWClicked) {557fail("HW component received the click.");558passed = false;559}560if (passed) {561pass();562}563}//End init()564private static boolean theTestPassed = false;565private static boolean testGeneratedInterrupt = false;566private static String failureMessage = "";567private static Thread mainThread = null;568private static int sleepTime = 300000;569570// Not sure about what happens if multiple of this test are571// instantiated in the same VM. Being static (and using572// static vars), it aint gonna work. Not worrying about573// it for now.574/**575* Starting point for test runs. See usage at {@link OverlappingTestBase }576* @param args regular main args, not used.577* @throws InterruptedException578*/579public static void doMain(String args[]) throws InterruptedException {580mainThread = Thread.currentThread();581try {582init();583} catch (TestPassedException e) {584//The test passed, so just return from main and harness will585// interepret this return as a pass586return;587}588//At this point, neither test pass nor test fail has been589// called -- either would have thrown an exception and ended the590// test, so we know we have multiple threads.591592//Test involves other threads, so sleep and wait for them to593// called pass() or fail()594try {595Thread.sleep(sleepTime);596//Timed out, so fail the test597throw new RuntimeException("Timed out after " + sleepTime / 1000 + " seconds");598} catch (InterruptedException e) {599//The test harness may have interrupted the test. If so, rethrow the exception600// so that the harness gets it and deals with it.601if (!testGeneratedInterrupt) {602throw e;603}604605//reset flag in case hit this code more than once for some reason (just safety)606testGeneratedInterrupt = false;607608if (theTestPassed == false) {609throw new RuntimeException(failureMessage);610}611}612613}//main614615/**616* Test will fail if not passed after this timeout. Default timeout is 300 seconds.617* @param seconds timeout in seconds618*/619public static synchronized void setTimeoutTo(int seconds) {620sleepTime = seconds * 1000;621}622623/**624* Set test as passed. Usually shoudn't be called directly.625*/626public static synchronized void pass() {627System.out.println("The test passed.");628System.out.println("The test is over, hit Ctl-C to stop Java VM");629//first check if this is executing in main thread630if (mainThread == Thread.currentThread()) {631//Still in the main thread, so set the flag just for kicks,632// and throw a test passed exception which will be caught633// and end the test.634theTestPassed = true;635throw new TestPassedException();636}637theTestPassed = true;638testGeneratedInterrupt = true;639mainThread.interrupt();640}//pass()641642/**643* Fail test generic message.644*/645public static synchronized void fail() {646//test writer didn't specify why test failed, so give generic647fail("it just plain failed! :-)");648}649650/**651* Fail test providing specific reason.652* @param whyFailed reason653*/654public static synchronized void fail(String whyFailed) {655System.out.println("The test failed: " + whyFailed);656System.out.println("The test is over, hit Ctl-C to stop Java VM");657//check if this called from main thread658if (mainThread == Thread.currentThread()) {659//If main thread, fail now 'cause not sleeping660throw new RuntimeException(whyFailed);661}662theTestPassed = false;663testGeneratedInterrupt = true;664failureMessage = whyFailed;665mainThread.interrupt();666}//fail()667}// class LWComboBox668class TestPassedException extends RuntimeException {669}670671672