240 lines
9.2 KiB
Java
240 lines
9.2 KiB
Java
package jmri.jmrit.display.layoutEditor;
|
|
|
|
import java.io.*;
|
|
import java.text.ParseException;
|
|
import java.util.stream.Stream;
|
|
|
|
import jmri.InstanceManager;
|
|
import jmri.JmriException;
|
|
import jmri.util.*;
|
|
import jmri.jmrit.display.Editor;
|
|
import jmri.jmrit.logixng.LogixNG_Manager;
|
|
|
|
import org.junit.jupiter.api.*;
|
|
import org.junit.jupiter.api.io.TempDir;
|
|
import org.junit.jupiter.params.ParameterizedTest;
|
|
import org.junit.jupiter.params.provider.Arguments;
|
|
import org.junit.jupiter.params.provider.MethodSource;
|
|
|
|
/**
|
|
* Test that configuration files can be read and then stored again consistently.
|
|
* When done across various versions of schema, this checks ability to read
|
|
* older files in newer versions; completeness of reading code; etc.
|
|
* <p>
|
|
* Functional checks, that e.g. check the details of a specific type are being
|
|
* read properly, should go into another type-specific test class.
|
|
* <p>
|
|
* The functionality comes from the common base class, this is just here to
|
|
* insert the test suite into the JUnit hierarchy at the right place.
|
|
*
|
|
* @author Bob Jacobsen Copyright 2009, 2014
|
|
* @since 2.5.5 (renamed & reworked in 3.9 series)
|
|
*/
|
|
public class LoadAndStoreTest extends jmri.configurexml.LoadAndStoreTestBase {
|
|
|
|
public static Stream<Arguments> data() {
|
|
return getFiles(new File("java/test/jmri/jmrit/display/layoutEditor"), false, true);
|
|
}
|
|
|
|
@ParameterizedTest(name = "{index}: {0} (pass={1})")
|
|
@MethodSource("data")
|
|
public void loadAndStoreTest(File file, boolean pass) throws IOException, JmriException, ParseException {
|
|
this.loadLoadStoreFileCheck(file);
|
|
}
|
|
|
|
public LoadAndStoreTest() {
|
|
super(SaveType.User, true);
|
|
}
|
|
|
|
private boolean done;
|
|
|
|
/**
|
|
* Wait for the layout editor block processing to take place. This is quite
|
|
* layoutEditor-specific.
|
|
*/
|
|
@Override
|
|
protected void postLoadProcessing() {
|
|
|
|
done = false;
|
|
ThreadingUtil.runOnGUIDelayed(() -> done = true, 2500);
|
|
JUnitUtil.waitFor(() -> {
|
|
return InstanceManager.getDefault(LayoutBlockManager.class).stabilised || done;
|
|
},"LayoutBlockManager stabilised || done");
|
|
|
|
// need to do two separate ones because of waitFor limit
|
|
done = false;
|
|
ThreadingUtil.runOnGUIDelayed(() -> done = true, 2500);
|
|
JUnitUtil.waitFor(() -> {
|
|
return InstanceManager.getDefault(LayoutBlockManager.class).stabilised || done;
|
|
},"LayoutBlockManager stabilised || done");
|
|
if ( ! InstanceManager.getDefault(LayoutBlockManager.class).stabilised ) {
|
|
log.debug("not stabilized after check");
|
|
}
|
|
|
|
// and wait yet another 2 sec before writing out
|
|
done = false;
|
|
ThreadingUtil.runOnGUIDelayed(()->{
|
|
done = true;
|
|
}, 2000);
|
|
JUnitUtil.waitFor(()->{return done;},"GUI wait did not complete");
|
|
|
|
if ( ! jmri.InstanceManager.getDefault(LayoutBlockManager.class).stabilised ) {
|
|
log.debug(" still not stabilized");
|
|
}
|
|
|
|
done = false;
|
|
ThreadingUtil.runOnGUIDelayed(()->{
|
|
done = true;
|
|
}, 2000);
|
|
JUnitUtil.waitFor(()->{return done;},"next GUI wait did not complete");
|
|
|
|
if ( ! jmri.InstanceManager.getDefault(LayoutBlockManager.class).stabilised ) {
|
|
log.debug(" nor now");
|
|
}
|
|
|
|
InstanceManager.getDefault(LogixNG_Manager.class).setupAllLogixNGs();
|
|
}
|
|
|
|
/**
|
|
* Also writes out image files from these for later offline checking.This
|
|
* can't be (easily) automated, as the images vary from platform to
|
|
* platform.
|
|
*
|
|
* @param file the file to check
|
|
* {@inheritDoc}
|
|
* @throws java.io.IOException on test failure
|
|
* @throws jmri.JmriException on test failure
|
|
*/
|
|
@Override
|
|
public void loadLoadStoreFileCheck(File file) throws IOException, JmriException, ParseException {
|
|
super.loadLoadStoreFileCheck(file);
|
|
|
|
done = false;
|
|
ThreadingUtil.runOnGUIDelayed(() -> done = true, 1000);
|
|
JUnitUtil.waitFor(() -> done,"1 sec gui delay incomplete");
|
|
|
|
storeAndCompareImage(file);
|
|
}
|
|
|
|
// store image(s) of any JFrames
|
|
// inFile is an XML file
|
|
public void storeAndCompareImage(File inFile) throws IOException {
|
|
int index = 0;
|
|
for (JmriJFrame frame : JmriJFrame.getFrameList()) {
|
|
index++;
|
|
if (frame instanceof Editor) {
|
|
Editor le = (Editor) frame;
|
|
|
|
String name = inFile.getName();
|
|
FileUtil.createDirectory(FileUtil.getUserFilesPath() + "temp");
|
|
File outFile = new File(FileUtil.getUserFilesPath() + "temp/" + name + "." + index + ".png");
|
|
|
|
java.awt.Dimension size = new java.awt.Dimension(Math.min(le.getTargetPanel().getSize().width, 2000),
|
|
Math.min(le.getTargetPanel().getSize().height, 1000));
|
|
JUnitSwingUtil.writeDisplayedContentToFile(le.getTargetPanel(),
|
|
size, new java.awt.Point(0, 0),
|
|
outFile);
|
|
|
|
boolean first = true;
|
|
// and compare that file to a reference
|
|
// right now, we have only macOS reference files
|
|
if (SystemType.isMacOSX()) {
|
|
findAndComparePngFiles(name, inFile, outFile, index, "macos");
|
|
} else if (SystemType.isWindows()) {
|
|
findAndComparePngFiles(name, inFile, outFile, index, "windows");
|
|
} else if (SystemType.isLinux()) {
|
|
if (Boolean.getBoolean("jmri.migrationtests")) {
|
|
findAndComparePngFiles(name, inFile, outFile, index, "linux");
|
|
} else {
|
|
// skip test that does match from one linux (Jenkins) to another (Travis), but remind about it
|
|
if (first) {
|
|
log.info("Skipping tricky comparison of LayoutEditor graphics because jmri.migrationtests not set true");
|
|
}
|
|
first = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void findAndComparePngFiles(String name, File inFile, File outFile, int index, String subdir) throws IOException {
|
|
File parent = inFile.getCanonicalFile().getParentFile();
|
|
Assertions.assertNotNull(parent);
|
|
String filepath = parent.getParent();
|
|
Assertions.assertNotNull(filepath);
|
|
File compFile = new File(filepath + "/loadref/" + subdir + "/" + name + "." + index + ".png");
|
|
|
|
int checkVal = compareImageFiles(compFile, outFile);
|
|
Assertions.assertEquals(0, checkVal,
|
|
() -> "Screenshots didn't compare, new: " + outFile
|
|
+ " ref: " + compFile);
|
|
}
|
|
|
|
/**
|
|
* @param fileA first image to compare
|
|
* @param fileB second image to compare
|
|
* @return 0 if both image files are equal, -1 if exception, else count of
|
|
* different pixels; 0 is good.
|
|
*/
|
|
public static int compareImageFiles(File fileA, File fileB) {
|
|
try {
|
|
log.info("FileA: {}",fileA);
|
|
log.info("FileB: {}",fileB);
|
|
|
|
// check comparison file exists
|
|
if (!fileA.exists()) {
|
|
log.info("Comparison file {} doesn't exist, test skipped", fileA.getName());
|
|
return 0; // consider this passed with message
|
|
}
|
|
// get buffer data from both files
|
|
java.awt.image.BufferedImage biA = javax.imageio.ImageIO.read(fileA);
|
|
java.awt.image.DataBuffer dbA = biA.getData().getDataBuffer();
|
|
|
|
java.awt.image.BufferedImage biB = javax.imageio.ImageIO.read(fileB);
|
|
java.awt.image.DataBuffer dbB = biB.getData().getDataBuffer();
|
|
|
|
// check sizes
|
|
int sizeA = dbA.getSize();
|
|
int sizeB = dbB.getSize();
|
|
if (sizeA != sizeB) {
|
|
log.warn("Sizes don't match: {} != {}", sizeA, sizeB);
|
|
}
|
|
|
|
int size = Math.min(sizeA, sizeB);
|
|
// compare pixels in buffers
|
|
int retval = 0;
|
|
for (int i = 0; i < size; i++) {
|
|
if (dbA.getElem(i) != dbB.getElem(i)) {
|
|
retval++;
|
|
// log.warn("{} {} {} {}", retval, i, dbA.getElem(i), dbB.getElem(i));
|
|
}
|
|
}
|
|
return retval;
|
|
} catch (IOException e) {
|
|
log.error("Exception prevented comparing image files {} {}", fileA, fileB, e);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
@BeforeEach
|
|
@Override
|
|
public void setUp(@TempDir java.io.File tempDir) throws IOException {
|
|
// This test should not use tempDir because if we do, we cannot download
|
|
// the screenshots of failing tests from GitHub Windows CI.
|
|
super.setUp(FileUtil.getFile(FileUtil.SETTINGS));
|
|
JUnitUtil.initLayoutBlockManager();
|
|
}
|
|
|
|
@AfterEach
|
|
@Override
|
|
public void tearDown() {
|
|
// since each file tested will open its own windows, just close any
|
|
// open windows since we can't accurately list them here
|
|
JUnitUtil.resetWindows(false, false);
|
|
super.tearDown();
|
|
}
|
|
|
|
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoadAndStoreTest.class);
|
|
|
|
}
|