< prev index next >

tools/SharedTestUtilsOpen/src/test/javaclient/shared/screenshots/ScreenshotUtils.java

Print this page
rev 320 : 8151500: [TEST] Implement multiple golden image support
Summary: Makes possible using any number of golden images.
   1 /*
   2  * Copyright (c) 2009, 2012, 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. Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  */
  24 package test.javaclient.shared.screenshots;
  25 
  26 import java.io.File;
  27 import java.util.ArrayList;
  28 import java.util.LinkedList;
  29 import java.util.List;
  30 import javafx.scene.Node;
  31 import javafx.scene.Scene;
  32 import javafx.scene.layout.Pane;
  33 import javafx.stage.Stage;
  34 import org.jemmy.Rectangle;
  35 import org.jemmy.TimeoutExpiredException;
  36 import org.jemmy.action.GetAction;
  37 import org.jemmy.control.Wrap;
  38 import org.jemmy.env.Environment;
  39 import org.jemmy.fx.ByWindowType;
  40 import org.jemmy.fx.NodeDock;
  41 import org.jemmy.fx.Root;
  42 import org.jemmy.image.Image;

  43 import org.jemmy.interfaces.Parent;
  44 import org.jemmy.timing.State;
  45 import org.junit.Assert;
  46 import test.javaclient.shared.AbstractTestableApplication;
  47 import test.javaclient.shared.JemmyUtils;
  48 import test.javaclient.shared.TestUtil;
  49 import test.javaclient.shared.description.FXSceneTreeBuilder;
  50 import test.javaclient.shared.description.FXSimpleNodeDescription;
  51 import test.javaclient.shared.description.TreeNode;
  52 
  53 /**
  54  * @author Andrey Glushchenko
  55  */
  56 public class ScreenshotUtils {
  57     //private static Wrap<? extends Scene> scene = null;

  58     private static AbstractTestableApplication application;
  59 /**
  60      * Verify or generate golden screenshot for a test depending on
  61      * <code>IS_GOLDEN_MODE</code> status.
  62      *
  63      * @param testClass
  64      * @param testName test name for a test
  65      * @param scene scene to take a screenshot of
  66      */
  67     public static void checkScreenshot(Class testClass, String testName, Wrap node) {
  68         checkScreenshot(testClass.getName() + "." + testName, node);
  69     }

  70     /**
  71      * Verify or generate golden screenshot for a test depending on
  72      * <code>IS_GOLDEN_MODE</code> status.
  73      *
  74      * @param testName test name for a test
  75      * @param scene scene to take a screenshot of
  76      */
  77     public static void checkScreenshot(String testName, Wrap node) {
  78         checkScreenshot(testName, node, null);
  79     }
  80 
  81     public static void checkScreenshot(String testName, Wrap node, int width, int height) {
  82         checkScreenshot(testName, node, new Rectangle(width, height));
  83     }
  84 
  85     public static void checkScreenshot(String testName, final Wrap node, Rectangle rect) {
  86         Image sceneImage;
  87         if (rect != null) {
  88             sceneImage = node.getScreenImage(rect);
  89         } else {
  90             sceneImage = node.getScreenImage();
  91         }
  92         String name = ImagesManager.getInstance().lookupGoldenScreenshot(testName);
  93         String descrName = ImagesManager.getInstance().getDescriptionPath(testName);
  94         Assert.assertNotNull("Invalid images path", name);
  95         if (TestUtil.IS_GOLDEN_MODE) {
  96             //TODO: specified directory
  97             sceneImage.save(ImagesManager.getInstance().getScreenshotPath(testName));
  98         } else {
  99             String diffName = ImagesManager.getInstance().getScreenshotPath(testName + "-diff");
 100             String resName = ImagesManager.getInstance().getScreenshotPath(testName);
 101             if (TestUtil.IS_DESCRIPTION_MODE) {
 102                 String descr_name = ImagesManager.getInstance().lookupGoldenDescription(testName);
 103                 if (new File(descr_name).exists()) {
 104                     try {
 105                         List<TreeNode<FXSimpleNodeDescription>> list = (List<TreeNode<FXSimpleNodeDescription>>) TestUtil.read(descr_name);
 106                         node.waitState(new State<List<TreeNode<FXSimpleNodeDescription>>>() {
 107                             public List<TreeNode<FXSimpleNodeDescription>> reached() {
 108                                 return FXSceneTreeBuilder.build(node);
 109                             }
 110 
 111                             @Override
 112                             public String toString() {
 113                                 return "Control having expected image description";
 114                             }
 115                         }, list);
 116                     } catch (TimeoutExpiredException e) {
 117                         if (diffName != null) {
 118                             node.getEnvironment().getOutput(Wrap.OUTPUT).println("Saving difference to " + diffName);
 119                             final Image diffImage = node.getScreenImage().compareTo(node.getEnvironment().getImageLoader().load(name));
 120                             if (diffImage != null) {
 121                                 diffImage.save(diffName);
 122                             }
 123                         }
 124                         throw e;
 125                     } finally {
 126                         if (resName != null) {
 127                             node.getEnvironment().getOutput(Wrap.OUTPUT).println("Saving result to " + resName);
 128                             node.getScreenImage().save(resName);
 129                         }
 130                     }
 131                 } else {
 132                     Assert.fail("Golden image description (" + descr_name + ") not found. Actual image is saved as " + descrName);
 133                     ArrayList<TreeNode<FXSimpleNodeDescription>> description = FXSceneTreeBuilder.build(node);
 134                     TestUtil.write(description, descrName);
 135                 }
 136             } else {
 137                 if (new File(name).exists()) {
 138                     try {
 139                         if (rect != null) {
 140                             node.waitImage(node.getEnvironment().getImageLoader().load(name), rect, resName, diffName);
 141                         } else {
 142                             node.waitImage(node.getEnvironment().getImageLoader().load(name), resName, diffName);
 143                         }


 144                     } catch (TimeoutExpiredException imagesAreDifferentException) {
 145                         //If images are really different, then not only diff and
 146                         //original images are to put in the results folder, but also golden image.
 147                         try {
 148                             String expectedName = ImagesManager.getInstance().getScreenshotPath(testName + "-expected");
 149                             node.getEnvironment().getImageLoader().load(name).save(expectedName);
 150                         } catch (Throwable ex) {
 151                             ex.printStackTrace();
 152                         }
 153                         throw imagesAreDifferentException;
 154                     }
 155                     if (TestUtil.IS_DESCRIBING_MODE) {
 156                         ArrayList<TreeNode<FXSimpleNodeDescription>> description = FXSceneTreeBuilder.build(node);
 157                         TestUtil.write(description, descrName);
 158                     }
 159                 } else {
 160                     sceneImage.save(resName);
 161                     Assert.fail("Golden image (" + name + ") not found. Actual image is saved as " + resName);
 162                 }


 163             }
 164         }
 165     }
 166     private static List<Throwable> screenshotErrors = new LinkedList<Throwable>();
 167 
 168     public static void setApplication(AbstractTestableApplication application) {
 169         ScreenshotUtils.application = application;
 170     }

 171     public static void setScene(Wrap<? extends Scene> scene) {
 172        // ScreenshotUtils.scene = scene;
 173     }
 174     
 175     private static void error(Throwable ex){
 176         screenshotErrors.add(ex);
 177         ex.printStackTrace();
 178     }
 179     /**
 180      * Set image comparator distance. Should be called from constructor or {}
 181      * class initialization block.
 182      *
 183      * @param comparatorDistance distance
 184      */
 185     public static void setComparatorDistance(float comparatorDistance) {
 186         JemmyUtils.comparatorDistance = comparatorDistance;
 187     }
 188     public static void throwScreenshotErrors(){

 189         StringBuilder sb = new StringBuilder();
 190         for(Throwable ex: screenshotErrors){
 191             sb.append(ex.toString()).append("\n");
 192         }
 193         screenshotErrors.clear();
 194         String msg = sb.toString();
 195         if(!"".equals(msg) && msg!=null){
 196             Assert.fail(msg);
 197         }
 198     }
 199 
 200     public static void checkPageContentScreenshot(String name) {
 201         checkPageContentScreenshot(name, false);
 202     }
 203 
 204     public static void checkPageContentScreenshot(String name, boolean valuable_rect) {
 205         try {
 206         if(application.getNodeForScreenshot()==null){
 207         final Wrap<? extends Scene> scene = Root.ROOT.lookup(new ByWindowType(Stage.class)).lookup(Scene.class).wrap(0);
 208 
 209             checkScreenshot(name, scene);
 210         }else{
 211             if (valuable_rect) {
 212                 checkScreenshot(name, getPageContent(), getPageContentSize());
 213             } else {
 214                 checkScreenshot(name, getPageContent());
 215             }
 216         }
 217         } catch (Throwable th) {
 218             error(th);
 219         }
 220     }

 221     public  static Wrap<? extends Node> getPageContent() {
 222         Node n = application.getNodeForScreenshot();
 223         final Wrap<? extends Scene> scene = Root.ROOT.lookup(new ByWindowType(Stage.class)).lookup(Scene.class).wrap(0);
 224         return new NodeDock(scene.as(Parent.class, Node.class), n.getId()).wrap();
 225     }

 226     /**
 227      *
 228      * @return rectangle contains all children of page content. This rectangle
 229      * may have different size then size of Content.
 230      */
 231     public static Rectangle getPageContentSize() {
 232         Node node = getPageContent().getControl();
 233         Rectangle rect = new Rectangle();
 234         if (node instanceof Pane) {
 235             Pane p = (Pane) node;
 236             for (Node n : p.getChildren()) {
 237                 rect.add((int) n.getBoundsInParent().getMaxX(), (int) n.getBoundsInParent().getMaxY());
 238             }
 239         } else {
 240             rect.add((int) node.getBoundsInParent().getMaxX(), (int) node.getBoundsInParent().getMaxY());
 241         }
 242         return rect;
 243     }
 244     
 245 }
   1 /*
   2  * Copyright (c) 2009, 2016, 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. Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  */
  24 package test.javaclient.shared.screenshots;
  25 
  26 import java.nio.file.Paths;

  27 import java.util.LinkedList;
  28 import java.util.List;
  29 import javafx.scene.Node;
  30 import javafx.scene.Scene;
  31 import javafx.scene.layout.Pane;
  32 import javafx.stage.Stage;
  33 import org.jemmy.Rectangle;
  34 import org.jemmy.TimeoutExpiredException;

  35 import org.jemmy.control.Wrap;

  36 import org.jemmy.fx.ByWindowType;
  37 import org.jemmy.fx.NodeDock;
  38 import org.jemmy.fx.Root;
  39 import org.jemmy.image.Image;
  40 import org.jemmy.image.ImageLoader;
  41 import org.jemmy.interfaces.Parent;

  42 import org.junit.Assert;
  43 import test.javaclient.shared.AbstractTestableApplication;
  44 import test.javaclient.shared.JemmyUtils;




  45 
  46 /**
  47  * @author Andrey Glushchenko, andrey.rusakov@oracle.com
  48  */
  49 public class ScreenshotUtils {
  50 
  51     private static final List<Throwable> SCREENSHOT_ERRORS = new LinkedList<>();
  52     private static AbstractTestableApplication application;
  53 
  54     /**
  55      * Verify or generate golden screenshot for a test.
  56      *
  57      * @param testClass
  58      * @param testName test name for a test
  59      * @param scene scene to take a screenshot of
  60      */
  61     public static void checkScreenshot(Class testClass, String testName, Wrap node) {
  62         checkScreenshot(testClass.getName() + "." + testName, node);
  63     }
  64 
  65     /**
  66      * Verify or generate golden screenshot for a test.

  67      *
  68      * @param testName test name for a test
  69      * @param scene scene to take a screenshot of
  70      */
  71     public static void checkScreenshot(String testName, Wrap node) {
  72         checkScreenshot(testName, node, null);
  73     }
  74 
  75     public static void checkScreenshot(String testName, Wrap node, int width, int height) {
  76         checkScreenshot(testName, node, new Rectangle(width, height));
  77     }
  78 
  79     public static void checkScreenshot(String testName, final Wrap node, Rectangle rect) {
  80         ImageLoader imgLoader = node.getEnvironment().getImageLoader();
  81         List<String> goldenImages = GoldenImageManager.getTestImages(testName, ".png");
  82         String resultPath = GoldenImageManager.getScreenshotPath(testName);
  83         if (goldenImages.isEmpty()) {
  84             Image sceneImage = (rect == null) ? node.getScreenImage() : node.getScreenImage(rect);
  85             sceneImage.save(resultPath);
  86             throw new RuntimeException("No golden images found for " + testName
  87                     + ", actual image saved to " + resultPath);
  88         }
  89         boolean nothingMatched = true;
  90         for (int i = 0; i < goldenImages.size(); i++) {
  91             String goldenPath = goldenImages.get(i);
  92             String goldenName = Paths.get(goldenPath).getFileName().toString()
  93                     .replaceFirst("\\.[^\\.]*$", String.format("-%02d", i));
  94             String diffPath = GoldenImageManager.getScreenshotPath(goldenName + "-diff");
  95             Image image = imgLoader.load(goldenPath);




































  96             try {
  97                 if (rect != null) {
  98                     node.waitImage(image, rect, resultPath, diffPath);
  99                 } else {
 100                     node.waitImage(image, resultPath, diffPath);
 101                 }
 102                 nothingMatched = false;
 103                 break;
 104             } catch (TimeoutExpiredException imagesAreDifferentException) {


 105                 try {
 106                     String expectedName = GoldenImageManager.getScreenshotPath(goldenName + "-expected");
 107                     imgLoader.load(goldenPath).save(expectedName);
 108                 } catch (Throwable ex) {
 109                     System.err.println(ex);
 110                 }

 111             }







 112         }
 113         if (nothingMatched) {
 114             throw new TimeoutExpiredException("Control having expected image has not been reached");
 115         }
 116     }


 117 
 118     public static void setApplication(AbstractTestableApplication application) {
 119         ScreenshotUtils.application = application;
 120     }
 121 
 122     public static void setScene(Wrap<? extends Scene> scene) {
 123         // ScreenshotUtils.scene = scene;
 124     }
 125 
 126     private static void error(Throwable ex) {
 127         SCREENSHOT_ERRORS.add(ex);
 128         ex.printStackTrace();
 129     }
 130 





 131     public static void setComparatorDistance(float comparatorDistance) {
 132         JemmyUtils.comparatorDistance = comparatorDistance;
 133     }
 134 
 135     public static void throwScreenshotErrors() {
 136         StringBuilder sb = new StringBuilder();
 137         for (Throwable ex : SCREENSHOT_ERRORS) {
 138             sb.append(ex.toString()).append("\n");
 139         }
 140         SCREENSHOT_ERRORS.clear();
 141         String msg = sb.toString();
 142         if (!"".equals(msg) && msg != null) {
 143             Assert.fail(msg);
 144         }
 145     }
 146 
 147     public static void checkPageContentScreenshot(String name) {
 148         checkPageContentScreenshot(name, false);
 149     }
 150 
 151     public static void checkPageContentScreenshot(String name, boolean valuable_rect) {
 152         try {
 153             if (application.getNodeForScreenshot() == null) {
 154                 final Wrap<? extends Scene> scene = Root.ROOT.lookup(new ByWindowType(Stage.class)).lookup(Scene.class).wrap(0);
 155 
 156                 checkScreenshot(name, scene);
 157             } else if (valuable_rect) {

 158                 checkScreenshot(name, getPageContent(), getPageContentSize());
 159             } else {
 160                 checkScreenshot(name, getPageContent());
 161             }

 162         } catch (Throwable th) {
 163             error(th);
 164         }
 165     }
 166 
 167     public static Wrap<? extends Node> getPageContent() {
 168         Node n = application.getNodeForScreenshot();
 169         final Wrap<? extends Scene> scene = Root.ROOT.lookup(new ByWindowType(Stage.class)).lookup(Scene.class).wrap(0);
 170         return new NodeDock(scene.as(Parent.class, Node.class), n.getId()).wrap();
 171     }
 172 
 173     /**
 174      *
 175      * @return rectangle contains all children of page content. This rectangle may have different
 176      * size then size of Content.
 177      */
 178     public static Rectangle getPageContentSize() {
 179         Node node = getPageContent().getControl();
 180         Rectangle rect = new Rectangle();
 181         if (node instanceof Pane) {
 182             Pane p = (Pane) node;
 183             for (Node n : p.getChildren()) {
 184                 rect.add((int) n.getBoundsInParent().getMaxX(), (int) n.getBoundsInParent().getMaxY());
 185             }
 186         } else {
 187             rect.add((int) node.getBoundsInParent().getMaxX(), (int) node.getBoundsInParent().getMaxY());
 188         }
 189         return rect;
 190     }
 191 
 192 }
< prev index next >