package jmri.configurexml; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import java.awt.GraphicsEnvironment; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.text.ParseException; import java.util.stream.Stream; import jmri.*; import jmri.jmrit.logix.WarrantPreferences; import jmri.util.FileUtil; import jmri.util.JUnitAppender; import jmri.util.JUnitUtil; import org.junit.jupiter.api.*; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.provider.Arguments; /** * Base for testing load-and-store of configuration files. *

* Creating a parameterized test class that extends this class will test each * file in a "load" directory by loading it, then storing it, then comparing * (with certain lines skipped) against either a file by the same name in the * "loadref" directory, or against the original file itself. A minimal test * class is:

   public class LoadAndStoreTest extends LoadAndStoreTestBase {

     public static Stream&Arguments& data() {
       return getFiles(new File("java/test/jmri/configurexml"), false, true);
     }

     @ParameterizedTest
     @MethodSource("data")
     public void loadAndStoreTest(File file, boolean pass) { super.validate(file, pass); }
   }
* * @author Bob Jacobsen Copyright 2009, 2014 * @since 2.5.5 (renamed & reworked in 3.9 series) */ public class LoadAndStoreTestBase { public enum SaveType { All, Config, Prefs, User, UserPrefs } private SaveType saveType = SaveType.Config; private boolean guiOnly = false; /** * Get all XML files in a directory and validate the ability to load and * store them. * * @param saveType the type (i.e. level) of ConfigureXml information being * saved * @param isGUI true for files containing GUI elements, i.e. panels. * These can only be loaded once (others can be loaded * twice, and that's tested when this is false), and can't * be loaded when running headless. */ public LoadAndStoreTestBase(SaveType saveType, boolean isGUI) { this.saveType = saveType; this.guiOnly = isGUI; } /** * Get all XML files in a directory and validate the ability to load and * store them. * * @param directory the directory containing XML files; the subdirectory * load under this directory will be used * @param recurse if true, will recurse into subdirectories * @param pass if true, successful validation will pass; if false, * successful validation will fail * @return a stream of {@link Arguments}, where each Argument contains the * {@link java.io.File} to validate and a boolean matching the pass * parameter */ public static Stream getFiles(File directory, boolean recurse, boolean pass) { // since this method gets the files to test, but does not trigger any // tests itself, we can use SchemaTestBase.getFiles() by adding "load" // to the directory to test return SchemaTestBase.getFiles(new File(directory, "load"), recurse, pass); } /** * Get all XML files in the immediate subdirectories of a directory and * validate them. * * @param directory the directory containing subdirectories containing XML * files * @param recurse if true, will recurse into subdirectories * @param pass if true, successful validation will pass; if false, * successful validation will fail * @return a collection of Object arrays, where each array contains the * {@link java.io.File} with a filename ending in {@literal .xml} to * validate and a boolean matching the pass parameter * @throws IllegalArgumentException if directory is a file */ public static Stream getDirectories(File directory, boolean recurse, boolean pass) throws IllegalArgumentException { // since this method gets the files to test, but does not trigger any // tests itself, we can use SchemaTestBase.getDirectories() by adding "load" // to the directory to test return SchemaTestBase.getDirectories(new File(directory, "load"), recurse, pass); } public static void checkFile(File inFile1, File inFile2) throws IOException, ParseException { try ( // compare files, except for certain special lines BufferedReader fileStream1 = new BufferedReader( new InputStreamReader(new FileInputStream(inFile1))); BufferedReader fileStream2 = new BufferedReader( new InputStreamReader(new FileInputStream(inFile2))); ) { String line1 = fileStream1.readLine(); String line2 = fileStream2.readLine(); int lineNumber1 = 0, lineNumber2 = 0; String next1, next2; while ((next1 = fileStream1.readLine()) != null && (next2 = fileStream2.readLine()) != null) { lineNumber1++; lineNumber2++; // Do we have a multi line comment? Comments in the xml file is used by LogixNG. // This only happens in the first file since store() will not store comments if (next1.startsWith("")) { lineNumber1++; } // If here, we either have a line that ends with --> or we have reached end of file String nullCheck = fileStream1.readLine(); if (nullCheck == null) { break; } // If here, we have a line that ends with --> or we have reached end of file continue; } // where the (empty) entryexitpairs line ends up seems to be non-deterministic // so if we see it in either file we just skip it String entryexitpairs = ""; if (line1.contains(entryexitpairs)) { line1 = next1; if ((next1 = fileStream1.readLine()) == null) { break; } lineNumber1++; } if (line2.contains(entryexitpairs)) { line2 = next2; if ((next2 = fileStream2.readLine()) == null) { break; } lineNumber2++; } // if we get to the file history... String filehistory = "filehistory"; if (line1.contains(filehistory) && line2.contains(filehistory)) { break; // we're done! } boolean match = false; // assume failure (pessimist!) String[] startsWithStrings = { "