Visual regression testing

This commit is contained in:
Bane Stojkovic
2022-03-03 09:42:31 +01:00
parent 2cbaaa4a7d
commit d376ec9278
10 changed files with 123 additions and 66 deletions
Binary file not shown.
+1 -1
View File
@@ -21,6 +21,6 @@
<classpathentry combineaccessrules="false" kind="src" path="/diylc-core"/> <classpathentry combineaccessrules="false" kind="src" path="/diylc-core"/>
<classpathentry kind="lib" path="lib/java-http-proxy.jar"/> <classpathentry kind="lib" path="lib/java-http-proxy.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="library/main.jar"/> <classpathentry kind="lib" path="library/main.jar" sourcepath="/diylc-library"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>
@@ -9,6 +9,6 @@
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE" value="true"/> <booleanAttribute key="org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.diylc.RegressionTestRunner"/> <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.diylc.RegressionTestRunner"/>
<stringAttribute key="org.eclipse.jdt.launching.MODULE_NAME" value="diylc-swing"/> <stringAttribute key="org.eclipse.jdt.launching.MODULE_NAME" value="diylc-swing"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="&quot;E:\Bane\Dev\DIYLC\regression&quot; TEST"/> <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="&quot;C:\Users\bancika\git\diy-layout-creator\diylc-regression-data&quot; TEST user"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="diylc-swing"/> <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="diylc-swing"/>
</launchConfiguration> </launchConfiguration>
Binary file not shown.
Binary file not shown.
@@ -107,11 +107,6 @@ public class ImageComparison {
*/ */
private boolean drawExcludedRectangles = false; private boolean drawExcludedRectangles = false;
/**
* The difference in percent between two images.
*/
private float differencePercent;
/** /**
* Flag for filling comparison difference rectangles. * Flag for filling comparison difference rectangles.
*/ */
@@ -5,6 +5,8 @@ package com.github.romankh3.image.comparison.exception;
*/ */
public final class ImageComparisonException extends RuntimeException { public final class ImageComparisonException extends RuntimeException {
private static final long serialVersionUID = 1L;
/** /**
* Constructs a new {@link ImageComparisonException} with the specified detail message. * Constructs a new {@link ImageComparisonException} with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a call to * The cause is not initialized, and may subsequently be initialized by a call to
@@ -5,6 +5,8 @@ package com.github.romankh3.image.comparison.exception;
*/ */
public class ImageNotFoundException extends RuntimeException { public class ImageNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
/** /**
* Constructs a new {@link ImageNotFoundException} with the specified detail message. * Constructs a new {@link ImageNotFoundException} with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a call to * The cause is not initialized, and may subsequently be initialized by a call to
@@ -2,6 +2,12 @@ package org.diylc;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.diylc.appframework.miscutils.ConfigurationManager; import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.appframework.miscutils.InMemoryConfigurationManager; import org.diylc.appframework.miscutils.InMemoryConfigurationManager;
import org.diylc.core.IView; import org.diylc.core.IView;
@@ -20,81 +26,133 @@ public class RegressionTestRunner {
System.out.println("No path and command provided"); System.out.println("No path and command provided");
return; return;
} }
ConfigurationManager.getInstance().initialize("diylc-test"); ConfigurationManager.getInstance().initialize("diylc-test");
String basePath = args[0]; String basePath = args[0];
String command = args[1]; String command = args[1];
String filter = null;
if (args.length > 2) {
filter = args[2];
}
System.out.println("Running command " + command + " in: " + basePath); System.out.println("Running command " + command + " in: " + basePath);
File inputsDir = new File(basePath + File.separator + "input" + File.separator + "diy"); File inputsDir = new File(basePath + File.separator + "input");
if (!inputsDir.exists()) { List<Boolean> collect =
System.out.println("Could not find the input directory: " + inputsDir.getAbsolutePath()); visit(inputsDir, basePath, command, filter).collect(Collectors.toList());
return;
} long okCount = collect.stream().filter(x -> x).count();
File[] files = inputsDir.listFiles(); long failCount = collect.size() - okCount;
int okCount = 0;
int failCount = 0;
for (File file : files) {
boolean fileOk = processFile(file, basePath, command);
if (fileOk) {
okCount++;
} else {
failCount++;
}
}
System.out.println("Finished! OK files: " + okCount + "; Failed files: " + failCount); System.out.println("Finished! OK files: " + okCount + "; Failed files: " + failCount);
} }
private static boolean processFile(File file, String basePath, String command) { private static Stream<Boolean> visit(File inputsDir, String basePath, String command,
System.out.print("Processing file: " + file.getName() + "..."); String filter) {
File[] files = inputsDir.listFiles();
return Arrays.stream(files)
// .filter(x -> x.getAbsolutePath().contains("405"))
.parallel()
.flatMap(file -> {
if (file.isDirectory()) {
return visit(file, basePath, command, filter);
} else {
if (!file.getName().endsWith(".diy")) {
return Stream.empty();
}
if (filter != null) {
Pattern pattern = Pattern.compile(filter, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(file.getAbsolutePath());
boolean matchFound = matcher.find();
if (!matchFound) {
return Stream.empty();
}
}
return Stream.of(processFile(file, command));
}
});
}
private static boolean processFile(File file, String command) {
String prefix = "File: " + file.getName() + " status: ";
try { try {
IView view = new MockView(); IView view = new MockView();
Presenter presenter = new Presenter(view, InMemoryConfigurationManager.getInstance()); Presenter presenter = new Presenter(view, InMemoryConfigurationManager.getInstance());
ProjectDrawingProvider drawingProvider = new ProjectDrawingProvider(presenter, false, true, false); ProjectDrawingProvider drawingProvider =
new ProjectDrawingProvider(presenter, false, true, false);
presenter.loadProjectFromFile(file.getAbsolutePath()); presenter.loadProjectFromFile(file.getAbsolutePath());
if ("PREPARE".equalsIgnoreCase(command)) { if ("PREPARE".equalsIgnoreCase(command)) {
// generate PNG input image for comparison // generate PNG input image for comparison
File pngFile = new File(basePath + File.separator + "input" + File.separator + "png" + File.separator + (file.getName().replace(".diy", ".png"))); prepareInputs(file, drawingProvider);
if (!pngFile.exists()) { System.out.println(prefix + "DONE");
DrawingExporter.getInstance().exportPNG(drawingProvider, pngFile); return true;
}
} else if ("TEST".equalsIgnoreCase(command)) { } else if ("TEST".equalsIgnoreCase(command)) {
// test save return testOutputs(file, prefix, presenter, drawingProvider);
File outputFile = new File(basePath + File.separator + "output" + File.separator + "diy" + File.separator + file.getName());
if (outputFile.exists()) {
outputFile.delete();
}
presenter.saveProjectToFile(outputFile.getAbsolutePath(), false);
// test export png
File pngOutputFile = new File(basePath + File.separator + "output" + File.separator + "png" + File.separator + (file.getName().replace(".diy", ".png")));
if (pngOutputFile.exists()) {
pngOutputFile.delete();
}
DrawingExporter.getInstance().exportPNG(drawingProvider, pngOutputFile);
File pngInputFile = new File(basePath + File.separator + "input" + File.separator + "png" + File.separator + (file.getName().replace(".diy", ".png")));
if (!pngInputFile.exists()) {
System.out.println("Input image does not exist!");
return false;
}
BufferedImage expectedImage = ImageComparisonUtil.readImageFromResources(pngInputFile.getAbsolutePath());
BufferedImage actualImage = ImageComparisonUtil.readImageFromResources(pngOutputFile.getAbsolutePath());
//Create ImageComparison object and compare the images.
ImageComparisonResult imageComparisonResult = new ImageComparison(expectedImage, actualImage).compareImages();
//Check the result
if (ImageComparisonState.MATCH != imageComparisonResult.getImageComparisonState()) {
System.out.println("Images do not match!");
return false;
}
} }
System.out.println("OK"); return false;
return true;
} catch (Exception e) { } catch (Exception e) {
System.out.println("ERROR: " + e.getMessage()); System.out.println(prefix + "ERROR: " + e.getMessage());
return false; return false;
} }
} }
private static boolean testOutputs(File file, String prefix, Presenter presenter,
ProjectDrawingProvider drawingProvider) {
File baseDir = file.getParentFile().getParentFile().getParentFile().getParentFile();
File outputDir = new File(baseDir.getAbsolutePath() + File.separator + "output" + File.separator +
file.getParentFile().getParentFile().getName());
File inputDir = file.getParentFile().getParentFile();
if (!outputDir.exists()) {
outputDir.mkdirs();
}
// test save
File outputFile = new File(outputDir.getAbsolutePath() + File.separator + "diy" + File.separator + file.getName());
outputFile.getParentFile().mkdirs();
if (outputFile.exists()) {
outputFile.delete();
}
presenter.saveProjectToFile(outputFile.getAbsolutePath(), false);
// test export png
File pngOutputFile = new File(outputDir.getAbsolutePath() + File.separator + "png" + File.separator +
file.getName().replace(".diy", ".png"));
pngOutputFile.getParentFile().mkdirs();
if (pngOutputFile.exists()) {
pngOutputFile.delete();
}
DrawingExporter.getInstance().exportPNG(drawingProvider, pngOutputFile);
File pngInputFile = new File(inputDir.getAbsolutePath() + File.separator + "png" + File.separator + (file.getName().replace(".diy", ".png")));
if (!pngInputFile.exists()) {
System.out.println(prefix + "Input image does not exist!");
return false;
}
BufferedImage expectedImage =
ImageComparisonUtil.readImageFromResources(pngInputFile.getAbsolutePath());
BufferedImage actualImage =
ImageComparisonUtil.readImageFromResources(pngOutputFile.getAbsolutePath());
File pngDiffFile = new File(outputDir.getAbsolutePath() + File.separator + "diff" + File.separator +
file.getName().replace(".diy", ".png"));
pngDiffFile.getParentFile().mkdirs();
ImageComparisonResult imageComparisonResult =
new ImageComparison(expectedImage, actualImage, pngDiffFile).compareImages();
if (ImageComparisonState.MATCH != imageComparisonResult.getImageComparisonState()) {
System.out.println(prefix + "Images do not match!");
return false;
}
System.out.println(prefix + "OK");
return true;
}
private static void prepareInputs(File file, ProjectDrawingProvider drawingProvider) {
File pngDir = new File(file.getParentFile().getParentFile().getAbsolutePath() + File.separator + "png");
File pngFile =
new File(pngDir.getAbsolutePath() + File.separator + file.getName().replace(".diy", ".png"));
pngFile.getParentFile().mkdirs();
if (!pngFile.exists()) {
DrawingExporter.getInstance().exportPNG(drawingProvider, pngFile);
}
}
} }
Binary file not shown.