JAL-3746 apply copyright to tests
[jalview.git] / test / jalview / io / BackupFilesTest.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.io;
22
23 import java.io.File;
24 import java.io.IOException;
25 import java.nio.file.Files;
26 import java.nio.file.Path;
27 import java.nio.file.Paths;
28 import java.util.Arrays;
29 import java.util.Collections;
30 import java.util.Enumeration;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.TreeMap;
34
35 import org.testng.Assert;
36 import org.testng.annotations.AfterClass;
37 import org.testng.annotations.BeforeClass;
38 import org.testng.annotations.Test;
39
40 import jalview.bin.Cache;
41 import jalview.datamodel.AlignmentI;
42 import jalview.datamodel.Sequence;
43 import jalview.datamodel.SequenceI;
44 import jalview.gui.AlignFrame;
45 import jalview.gui.JvOptionPane;
46
47 public class BackupFilesTest
48 {
49   @BeforeClass(alwaysRun = true)
50   public void setUpJvOptionPane()
51   {
52     JvOptionPane.setInteractiveMode(false);
53     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
54   }
55
56   private static boolean actuallyDeleteTmpFiles = true;
57
58   private static String testDir = "test/jalview/io";
59
60   private static String testBasename = "backupfilestest";
61
62   private static String testExt = ".fa";
63
64   private static String testFilename = testBasename + testExt;
65
66   private static String testFile = testDir + File.separatorChar
67           + testFilename;
68
69   private static String newBasename = testBasename + "Temp";
70
71   private static String newFilename = newBasename + testExt;
72
73   private static String newFile = testDir + File.separatorChar
74           + newFilename;
75
76   private static String sequenceName = "BACKUP_FILES";
77
78   private static String sequenceDescription = "backupfiles";
79
80   private static String sequenceData = "AAAARG";
81
82   private static String suffix = "_BACKUPTEST-%n";
83
84   private static int digits = 6;
85
86   private static int rollMax = 2;
87
88   private AlignFrame af;
89
90   // read and save with backupfiles disabled
91   @Test(groups = { "Functional" })
92   public void noBackupsEnabledTest() throws Exception
93   {
94     // set BACKUPFILES_ENABLED to false (i.e. turn off BackupFiles feature -- no
95     // backup files to be made when saving)
96     setBackupFilesOptions(false, true, true);
97
98     // init the newFile and backups (i.e. make sure newFile exists on its own
99     // and has no backups
100     initNewFileForTesting();
101
102     // now save again
103     save();
104
105     // check no backup files
106     File[] backupFiles = getBackupFiles();
107     Assert.assertTrue(backupFiles.length == 0);
108   }
109
110   // save with no numbers in the backup file names
111   @Test(groups = { "Functional" })
112   public void backupsEnabledSingleFileBackupTest() throws Exception
113   {
114     // Enable BackupFiles and set noMax so all backupfiles get kept
115     String mysuffix = "~";
116     BackupFilesPresetEntry bfpe = new BackupFilesPresetEntry(mysuffix, 1,
117             false, true, 1, false);
118     setBackupFilesOptions(true, false, true,
119             "test/jalview/io/testProps_singlefilebackup.jvprops", bfpe);
120
121     // init the newFile and backups (i.e. make sure newFile exists on its own
122     // and has no backups)
123     initNewFileForTesting();
124     HashMap<Integer, String> correctindexmap = new HashMap<>();
125     correctindexmap.put(0, "backupfilestestTemp.fa~");
126
127     save();
128     Assert.assertTrue(checkBackupFiles(correctindexmap, newFile, "~", 1));
129
130     // and a second time -- see JAL-3628
131     save();
132     Assert.assertTrue(checkBackupFiles(correctindexmap, newFile, "~", 1));
133
134     cleanupTmpFiles(newFile, "~", 1);
135   }
136
137   // save keeping all backup files
138   @Test(groups = { "Functional" })
139   public void backupsEnabledNoRollMaxTest() throws Exception
140   {
141     // Enable BackupFiles and set noMax so all backupfiles get kept
142     setBackupFilesOptions(true, false, true);
143
144     // init the newFile and backups (i.e. make sure newFile exists on its own
145     // and has no backups)
146     initNewFileForTesting();
147
148     // now save a few times again. No rollMax so should have more than two
149     // backup files
150     int numSaves = 10;
151     for (int i = 0; i < numSaves; i++)
152     {
153       save();
154     }
155
156     // check 10 backup files
157     HashMap<Integer, String> correctindexmap = new HashMap<>();
158     correctindexmap.put(1, "backupfilestestTemp.fa_BACKUPTEST-000001");
159     correctindexmap.put(2, "backupfilestestTemp.fa_BACKUPTEST-000002");
160     correctindexmap.put(3, "backupfilestestTemp.fa_BACKUPTEST-000003");
161     correctindexmap.put(4, "backupfilestestTemp.fa_BACKUPTEST-000004");
162     correctindexmap.put(5, "backupfilestestTemp.fa_BACKUPTEST-000005");
163     correctindexmap.put(6, "backupfilestestTemp.fa_BACKUPTEST-000006");
164     correctindexmap.put(7, "backupfilestestTemp.fa_BACKUPTEST-000007");
165     correctindexmap.put(8, "backupfilestestTemp.fa_BACKUPTEST-000008");
166     correctindexmap.put(9, "backupfilestestTemp.fa_BACKUPTEST-000009");
167     correctindexmap.put(10, "backupfilestestTemp.fa_BACKUPTEST-000010");
168     HashMap<Integer, String> wrongindexmap = new HashMap<>();
169     wrongindexmap.put(1, "backupfilestestTemp.fa_BACKUPTEST-1");
170     wrongindexmap.put(2, "backupfilestestTemp.fa_BACKUPTEST-000002");
171     wrongindexmap.put(3, "backupfilestestTemp.fa_BACKUPTEST-000003");
172     wrongindexmap.put(4, "backupfilestestTemp.fa_BACKUPTEST-000004");
173     wrongindexmap.put(5, "backupfilestestTemp.fa_BACKUPTEST-000005");
174     wrongindexmap.put(6, "backupfilestestTemp.fa_BACKUPTEST-000006");
175     wrongindexmap.put(7, "backupfilestestTemp.fa_BACKUPTEST-000007");
176     wrongindexmap.put(8, "backupfilestestTemp.fa_BACKUPTEST-000008");
177     wrongindexmap.put(9, "backupfilestestTemp.fa_BACKUPTEST-000009");
178     wrongindexmap.put(10, "backupfilestestTemp.fa_BACKUPTEST-000010");
179     int[] indexes2 = { 3, 4, 5, 6, 7, 8, 9, 10 };
180     int[] indexes3 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
181     Assert.assertTrue(checkBackupFiles(correctindexmap));
182     Assert.assertFalse(checkBackupFiles(wrongindexmap));
183     Assert.assertFalse(checkBackupFiles(indexes2));
184     Assert.assertFalse(checkBackupFiles(indexes3));
185   }
186
187   // save keeping only the last rollMax (2) backup files
188   @Test(groups = { "Functional" })
189   public void backupsEnabledRollMaxTest() throws Exception
190   {
191     // Enable BackupFiles and set noMax so all backupfiles get kept
192     setBackupFilesOptions(true, false, false);
193
194     // init the newFile and backups (i.e. make sure newFile exists on its own
195     // and has no backups)
196     initNewFileForTesting();
197
198     // now save a few times again. No rollMax so should have more than two
199     // backup files
200     int numSaves = 10;
201     for (int i = 0; i < numSaves; i++)
202     {
203       save();
204     }
205
206     // check there are "rollMax" backup files and they are all saved correctly
207     // check 10 backup files
208     HashMap<Integer, String> correctindexmap = new HashMap<>();
209     correctindexmap.put(9, "backupfilestestTemp.fa_BACKUPTEST-000009");
210     correctindexmap.put(10, "backupfilestestTemp.fa_BACKUPTEST-000010");
211     int[] indexes2 = { 10 };
212     int[] indexes3 = { 8, 9, 10 };
213     Assert.assertTrue(checkBackupFiles(correctindexmap));
214     Assert.assertFalse(checkBackupFiles(indexes2));
215     Assert.assertFalse(checkBackupFiles(indexes3));
216   }
217
218   // save keeping only the last rollMax (2) backup files
219   @Test(groups = { "Functional" })
220   public void backupsEnabledReverseRollMaxTest() throws Exception
221   {
222     // Enable BackupFiles and set noMax so all backupfiles get kept
223     setBackupFilesOptions(true, true, false);
224
225     // init the newFile and backups (i.e. make sure newFile exists on its own
226     // and has no backups)
227     initNewFileForTesting();
228
229     // now save a few times again. No rollMax so should have more than two
230     // backup files
231     int numSaves = 10;
232     for (int i = 0; i < numSaves; i++)
233     {
234       save();
235     }
236
237     // check there are "rollMax" backup files and they are all saved correctly
238     // check 10 backup files
239     HashMap<Integer, String> correctindexmap = new HashMap<>();
240     correctindexmap.put(1, "backupfilestestTemp.fa_BACKUPTEST-000001");
241     correctindexmap.put(2, "backupfilestestTemp.fa_BACKUPTEST-000002");
242     int[] indexes2 = { 1 };
243     int[] indexes3 = { 1, 2, 3 };
244     Assert.assertTrue(checkBackupFiles(correctindexmap));
245     Assert.assertFalse(checkBackupFiles(indexes2));
246     Assert.assertFalse(checkBackupFiles(indexes3));
247   }
248
249   private void setBackupFilesOptions()
250   {
251     setBackupFilesOptions(true, false, false);
252   }
253
254   private void setBackupFilesOptions(boolean enabled, boolean reverse,
255           boolean noMax)
256   {
257     BackupFilesPresetEntry bfpe = new BackupFilesPresetEntry(suffix, digits,
258             reverse, noMax, rollMax, false);
259     setBackupFilesOptions(enabled, reverse, noMax,
260             "test/jalview/io/testProps.jvprops", bfpe);
261   }
262
263   private void setBackupFilesOptions(boolean enabled, boolean reverse,
264           boolean noMax, String propsFile, BackupFilesPresetEntry bfpe)
265   {
266     Cache.loadProperties(propsFile);
267
268     Cache.applicationProperties.setProperty(BackupFiles.ENABLED,
269             Boolean.toString(enabled));
270     Cache.applicationProperties.setProperty(
271             BackupFilesPresetEntry.SAVEDCONFIG, bfpe.toString());
272     /*
273     Cache.applicationProperties.setProperty(BackupFiles.ENABLED,
274             Boolean.toString(enabled));
275     Cache.applicationProperties.setProperty(BackupFiles.SUFFIX, suffix);
276     Cache.applicationProperties.setProperty(BackupFiles.SUFFIX_DIGITS,
277             Integer.toString(digits));
278     Cache.applicationProperties.setProperty(BackupFiles.REVERSE_ORDER,
279             Boolean.toString(reverse));
280     Cache.applicationProperties.setProperty(BackupFiles.NO_MAX,
281             Boolean.toString(noMax));
282     Cache.applicationProperties.setProperty(BackupFiles.ROLL_MAX,
283             Integer.toString(rollMax));
284     Cache.applicationProperties.setProperty(BackupFiles.CONFIRM_DELETE_OLD,
285             "false");
286             */
287   }
288
289   private void save()
290   {
291     if (af != null)
292     {
293       af.saveAlignment(newFile, jalview.io.FileFormat.Fasta);
294     }
295   }
296
297   // this runs cleanTmpFiles and then writes the newFile once as a starting
298   // point for all tests
299   private void initNewFileForTesting() throws Exception
300   {
301     cleanupTmpFiles();
302
303     AppletFormatAdapter afa = new AppletFormatAdapter();
304     AlignmentI al = afa.readFile(testFile, DataSourceType.FILE,
305             jalview.io.FileFormat.Fasta);
306     List<SequenceI> l = al.getSequences();
307
308     // check this is right
309     if (l.size() != 1)
310     {
311       throw new Exception("single sequence from '" + testFile
312               + "' not read in correctly (should be a single short sequence). List<SequenceI> size is wrong.");
313     }
314     SequenceI s = l.get(0);
315     Sequence ref = new Sequence(sequenceName, sequenceData);
316     ref.setDescription(sequenceDescription);
317     if (!sequencesEqual(s, ref))
318     {
319       throw new Exception("single sequence from '" + testFile
320               + "' not read in correctly (should be a single short sequence). SequenceI name, description or data is wrong.");
321     }
322     // save alignment file to new filename -- this doesn't test backups disabled
323     // yet as this file shouldn't already exist
324     af = new AlignFrame(al, 0, 0);
325     af.saveAlignment(newFile, jalview.io.FileFormat.Fasta);
326   }
327
328   // this deletes the newFile (if it exists) and any saved backup file for it
329   @AfterClass(alwaysRun = true)
330   private void cleanupTmpFiles()
331   {
332     cleanupTmpFiles(newFile, suffix, digits);
333   }
334
335   protected static void cleanupTmpFiles(String file, String mysuffix,
336           int mydigits)
337   {
338     File newfile = new File(file);
339     if (newfile.exists())
340     {
341       newfile.delete();
342     }
343     File[] tmpFiles = getBackupFiles(file, mysuffix, mydigits);
344     for (int i = 0; i < tmpFiles.length; i++)
345     {
346       if (actuallyDeleteTmpFiles)
347       {
348         tmpFiles[i].delete();
349       }
350       else
351       {
352         System.out.println("Pretending to delete " + tmpFiles[i].getPath());
353       }
354     }
355   }
356
357   private static File[] getBackupFiles(String f, String s, int i)
358   {
359     TreeMap<Integer, File> bfTreeMap = BackupFiles
360             .getBackupFilesAsTreeMap(f, s, i);
361     File[] backupFiles = new File[bfTreeMap.size()];
362     bfTreeMap.values().toArray(backupFiles);
363     return backupFiles;
364   }
365
366   private static File[] getBackupFiles()
367   {
368     return getBackupFiles(newFile, suffix, digits);
369   }
370
371   private static boolean checkBackupFiles(HashMap<Integer, String> indexmap)
372           throws IOException
373   {
374     return checkBackupFiles(indexmap, newFile, suffix, digits);
375   }
376
377   private static boolean checkBackupFiles(HashMap<Integer, String> indexmap,
378           String file, String mysuffix, int mydigits) throws IOException
379   {
380     TreeMap<Integer, File> map = BackupFiles.getBackupFilesAsTreeMap(file,
381             mysuffix, mydigits);
382     Enumeration<Integer> indexesenum = Collections
383             .enumeration(indexmap.keySet());
384     while (indexesenum.hasMoreElements())
385     {
386       int i = indexesenum.nextElement();
387       String indexfilename = indexmap.get(i);
388       if (!map.containsKey(i))
389       {
390         return false;
391       }
392       File f = map.get(i);
393       if (!filesContentEqual(newFile, f.getPath()))
394       {
395         return false;
396       }
397       map.remove(i);
398       if (f == null)
399       {
400         return false;
401       }
402       if (!f.getName().equals(indexfilename))
403       {
404         return false;
405       }
406     }
407     // should be nothing left in map
408     if (map.size() > 0)
409     {
410       return false;
411     }
412
413     return true;
414   }
415
416   private static boolean checkBackupFiles(int[] indexes) throws IOException
417   {
418     TreeMap<Integer, File> map = BackupFiles
419             .getBackupFilesAsTreeMap(newFile, suffix, digits);
420     for (int m = 0; m < indexes.length; m++)
421     {
422       int i = indexes[m];
423       if (!map.containsKey(i))
424       {
425         return false;
426       }
427       File f = map.get(i);
428       if (!filesContentEqual(newFile, f.getPath()))
429       {
430         return false;
431       }
432       map.remove(i);
433       if (f == null)
434       {
435         return false;
436       }
437       // check the filename -- although this uses the same code to forumulate
438       // the filename so not much of a test!
439       String filename = BackupFilenameParts.getBackupFilename(i,
440               newBasename + testExt, suffix, digits);
441       if (!filename.equals(f.getName()))
442       {
443         System.out.println("Supposed filename '" + filename
444                 + "' not equal to actual filename '" + f.getName() + "'");
445         return false;
446       }
447     }
448     // should be nothing left in map
449     if (map.size() > 0)
450     {
451       return false;
452     }
453
454     return true;
455   }
456
457   private static String[] getBackupFilesAsStrings()
458   {
459     File[] files = getBackupFiles(newFile, suffix, digits);
460     String[] filenames = new String[files.length];
461     for (int i = 0; i < files.length; i++)
462     {
463       filenames[i] = files[i].getPath();
464     }
465     return filenames;
466   }
467
468   public static boolean sequencesEqual(SequenceI s1, SequenceI s2)
469   {
470     if (s1 == null && s2 == null)
471     {
472       return true;
473     }
474     else if (s1 == null || s2 == null)
475     {
476       return false;
477     }
478     return (s1.getName().equals(s2.getName())
479             && s1.getDescription().equals(s2.getDescription())
480             && Arrays.equals(s1.getSequence(), s2.getSequence()));
481   }
482
483   public static boolean filesContentEqual(String fileName1,
484           String fileName2) throws IOException
485   {
486     Path file1 = Paths.get(fileName1);
487     Path file2 = Paths.get(fileName2);
488     byte[] bytes1 = Files.readAllBytes(file1);
489     byte[] bytes2 = Files.readAllBytes(file2);
490     return Arrays.equals(bytes1, bytes2);
491   }
492
493 }