All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vaadin.testbench.screenshot.ScreenShotFailureReporter Maven / Gradle / Ivy

/**
 * Copyright (C) 2000-2022 Vaadin Ltd
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See  for the full
 * license.
 */
package com.vaadin.testbench.screenshot;

import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ScreenShotFailureReporter {
    private final BufferedImage referenceImage;
    private final boolean[][] falseBlocks;
    private final int xBlocks;
    private final int yBlocks;

    public ScreenShotFailureReporter(BufferedImage referenceImage,
            boolean[][] falseBlocks) {
        this.referenceImage = referenceImage;
        this.falseBlocks = falseBlocks;
        xBlocks = ImageComparisonUtil.getNrBlocks(referenceImage.getWidth());
        yBlocks = ImageComparisonUtil.getNrBlocks(referenceImage.getHeight());
    }

    public void createErrorImageAndHTML(String fileName,
            BufferedImage screenshotImage) {
        try {
            // Write the screenshot into the error directory
            ImageIO.write(screenshotImage, "png",
                    ImageFileUtil.getErrorScreenshotFile(fileName));
        } catch (IOException e) {
            getLogger().error("Error writing screenshot to "
                    + ImageFileUtil.getErrorScreenshotFile(fileName).getPath(),
                    e);
        }

        // collect big error blocks of differences
        List errorAreas = collectErrorsToList(xBlocks, yBlocks);

        // Draw boxes around blocks that differ
        drawErrorsToImage(errorAreas, screenshotImage);

        createDiffHtml(errorAreas, fileName, screenshotImage, referenceImage);
    }

    private Logger getLogger() {
        return LoggerFactory.getLogger(getClass());
    }

    /**
     * Runs through the marked false macroblocks and collects them to bigger
     * blocks
     *
     * @param xBlocks
     *            Amount of macroblocks in x direction
     * @param yBlocks
     *            Amount of macroblocks in y direction
     * @return List of ErrorBlocks
     */
    private List collectErrorsToList(int xBlocks, int yBlocks) {
        List errorAreas = new LinkedList<>();

        // run through blocks for marked errors for macroblocks.
        for (int y = 0; y < yBlocks; y++) {
            for (int x = 0; x < xBlocks; x++) {
                // if found error make new ErrorBlock and collect
                // connected error blocks and mark them false so
                // that they won't trigger new errors
                if (falseBlocks[x][y]) {
                    ErrorBlock newBlock = new ErrorBlock();
                    newBlock.setX(x * 16);
                    newBlock.setY(y * 16);
                    int x1 = x, xmin = x, y1 = y, maxSteps = xBlocks * yBlocks,
                            steps = 0;
                    falseBlocks[x][y] = false;

                    // This'll confirm logic errors.
                    while (true) {
                        x1++;

                        // if x1 out of bounds set x1 to xmin where
                        // xmin == smallest error block found for
                        // this error
                        if (x1 >= xBlocks) {
                            x1 = xmin;
                        }

                        // if x1,y1 marked true add width to ErrorBlock
                        if (falseBlocks[x1][y1]) {
                            newBlock.addXBlock();
                            falseBlocks[x1][y1] = false;
                        } else if (y1 < yBlocks) {
                            x1 = xmin;

                            // If next row has a false block
                            // connected to our block
                            boolean foundConnectedBlock = false;
                            for (int foundX = x1; foundX < x1
                                    + newBlock.getXBlocks(); foundX++) {
                                if (foundX == xBlocks || y1 + 1 == yBlocks) {
                                    break;
                                }

                                if (falseBlocks[foundX][y1 + 1]) {
                                    foundConnectedBlock = true;
                                }
                            }

                            // If connected error to ErrorBlock add
                            // height to error block
                            if (foundConnectedBlock) {
                                y1++;
                                newBlock.addYBlock();

                                // while stepping back on this
                                // row is false change block x
                                // position
                                if (x1 - 1 >= 0) {
                                    while (falseBlocks[x1 - 1][y1]) {
                                        falseBlocks[x1 - 1][y1] = false;
                                        newBlock.addXBlock();
                                        x1 = x1 - 1;
                                        newBlock.setX(newBlock.getX() - 16);
                                        if (x1 == 0) {
                                            break;
                                        }
                                    }
                                    xmin = x1;
                                }

                                // Skip blocks inside main error
                                // block for this error
                                x1 = x1 + newBlock.getXBlocks() - 1;
                            } else {
                                x1 = newBlock.getX() / 16;
                                y1 = newBlock.getY() / 16;
                                // Set all blocks to false
                                // inside found box
                                for (int j = 0; j < newBlock
                                        .getYBlocks(); j++) {
                                    for (int i = 0; i < newBlock
                                            .getXBlocks(); i++) {
                                        if (x1 + i < xBlocks
                                                && y1 + j < yBlocks) {
                                            falseBlocks[x1 + i][y1 + j] = false;
                                        }
                                    }
                                }
                                break;

                            }
                        }
                        // In case something goes wrong we won't get stuck in
                        // the loop forever
                        if (++steps == maxSteps) {
                            break;
                        }
                    }
                    errorAreas.add(newBlock);
                }
            }
        }
        return errorAreas;
    }

    private void drawErrorsToImage(List errorAreas,
            BufferedImage screenshotImage) {
        // Draw lines around false ErrorBlocks before saving _diff
        // file.
        Graphics2D drawToPicture = screenshotImage.createGraphics();
        drawToPicture.setColor(Color.MAGENTA);

        int width = screenshotImage.getWidth();
        int height = screenshotImage.getHeight();

        for (ErrorBlock error : errorAreas) {
            int offsetX = 0, offsetY = 0;
            if (error.getX() > 0) {
                offsetX = 1;
            }
            if (error.getY() > 0) {
                offsetY = 1;
            }
            int toX = error.getXBlocks() * 16 + offsetX;
            int toY = error.getYBlocks() * 16 + offsetY;
            // Draw lines inside canvas
            if ((error.getX() + (error.getXBlocks() * 16) + offsetX) > width) {
                toX = width - error.getX();
            }
            if ((error.getY() + (error.getYBlocks() * 16) + offsetY) > height) {
                toY = height - error.getY();
            }

            // draw error to image
            drawToPicture.drawRect(error.getX() - offsetX,
                    error.getY() - offsetY, toX, toY);

        }
        // release resources
        drawToPicture.dispose();
    }

    /**
     * Build a small html file that has mouse over picture change for fast
     * checking of errors and click on picture to switch between reference and
     * diff pictures.
     *
     * @param blocks
     *            List of ErrorBlock
     * @param fileId
     *            fileName for html file
     */
    private void createDiffHtml(List blocks, String fileId,
            BufferedImage screenshotImage, BufferedImage referenceImage) {
        String image = ImageUtil.encodeImageToBase64(screenshotImage);
        String ref_image = ImageUtil.encodeImageToBase64(referenceImage);
        try {
            PrintWriter writer = new PrintWriter(
                    ImageFileUtil.getErrorScreenshotFile(fileId + ".html"));
            // Write head
            writer.println("");
            writer.println("");
            writer.println(
                    "");
            writer.println("");
            writer.println(
                    "");

            writer.println(
                    "
Image for this run
"); writer.println( "
"); int add = 0; for (ErrorBlock error : blocks) { int offsetX = 0, offsetY = 0; if (error.getX() > 0) { offsetX = 1; } if (error.getY() > 0) { offsetY = 1; } String id = "popUpDiv_" + (error.getX() + add) + "_" + (error.getY() + add); // position stars so that it's not out of screen. writer.println("
"); // Start "popup" div writer.println( "
"); writer.println(""); // End popup div writer.println("
"); add++; } // End file writer.println(""); writer.flush(); writer.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy