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