package jalview.io; import jalview.bin.Cache; import jalview.datamodel.AlignmentI; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; import jalview.gui.JvOptionPane; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.TreeMap; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class BackupFilesTest { @BeforeClass(alwaysRun = true) public void setUpJvOptionPane() { JvOptionPane.setInteractiveMode(false); JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); } private static boolean actuallyDeleteTmpFiles = true; private static String testDir = "test/jalview/io"; private static String testBasename = "backupfilestest"; private static String testExt = ".fa"; private static String testFilename = testBasename + testExt; private static String testFile = testDir + File.separatorChar + testFilename; private static String newBasename = testBasename + "Temp"; private static String newFilename = newBasename + testExt; private static String newFile = testDir + File.separatorChar + newFilename; private static String sequenceName = "BACKUP_FILES"; private static String sequenceDescription = "backupfiles"; private static String sequenceData = "AAAARG"; private static String suffix = "_BACKUPTEST-%n"; private static int digits = 6; private static int rollMax = 2; private AlignFrame af; // read and save with backupfiles disabled @Test(groups = { "Functional" }) public void noBackupsEnabledTest() throws Exception { // set BACKUPFILES_ENABLED to false (i.e. turn off BackupFiles feature -- no // backup files to be made when saving) setBackupFilesOptions(false, true, true); // init the newFile and backups (i.e. make sure newFile exists on its own // and has no backups initNewFileForTesting(); // now save again save(); // check no backup files File[] backupFiles = getBackupFiles(); Assert.assertTrue(backupFiles.length == 0); } // save keeping all backup files @Test(groups = { "Functional" }) public void backupsEnabledNoRollMaxTest() throws Exception { // Enable BackupFiles and set noMax so all backupfiles get kept setBackupFilesOptions(true, false, true); // init the newFile and backups (i.e. make sure newFile exists on its own // and has no backups) initNewFileForTesting(); // now save a few times again. No rollMax so should have more than two // backup files int numSaves = 10; for (int i = 0; i < numSaves; i++) { save(); } // check 10 backup files HashMap correctindexmap = new HashMap<>(); correctindexmap.put(1, "backupfilestestTemp.fa_BACKUPTEST-000001"); correctindexmap.put(2, "backupfilestestTemp.fa_BACKUPTEST-000002"); correctindexmap.put(3, "backupfilestestTemp.fa_BACKUPTEST-000003"); correctindexmap.put(4, "backupfilestestTemp.fa_BACKUPTEST-000004"); correctindexmap.put(5, "backupfilestestTemp.fa_BACKUPTEST-000005"); correctindexmap.put(6, "backupfilestestTemp.fa_BACKUPTEST-000006"); correctindexmap.put(7, "backupfilestestTemp.fa_BACKUPTEST-000007"); correctindexmap.put(8, "backupfilestestTemp.fa_BACKUPTEST-000008"); correctindexmap.put(9, "backupfilestestTemp.fa_BACKUPTEST-000009"); correctindexmap.put(10, "backupfilestestTemp.fa_BACKUPTEST-000010"); HashMap wrongindexmap = new HashMap<>(); wrongindexmap.put(1, "backupfilestestTemp.fa_BACKUPTEST-1"); wrongindexmap.put(2, "backupfilestestTemp.fa_BACKUPTEST-000002"); wrongindexmap.put(3, "backupfilestestTemp.fa_BACKUPTEST-000003"); wrongindexmap.put(4, "backupfilestestTemp.fa_BACKUPTEST-000004"); wrongindexmap.put(5, "backupfilestestTemp.fa_BACKUPTEST-000005"); wrongindexmap.put(6, "backupfilestestTemp.fa_BACKUPTEST-000006"); wrongindexmap.put(7, "backupfilestestTemp.fa_BACKUPTEST-000007"); wrongindexmap.put(8, "backupfilestestTemp.fa_BACKUPTEST-000008"); wrongindexmap.put(9, "backupfilestestTemp.fa_BACKUPTEST-000009"); wrongindexmap.put(10, "backupfilestestTemp.fa_BACKUPTEST-000010"); int[] indexes2 = { 3, 4, 5, 6, 7, 8, 9, 10 }; int[] indexes3 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; Assert.assertTrue(checkBackupFiles(correctindexmap)); Assert.assertFalse(checkBackupFiles(wrongindexmap)); Assert.assertFalse(checkBackupFiles(indexes2)); Assert.assertFalse(checkBackupFiles(indexes3)); } // save keeping only the last rollMax (2) backup files @Test(groups = { "Functional" }) public void backupsEnabledRollMaxTest() throws Exception { // Enable BackupFiles and set noMax so all backupfiles get kept setBackupFilesOptions(true, false, false); // init the newFile and backups (i.e. make sure newFile exists on its own // and has no backups) initNewFileForTesting(); // now save a few times again. No rollMax so should have more than two // backup files int numSaves = 10; for (int i = 0; i < numSaves; i++) { save(); } // check there are "rollMax" backup files and they are all saved correctly // check 10 backup files HashMap correctindexmap = new HashMap<>(); correctindexmap.put(9, "backupfilestestTemp.fa_BACKUPTEST-000009"); correctindexmap.put(10, "backupfilestestTemp.fa_BACKUPTEST-000010"); int[] indexes2 = { 10 }; int[] indexes3 = { 8, 9, 10 }; Assert.assertTrue(checkBackupFiles(correctindexmap)); Assert.assertFalse(checkBackupFiles(indexes2)); Assert.assertFalse(checkBackupFiles(indexes3)); } // save keeping only the last rollMax (2) backup files @Test(groups = { "Functional" }) public void backupsEnabledReverseRollMaxTest() throws Exception { // Enable BackupFiles and set noMax so all backupfiles get kept setBackupFilesOptions(true, true, false); // init the newFile and backups (i.e. make sure newFile exists on its own // and has no backups) initNewFileForTesting(); // now save a few times again. No rollMax so should have more than two // backup files int numSaves = 10; for (int i = 0; i < numSaves; i++) { save(); } // check there are "rollMax" backup files and they are all saved correctly // check 10 backup files HashMap correctindexmap = new HashMap<>(); correctindexmap.put(1, "backupfilestestTemp.fa_BACKUPTEST-000001"); correctindexmap.put(2, "backupfilestestTemp.fa_BACKUPTEST-000002"); int[] indexes2 = { 1 }; int[] indexes3 = { 1, 2, 3 }; Assert.assertTrue(checkBackupFiles(correctindexmap)); Assert.assertFalse(checkBackupFiles(indexes2)); Assert.assertFalse(checkBackupFiles(indexes3)); } private void setBackupFilesOptions() { setBackupFilesOptions(true, false, false); } private void setBackupFilesOptions(boolean enabled, boolean reverse, boolean noMax) { Cache.loadProperties("test/jalview/io/testProps.jvprops"); Cache.initLogger(); BackupFilesPresetEntry bfpe = new BackupFilesPresetEntry(suffix, digits, reverse, noMax, rollMax, false); Cache.applicationProperties.setProperty(BackupFiles.ENABLED, Boolean.toString(enabled)); Cache.applicationProperties.setProperty( BackupFilesPresetEntry.SAVEDCONFIG, bfpe.toString()); /* Cache.applicationProperties.setProperty(BackupFiles.ENABLED, Boolean.toString(enabled)); Cache.applicationProperties.setProperty(BackupFiles.SUFFIX, suffix); Cache.applicationProperties.setProperty(BackupFiles.SUFFIX_DIGITS, Integer.toString(digits)); Cache.applicationProperties.setProperty(BackupFiles.REVERSE_ORDER, Boolean.toString(reverse)); Cache.applicationProperties.setProperty(BackupFiles.NO_MAX, Boolean.toString(noMax)); Cache.applicationProperties.setProperty(BackupFiles.ROLL_MAX, Integer.toString(rollMax)); Cache.applicationProperties.setProperty(BackupFiles.CONFIRM_DELETE_OLD, "false"); */ } private void save() { if (af != null) { af.saveAlignment(newFile, jalview.io.FileFormat.Fasta); } } // this runs cleanTmpFiles and then writes the newFile once as a starting // point for all tests private void initNewFileForTesting() throws Exception { cleanupTmpFiles(); AppletFormatAdapter afa = new AppletFormatAdapter(); AlignmentI al = afa.readFile(testFile, DataSourceType.FILE, jalview.io.FileFormat.Fasta); List l = al.getSequences(); // check this is right if (l.size() != 1) { throw new Exception("single sequence from '" + testFile + "' not read in correctly (should be a single short sequence). List size is wrong."); } SequenceI s = l.get(0); Sequence ref = new Sequence(sequenceName, sequenceData); ref.setDescription(sequenceDescription); if (!sequencesEqual(s, ref)) { throw new Exception("single sequence from '" + testFile + "' not read in correctly (should be a single short sequence). SequenceI name, description or data is wrong."); } // save alignment file to new filename -- this doesn't test backups disabled // yet as this file shouldn't already exist af = new AlignFrame(al, 0, 0); af.saveAlignment(newFile, jalview.io.FileFormat.Fasta); } // this deletes the newFile (if it exists) and any saved backup file for it @AfterClass(alwaysRun = true) private void cleanupTmpFiles() { File newfile = new File(newFile); if (newfile.exists()) { newfile.delete(); } File[] tmpFiles = getBackupFiles(newFile, suffix, digits); for (int i = 0; i < tmpFiles.length; i++) { if (actuallyDeleteTmpFiles) { tmpFiles[i].delete(); } else { System.out.println("Pretending to delete " + tmpFiles[i].getPath()); } } } private static File[] getBackupFiles(String f, String s, int i) { TreeMap bfTreeMap = BackupFiles.getBackupFilesAsTreeMap(f, s, i); File[] backupFiles = new File[bfTreeMap.size()]; bfTreeMap.values().toArray(backupFiles); return backupFiles; } private static File[] getBackupFiles() { return getBackupFiles(newFile, suffix, digits); } private static boolean checkBackupFiles(HashMap indexmap) throws IOException { TreeMap map = BackupFiles.getBackupFilesAsTreeMap(newFile, suffix, digits); Enumeration indexesenum = Collections .enumeration(indexmap.keySet()); while (indexesenum.hasMoreElements()) { int i = indexesenum.nextElement(); String indexfilename = indexmap.get(i); if (!map.containsKey(i)) { return false; } File f = map.get(i); if (!filesContentEqual(newFile, f.getPath())) { return false; } map.remove(i); if (f == null) { return false; } if (!f.getName().equals(indexfilename)) { return false; } } // should be nothing left in map if (map.size() > 0) { return false; } return true; } private static boolean checkBackupFiles(int[] indexes) throws IOException { TreeMap map = BackupFiles.getBackupFilesAsTreeMap(newFile, suffix, digits); for (int m = 0; m < indexes.length; m++) { int i = indexes[m]; if (!map.containsKey(i)) { return false; } File f = map.get(i); if (!filesContentEqual(newFile, f.getPath())) { return false; } map.remove(i); if (f == null) { return false; } // check the filename -- although this uses the same code to forumulate the filename so not much of a test! String filename = BackupFilenameParts.getBackupFilename(i, newBasename + testExt, suffix, digits); if (!filename.equals(f.getName())) { System.out.println("Supposed filename '" + filename + "' not equal to actual filename '" + f.getName() + "'"); return false; } } // should be nothing left in map if (map.size() > 0) { return false; } return true; } private static String[] getBackupFilesAsStrings() { File[] files = getBackupFiles(newFile, suffix, digits); String[] filenames = new String[files.length]; for (int i = 0; i < files.length; i++) { filenames[i] = files[i].getPath(); } return filenames; } public static boolean sequencesEqual(SequenceI s1, SequenceI s2) { if (s1 == null && s2 == null) { return true; } else if (s1 == null || s2 == null) { return false; } return (s1.getName().equals(s2.getName()) && s1.getDescription().equals(s2.getDescription()) && Arrays.equals(s1.getSequence(), s2.getSequence())); } public static boolean filesContentEqual(String fileName1, String fileName2) throws IOException { Path file1 = Paths.get(fileName1); Path file2 = Paths.get(fileName2); byte[] bytes1 = Files.readAllBytes(file1); byte[] bytes2 = Files.readAllBytes(file2); return Arrays.equals(bytes1, bytes2); } }