JAL-1369 additional asserts in testStoreAndRecoverReferenceSeqSettings
[jalview.git] / test / jalview / io / Jalview2xmlTests.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 static org.testng.AssertJUnit.assertEquals;
24 import static org.testng.AssertJUnit.assertFalse;
25 import static org.testng.AssertJUnit.assertTrue;
26
27 import jalview.api.AlignViewportI;
28 import jalview.api.AlignmentViewPanel;
29 import jalview.api.ViewStyleI;
30 import jalview.bin.Cache;
31 import jalview.datamodel.AlignmentAnnotation;
32 import jalview.datamodel.AlignmentI;
33 import jalview.datamodel.HiddenSequences;
34 import jalview.datamodel.SequenceGroup;
35 import jalview.datamodel.SequenceI;
36 import jalview.gui.AlignFrame;
37 import jalview.gui.Desktop;
38 import jalview.gui.Jalview2XML;
39 import jalview.schemes.AnnotationColourGradient;
40 import jalview.schemes.ColourSchemeI;
41 import jalview.viewmodel.AlignmentViewport;
42
43 import java.io.File;
44 import java.util.ArrayList;
45 import java.util.HashMap;
46 import java.util.List;
47 import java.util.Map;
48
49 import org.testng.Assert;
50 import org.testng.AssertJUnit;
51 import org.testng.annotations.AfterClass;
52 import org.testng.annotations.BeforeClass;
53 import org.testng.annotations.Test;
54
55 @Test(singleThreaded = true)
56 public class Jalview2xmlTests
57 {
58
59   /**
60    * @throws java.lang.Exception
61    */
62   @BeforeClass(alwaysRun = true)
63   public static void setUpBeforeClass() throws Exception
64   {
65     jalview.bin.Jalview.main(new String[] { "-props",
66         "test/jalview/io/testProps.jvprops" });
67   }
68
69   /**
70    * @throws java.lang.Exception
71    */
72   @AfterClass(alwaysRun = true)
73   public static void tearDownAfterClass() throws Exception
74   {
75     jalview.gui.Desktop.instance.closeAll_actionPerformed(null);
76   }
77
78   int countDsAnn(jalview.viewmodel.AlignmentViewport avp)
79   {
80     int numdsann = 0;
81     for (SequenceI sq : avp.getAlignment().getDataset().getSequences())
82     {
83       if (sq.getAnnotation() != null)
84       {
85         for (AlignmentAnnotation dssa : sq.getAnnotation())
86         {
87           if (dssa.isValidStruc())
88           {
89             numdsann++;
90           }
91         }
92       }
93     }
94     return numdsann;
95   }
96
97   @Test(groups = { "Functional" })
98   public void testRNAStructureRecovery() throws Exception
99   {
100     String inFile = "examples/RF00031_folded.stk";
101     String tfile = File.createTempFile("JalviewTest", ".jvp")
102             .getAbsolutePath();
103     AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
104             inFile, FormatAdapter.FILE);
105     assertTrue("Didn't read input file " + inFile, af != null);
106     int olddsann = countDsAnn(af.getViewport());
107     assertTrue("Didn't find any dataset annotations", olddsann > 0);
108     af.rnahelicesColour_actionPerformed(null);
109     assertTrue(
110             "Couldn't apply RNA helices colourscheme",
111             af.getViewport().getGlobalColourScheme() instanceof jalview.schemes.RNAHelicesColour);
112     assertTrue("Failed to store as a project.",
113             af.saveAlignment(tfile, "Jalview"));
114     af.closeMenuItem_actionPerformed(true);
115     af = null;
116     af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(tfile,
117             FormatAdapter.FILE);
118     assertTrue("Failed to import new project", af != null);
119     int newdsann = countDsAnn(af.getViewport());
120     assertTrue(
121             "Differing numbers of dataset sequence annotation\nOriginally "
122                     + olddsann + " and now " + newdsann,
123             olddsann == newdsann);
124     System.out
125             .println("Read in same number of annotations as originally present ("
126                     + olddsann + ")");
127     assertTrue(
128             "RNA helices colourscheme was not applied on import.",
129             af.getViewport().getGlobalColourScheme() instanceof jalview.schemes.RNAHelicesColour);
130   }
131
132   @Test(groups = { "Functional" })
133   public void testTCoffeeScores() throws Exception
134   {
135     String inFile = "examples/uniref50.fa", inAnnot = "examples/uniref50.score_ascii";
136     String tfile = File.createTempFile("JalviewTest", ".jvp")
137             .getAbsolutePath();
138     AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
139             inFile, FormatAdapter.FILE);
140     assertTrue("Didn't read input file " + inFile, af != null);
141     af.loadJalviewDataFile(inAnnot, FormatAdapter.FILE, null, null);
142     assertTrue(
143             "Didn't set T-coffee colourscheme",
144             af.getViewport().getGlobalColourScheme().getClass()
145                     .equals(jalview.schemes.TCoffeeColourScheme.class));
146     assertTrue(
147             "Recognise T-Coffee score from string",
148             jalview.schemes.ColourSchemeProperty.getColour(af.getViewport()
149                     .getAlignment(),
150                     jalview.schemes.ColourSchemeProperty.getColourName(af
151                             .getViewport().getGlobalColourScheme())) != null);
152
153     assertTrue("Failed to store as a project.",
154             af.saveAlignment(tfile, "Jalview"));
155     af.closeMenuItem_actionPerformed(true);
156     af = null;
157     af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(tfile,
158             FormatAdapter.FILE);
159     assertTrue("Failed to import new project", af != null);
160     assertTrue(
161             "Didn't set T-coffee colourscheme for imported project.",
162             af.getViewport().getGlobalColourScheme().getClass()
163                     .equals(jalview.schemes.TCoffeeColourScheme.class));
164     System.out
165             .println("T-Coffee score shading successfully recovered from project.");
166   }
167
168   @Test(groups = { "Functional" })
169   public void testColourByAnnotScores() throws Exception
170   {
171     String inFile = "examples/uniref50.fa", inAnnot = "examples/testdata/uniref50_iupred.jva";
172     String tfile = File.createTempFile("JalviewTest", ".jvp")
173             .getAbsolutePath();
174     AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
175             inFile, FormatAdapter.FILE);
176     assertTrue("Didn't read input file " + inFile, af != null);
177     af.loadJalviewDataFile(inAnnot, FormatAdapter.FILE, null, null);
178     AlignmentAnnotation[] aa = af.getViewport().getAlignment()
179             .getSequenceAt(0).getAnnotation("IUPredWS (Short)");
180     assertTrue(
181             "Didn't find any IUPred annotation to use to shade alignment.",
182             aa != null && aa.length > 0);
183     AnnotationColourGradient cs = new jalview.schemes.AnnotationColourGradient(
184             aa[0], null, AnnotationColourGradient.ABOVE_THRESHOLD);
185     AnnotationColourGradient gcs = new jalview.schemes.AnnotationColourGradient(
186             aa[0], null, AnnotationColourGradient.BELOW_THRESHOLD);
187     cs.setSeqAssociated(true);
188     gcs.setSeqAssociated(true);
189     af.changeColour(cs);
190     SequenceGroup sg = new SequenceGroup();
191     sg.setStartRes(57);
192     sg.setEndRes(92);
193     sg.cs = gcs;
194     af.getViewport().getAlignment().addGroup(sg);
195     sg.addSequence(af.getViewport().getAlignment().getSequenceAt(1), false);
196     sg.addSequence(af.getViewport().getAlignment().getSequenceAt(2), true);
197     af.alignPanel.alignmentChanged();
198     assertTrue("Failed to store as a project.",
199             af.saveAlignment(tfile, "Jalview"));
200     af.closeMenuItem_actionPerformed(true);
201     af = null;
202     af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(tfile,
203             FormatAdapter.FILE);
204     assertTrue("Failed to import new project", af != null);
205
206     // check for group and alignment colourschemes
207
208     ColourSchemeI _rcs = af.getViewport().getGlobalColourScheme();
209     ColourSchemeI _rgcs = af.getViewport().getAlignment().getGroups()
210             .get(0).cs;
211     assertTrue("Didn't recover global colourscheme", _rcs != null);
212     assertTrue("Didn't recover annotation colour global scheme",
213             _rcs instanceof AnnotationColourGradient);
214     AnnotationColourGradient __rcs = (AnnotationColourGradient) _rcs;
215     assertTrue("Annotation colourscheme wasn't sequence associated",
216             __rcs.isSeqAssociated());
217
218     boolean diffseqcols = false, diffgseqcols = false;
219     SequenceI[] sqs = af.getViewport().getAlignment().getSequencesArray();
220     for (int p = 0, pSize = af.getViewport().getAlignment().getWidth(); p < pSize
221             && (!diffseqcols || !diffgseqcols); p++)
222     {
223       if (_rcs.findColour(sqs[0].getCharAt(p), p, sqs[0]) != _rcs
224               .findColour(sqs[5].getCharAt(p), p, sqs[5]))
225       {
226         diffseqcols = true;
227       }
228     }
229     assertTrue("Got Different sequence colours", diffseqcols);
230     System.out
231             .println("Per sequence colourscheme (Background) successfully applied and recovered.");
232
233     assertTrue("Didn't recover group colourscheme", _rgcs != null);
234     assertTrue("Didn't recover annotation colour group colourscheme",
235             _rgcs instanceof AnnotationColourGradient);
236     __rcs = (AnnotationColourGradient) _rgcs;
237     assertTrue("Group Annotation colourscheme wasn't sequence associated",
238             __rcs.isSeqAssociated());
239
240     for (int p = 0, pSize = af.getViewport().getAlignment().getWidth(); p < pSize
241             && (!diffseqcols || !diffgseqcols); p++)
242     {
243       if (_rgcs.findColour(sqs[1].getCharAt(p), p, sqs[1]) != _rgcs
244               .findColour(sqs[2].getCharAt(p), p, sqs[2]))
245       {
246         diffgseqcols = true;
247       }
248     }
249     assertTrue("Got Different group sequence colours", diffgseqcols);
250     System.out
251             .println("Per sequence (Group) colourscheme successfully applied and recovered.");
252   }
253
254   @Test(groups = { "Functional" })
255   public void gatherViewsHere() throws Exception
256   {
257     int origCount = Desktop.getAlignFrames() == null ? 0 : Desktop
258             .getAlignFrames().length;
259     AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
260             "examples/exampleFile_2_7.jar", FormatAdapter.FILE);
261     assertTrue("Didn't read in the example file correctly.", af != null);
262     assertTrue("Didn't gather the views in the example file.",
263             Desktop.getAlignFrames().length == 1 + origCount);
264
265   }
266
267   @Test(groups = { "Functional" })
268   public void viewRefPdbAnnotation() throws Exception
269   {
270     Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
271             Boolean.TRUE.toString());
272     Cache.applicationProperties.setProperty("ADD_SS_ANN",
273             Boolean.TRUE.toString());
274     AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
275             "examples/exampleFile_2_7.jar", FormatAdapter.FILE);
276     assertTrue("Didn't read in the example file correctly.", af != null);
277     AlignmentViewPanel sps = null;
278     for (AlignmentViewPanel ap : af.alignPanel.alignFrame.getAlignPanels())
279     {
280       if ("Spinach Feredoxin Structure".equals(ap.getViewName()))
281       {
282         sps = ap;
283         break;
284       }
285     }
286     assertTrue("Couldn't find the structure view", sps != null);
287     SequenceI sq = sps.getAlignment().findName("1A70|");
288     AlignmentAnnotation refan = null;
289     for (AlignmentAnnotation ra : sps.getAlignment()
290             .getAlignmentAnnotation())
291     {
292       if (ra.graph != 0)
293       {
294         refan = ra;
295         break;
296       }
297     }
298     assertTrue("Annotation secondary structure not found.", refan != null);
299     assertTrue("Couldn't find 1a70 null chain", sq != null);
300     // compare the manually added temperature factor annotation
301     // to the track automatically transferred from the pdb structure on load
302     for (AlignmentAnnotation ala : sq.getDatasetSequence().getAnnotation())
303     {
304       AlignmentAnnotation alaa;
305       sq.addAlignmentAnnotation(alaa = new AlignmentAnnotation(ala));
306       alaa.adjustForAlignment();
307       if (ala.graph == refan.graph)
308       {
309         for (int p = 0; p < ala.annotations.length; p++)
310         {
311           sq.findPosition(p);
312           try
313           {
314             assertTrue(
315                     "Mismatch at alignment position " + p,
316                     (alaa.annotations[p] == null && refan.annotations[p] == null)
317                             || alaa.annotations[p].value == refan.annotations[p].value);
318           } catch (NullPointerException q)
319           {
320             Assert.fail("Mismatch of alignment annotations at position "
321                     + p + " Ref seq ann: " + refan.annotations[p]
322                     + " alignment " + alaa.annotations[p]);
323           }
324         }
325       }
326     }
327
328   }
329
330   @Test(groups = { "Functional" })
331   public void testCopyViewSettings() throws Exception
332   {
333     AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
334             "examples/exampleFile_2_7.jar", FormatAdapter.FILE);
335     assertTrue("Didn't read in the example file correctly.", af != null);
336     AlignmentViewPanel sps = null, groups = null;
337     for (AlignmentViewPanel ap : af.alignPanel.alignFrame.getAlignPanels())
338     {
339       if ("Spinach Feredoxin Structure".equals(ap.getViewName()))
340       {
341         sps = ap;
342       }
343       if (ap.getViewName().contains("MAFFT"))
344       {
345         groups = ap;
346       }
347     }
348     assertTrue("Couldn't find the structure view", sps != null);
349     assertTrue("Couldn't find the MAFFT view", groups != null);
350
351     ViewStyleI structureStyle = sps.getAlignViewport().getViewStyle();
352     ViewStyleI groupStyle = groups.getAlignViewport().getViewStyle();
353     AssertJUnit.assertFalse(structureStyle.sameStyle(groupStyle));
354
355     groups.getAlignViewport().setViewStyle(structureStyle);
356     AssertJUnit.assertFalse(groupStyle.sameStyle(groups.getAlignViewport()
357             .getViewStyle()));
358     Assert.assertTrue(structureStyle.sameStyle(groups.getAlignViewport()
359             .getViewStyle()));
360
361   }
362
363   /**
364    * test store and recovery of expanded views - currently this is disabled
365    * since the Desktop.explodeViews method doesn't seem to result in the views
366    * being expanded to distinct align frames when executed programmatically.
367    * 
368    * @throws Exception
369    */
370   @Test(groups = { "Functional" }, enabled = true)
371   public void testStoreAndRecoverExpandedviews() throws Exception
372   {
373     AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
374             "examples/exampleFile_2_7.jar", FormatAdapter.FILE);
375     assertTrue("Didn't read in the example file correctly.", af != null);
376     String afid = af.getViewport().getSequenceSetId();
377     {
378       final AlignFrame xaf = af;
379       af = null;
380       new Thread(new Runnable()
381       {
382         @Override
383         public void run()
384         {
385           Desktop.instance.explodeViews(xaf);
386         }
387       }).start();
388       Thread.sleep(1000);
389     }
390     // int times = 0;
391     // while (++times < 5 && Desktop.getAlignFrames().length < )
392     // {
393     // Thread.sleep(300);
394     // }
395     int oldviews = Desktop.getAlignFrames().length;
396     Assert.assertEquals(Desktop.getAlignFrames().length,
397             Desktop.getAlignmentPanels(afid).length);
398     File tfile = File.createTempFile("testStoreAndRecoverExpanded", ".jvp");
399     try
400     {
401       new Jalview2XML(false).saveState(tfile);
402     } catch (Error e)
403     {
404       Assert.fail("Didn't save the expanded view state", e);
405     } catch (Exception e)
406     {
407       Assert.fail("Didn't save the expanded view state", e);
408     }
409     Desktop.instance.closeAll_actionPerformed(null);
410     if (Desktop.getAlignFrames() != null)
411     {
412       Assert.assertEquals(Desktop.getAlignFrames().length, 0);
413     }
414     af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
415             tfile.getAbsolutePath(), FormatAdapter.FILE);
416     Assert.assertNotNull(af);
417     Assert.assertEquals(
418             Desktop.getAlignFrames().length,
419             Desktop.getAlignmentPanels(af.getViewport().getSequenceSetId()).length);
420     Assert.assertEquals(
421             oldviews,
422             Desktop.getAlignmentPanels(af.getViewport().getSequenceSetId()).length);
423   }
424
425   /**
426    * Test save and reload of a project with a different representative sequence
427    * in each view.
428    * 
429    * @throws Exception
430    */
431   @Test(groups = { "Functional" })
432   public void testStoreAndRecoverReferenceSeqSettings() throws Exception
433   {
434     Desktop.instance.closeAll_actionPerformed(null);
435     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
436             "examples/exampleFile_2_7.jar", FormatAdapter.FILE);
437     assertTrue("Didn't read in the example file correctly.", af != null);
438     String afid = af.getViewport().getSequenceSetId();
439
440     /*
441      * remember representative and hidden sequences marked 
442      * on each panel
443      */
444     Map<String, SequenceI> refseqs = new HashMap<String, SequenceI>();
445     Map<String, List<String>> hiddenSeqNames = new HashMap<String, List<String>>();
446
447     /*
448      * mark sequence 2, 3, 4.. in panels 1, 2, 3...
449      * as reference sequence for itself and the preceding sequence
450      */
451     int n = 1;
452     for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
453     {
454       AlignViewportI av = ap.getAlignViewport();
455       AlignmentI alignment = ap.getAlignment();
456       int repIndex = n % alignment.getHeight();
457       SequenceI rep = alignment.getSequenceAt(repIndex);
458       refseqs.put(ap.getViewName(), rep);
459       List<String> hiddenNames = new ArrayList<String>();
460       hiddenSeqNames.put(ap.getViewName(), hiddenNames);
461
462       /*
463        * hide rep sequence and the one before it
464        */
465       SequenceI seqToHide = alignment.getSequenceAt(repIndex);
466       SequenceGroup sg = new SequenceGroup();
467       sg.addSequence(seqToHide, false);
468       SequenceI precedingSeq = alignment.getSequenceAt(repIndex - 1);
469       sg.addSequence(precedingSeq, false);
470       av.setSelectionGroup(sg);
471       ((AlignmentViewport) av).hideSequences(seqToHide, true);
472
473       /*
474        * record names of hidden sequences
475        */
476       HiddenSequences hs = alignment.getHiddenSequences();
477       for (SequenceI seq : hs.hiddenSequences)
478       {
479         if (seq != null)
480         {
481           hiddenNames.add(seq.getName());
482         }
483       }
484       // code from mark/unmark sequence as reference in jalview.gui.PopupMenu
485       // todo refactor this to an alignment view controller
486       av.setDisplayReferenceSeq(true);
487       av.setColourByReferenceSeq(true);
488       av.getAlignment().setSeqrep(rep);
489
490       n++;
491     }
492     File tfile = File.createTempFile("testStoreAndRecoverReferenceSeq",
493             ".jvp");
494     try
495     {
496       new Jalview2XML(false).saveState(tfile);
497     } catch (Throwable e)
498     {
499       Assert.fail("Didn't save the expanded view state", e);
500     }
501     Desktop.instance.closeAll_actionPerformed(null);
502     if (Desktop.getAlignFrames() != null)
503     {
504       Assert.assertEquals(Desktop.getAlignFrames().length, 0);
505     }
506
507     af = new FileLoader().LoadFileWaitTillLoaded(
508             tfile.getAbsolutePath(), FormatAdapter.FILE);
509     afid = af.getViewport().getSequenceSetId();
510
511     for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
512     {
513       // check representative
514       AlignmentI alignment = ap.getAlignment();
515       SequenceI rep = alignment.getSeqrep();
516       Assert.assertNotNull(rep,
517               "Couldn't restore sequence representative from project");
518       // can't use a strong equals here, because by definition, the sequence IDs
519       // will be different.
520       // could set vamsas session save/restore flag to preserve IDs across
521       // load/saves.
522       Assert.assertEquals(refseqs.get(ap.getViewName()).toString(),
523               rep.toString(),
524               "Representative wasn't the same when recovered.");
525       Assert.assertTrue(ap.getAlignViewport().isDisplayReferenceSeq(),
526               "Display reference sequence view setting not set.");
527       Assert.assertTrue(ap.getAlignViewport().isColourByReferenceSeq(),
528               "Colour By Reference Seq view setting not set.");
529
530       /*
531        * verify hidden sequences in restored panel
532        */
533       List<String> hidden = hiddenSeqNames.get(ap.getViewName());
534       HiddenSequences hs = alignment.getHiddenSequences();
535       assertEquals(
536               "wrong number of restored hidden sequences in "
537                       + ap.getViewName(),
538               hidden.size(), hs.getSize());
539     }
540   }
541
542   @Test(groups = { "Functional" })
543   public void testIsVersionStringLaterThan()
544   {
545     /*
546      * No version / development / test / autobuild is leniently assumed to be
547      * compatible
548      */
549     assertTrue(Jalview2XML.isVersionStringLaterThan(null, null));
550     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", null));
551     assertTrue(Jalview2XML.isVersionStringLaterThan(null, "2.8.3"));
552     assertTrue(Jalview2XML.isVersionStringLaterThan(null,
553             "Development Build"));
554     assertTrue(Jalview2XML.isVersionStringLaterThan(null,
555             "DEVELOPMENT BUILD"));
556     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3",
557             "Development Build"));
558     assertTrue(Jalview2XML.isVersionStringLaterThan(null, "Test"));
559     assertTrue(Jalview2XML.isVersionStringLaterThan(null, "TEST"));
560     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "Test"));
561     assertTrue(Jalview2XML
562             .isVersionStringLaterThan(null, "Automated Build"));
563     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3",
564             "Automated Build"));
565     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3",
566             "AUTOMATED BUILD"));
567
568     /*
569      * same version returns true i.e. compatible
570      */
571     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8", "2.8"));
572     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8.3"));
573     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3b1", "2.8.3b1"));
574     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3B1", "2.8.3b1"));
575     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3b1", "2.8.3B1"));
576
577     /*
578      * later version returns true
579      */
580     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8.4"));
581     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.9"));
582     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.9.2"));
583     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8", "2.8.3"));
584     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8.3b1"));
585
586     /*
587      * earlier version returns false
588      */
589     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8"));
590     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.4", "2.8.3"));
591     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.3b1", "2.8.3"));
592     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8.2b1"));
593     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.0b2", "2.8.0b1"));
594   }
595 }