JAL-1713 don’t close an automatically created overview window for projects from Jalvi...
[jalview.git] / test / jalview / project / 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.project;
22
23 import static org.testng.Assert.assertEquals;
24 import static org.testng.Assert.assertFalse;
25 import static org.testng.Assert.assertNotNull;
26 import static org.testng.Assert.assertNotSame;
27 import static org.testng.Assert.assertNull;
28 import static org.testng.Assert.assertSame;
29 import static org.testng.Assert.assertTrue;
30
31 import java.awt.Color;
32 import java.awt.Rectangle;
33 import java.io.File;
34 import java.io.IOException;
35 import java.util.ArrayList;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Locale;
39 import java.util.Map;
40
41 import javax.swing.JInternalFrame;
42
43 import org.testng.Assert;
44 import org.testng.AssertJUnit;
45 import org.testng.annotations.BeforeClass;
46 import org.testng.annotations.Test;
47
48 import jalview.analysis.scoremodels.SimilarityParams;
49 import jalview.api.AlignViewportI;
50 import jalview.api.AlignmentViewPanel;
51 import jalview.api.FeatureColourI;
52 import jalview.api.ViewStyleI;
53 import jalview.bin.Cache;
54 import jalview.datamodel.AlignmentAnnotation;
55 import jalview.datamodel.AlignmentI;
56 import jalview.datamodel.Annotation;
57 import jalview.datamodel.DBRefEntry;
58 import jalview.datamodel.GeneLocus;
59 import jalview.datamodel.HiddenSequences;
60 import jalview.datamodel.Mapping;
61 import jalview.datamodel.PDBEntry;
62 import jalview.datamodel.PDBEntry.Type;
63 import jalview.datamodel.Sequence.DBModList;
64 import jalview.datamodel.SequenceCollectionI;
65 import jalview.datamodel.SequenceFeature;
66 import jalview.datamodel.SequenceGroup;
67 import jalview.datamodel.SequenceI;
68 import jalview.datamodel.features.FeatureMatcher;
69 import jalview.datamodel.features.FeatureMatcherSet;
70 import jalview.datamodel.features.FeatureMatcherSetI;
71 import jalview.gui.AlignFrame;
72 import jalview.gui.AlignViewport;
73 import jalview.gui.AlignmentPanel;
74 import jalview.gui.Desktop;
75 import jalview.gui.JvOptionPane;
76 import jalview.gui.OverviewPanel;
77 import jalview.gui.PCAPanel;
78 import jalview.gui.PopupMenu;
79 import jalview.gui.Preferences;
80 import jalview.gui.SliderPanel;
81 import jalview.io.DataSourceType;
82 import jalview.io.FileFormat;
83 import jalview.io.FileLoader;
84 import jalview.io.Jalview2xmlBase;
85 import jalview.renderer.ResidueShaderI;
86 import jalview.schemes.AnnotationColourGradient;
87 import jalview.schemes.BuriedColourScheme;
88 import jalview.schemes.ColourSchemeI;
89 import jalview.schemes.ColourSchemeProperty;
90 import jalview.schemes.FeatureColour;
91 import jalview.schemes.JalviewColourScheme;
92 import jalview.schemes.RNAHelicesColour;
93 import jalview.schemes.StrandColourScheme;
94 import jalview.schemes.TCoffeeColourScheme;
95 import jalview.structure.StructureImportSettings;
96 import jalview.util.MapList;
97 import jalview.util.matcher.Condition;
98 import jalview.viewmodel.AlignmentViewport;
99 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
100
101 @Test(singleThreaded = true)
102 public class Jalview2xmlTests extends Jalview2xmlBase
103 {
104
105   @Override
106   @BeforeClass(alwaysRun = true)
107   public void setUpJvOptionPane()
108   {
109     JvOptionPane.setInteractiveMode(false);
110     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
111   }
112
113   @Test(groups = { "Functional" })
114   public void testRNAStructureRecovery() throws Exception
115   {
116     String inFile = "examples/RF00031_folded.stk";
117     String tfile = File.createTempFile("JalviewTest", ".jvp")
118             .getAbsolutePath();
119     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
120             DataSourceType.FILE);
121     assertNotNull(af, "Didn't read input file " + inFile);
122     int olddsann = countDsAnn(af.getViewport());
123     assertTrue(olddsann > 0, "Didn't find any dataset annotations");
124     af.changeColour_actionPerformed(
125             JalviewColourScheme.RNAHelices.toString());
126     assertTrue(
127             af.getViewport()
128                     .getGlobalColourScheme() instanceof RNAHelicesColour,
129             "Couldn't apply RNA helices colourscheme");
130     af.saveAlignment(tfile, FileFormat.Jalview);
131     assertTrue(af.isSaveAlignmentSuccessful(),
132             "Failed to store as a project.");
133     af.closeMenuItem_actionPerformed(true);
134     af = null;
135     af = new FileLoader().LoadFileWaitTillLoaded(tfile,
136             DataSourceType.FILE);
137     assertNotNull(af, "Failed to import new project");
138     int newdsann = countDsAnn(af.getViewport());
139     assertEquals(olddsann, newdsann,
140             "Differing numbers of dataset sequence annotation\nOriginally "
141                     + olddsann + " and now " + newdsann);
142     System.out.println(
143             "Read in same number of annotations as originally present ("
144                     + olddsann + ")");
145     assertTrue(
146
147             af.getViewport()
148                     .getGlobalColourScheme() instanceof RNAHelicesColour,
149             "RNA helices colourscheme was not applied on import.");
150   }
151
152   @Test(groups = { "Functional" })
153   public void testTCoffeeScores() throws Exception
154   {
155     String inFile = "examples/uniref50.fa",
156             inAnnot = "examples/uniref50.score_ascii";
157     String tfile = File.createTempFile("JalviewTest", ".jvp")
158             .getAbsolutePath();
159     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
160             DataSourceType.FILE);
161     assertNotNull(af, "Didn't read input file " + inFile);
162     af.loadJalviewDataFile(inAnnot, DataSourceType.FILE, null, null);
163     AlignViewport viewport = af.getViewport();
164     assertSame(viewport.getGlobalColourScheme().getClass(),
165             TCoffeeColourScheme.class, "Didn't set T-coffee colourscheme");
166     assertNotNull(
167             ColourSchemeProperty.getColourScheme(viewport,
168                     viewport.getAlignment(),
169                     viewport.getGlobalColourScheme().getSchemeName()),
170             "Recognise T-Coffee score from string");
171
172     af.saveAlignment(tfile, FileFormat.Jalview);
173     assertTrue(af.isSaveAlignmentSuccessful(),
174             "Failed to store as a project.");
175     af.closeMenuItem_actionPerformed(true);
176     af = null;
177     af = new FileLoader().LoadFileWaitTillLoaded(tfile,
178             DataSourceType.FILE);
179     assertNotNull(af, "Failed to import new project");
180     assertSame(af.getViewport().getGlobalColourScheme().getClass(),
181             TCoffeeColourScheme.class,
182             "Didn't set T-coffee colourscheme for imported project.");
183     System.out.println(
184             "T-Coffee score shading successfully recovered from project.");
185   }
186
187   @Test(groups = { "Functional" })
188   public void testColourByAnnotScores() throws Exception
189   {
190     String inFile = "examples/uniref50.fa",
191             inAnnot = "examples/testdata/uniref50_iupred.jva";
192     String tfile = File.createTempFile("JalviewTest", ".jvp")
193             .getAbsolutePath();
194     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
195             DataSourceType.FILE);
196     assertNotNull(af, "Didn't read input file " + inFile);
197     af.loadJalviewDataFile(inAnnot, DataSourceType.FILE, null, null);
198     AlignmentAnnotation[] aa = af.getViewport().getAlignment()
199             .getSequenceAt(0).getAnnotation("IUPredWS (Short)");
200     assertTrue(
201
202             aa != null && aa.length > 0,
203             "Didn't find any IUPred annotation to use to shade alignment.");
204     AnnotationColourGradient cs = new AnnotationColourGradient(aa[0], null,
205             AnnotationColourGradient.ABOVE_THRESHOLD);
206     AnnotationColourGradient gcs = new AnnotationColourGradient(aa[0], null,
207             AnnotationColourGradient.BELOW_THRESHOLD);
208     cs.setSeqAssociated(true);
209     gcs.setSeqAssociated(true);
210     af.changeColour(cs);
211     SequenceGroup sg = new SequenceGroup();
212     sg.setStartRes(57);
213     sg.setEndRes(92);
214     sg.cs.setColourScheme(gcs);
215     af.getViewport().getAlignment().addGroup(sg);
216     sg.addSequence(af.getViewport().getAlignment().getSequenceAt(1), false);
217     sg.addSequence(af.getViewport().getAlignment().getSequenceAt(2), true);
218     af.alignPanel.alignmentChanged();
219     af.saveAlignment(tfile, FileFormat.Jalview);
220     assertTrue(af.isSaveAlignmentSuccessful(),
221             "Failed to store as a project.");
222     af.closeMenuItem_actionPerformed(true);
223     af = null;
224     af = new FileLoader().LoadFileWaitTillLoaded(tfile,
225             DataSourceType.FILE);
226     assertNotNull(af, "Failed to import new project");
227
228     // check for group and alignment colourschemes
229
230     ColourSchemeI _rcs = af.getViewport().getGlobalColourScheme();
231     ColourSchemeI _rgcs = af.getViewport().getAlignment().getGroups().get(0)
232             .getColourScheme();
233     assertNotNull(_rcs, "Didn't recover global colourscheme");
234     assertTrue(_rcs instanceof AnnotationColourGradient,
235             "Didn't recover annotation colour global scheme");
236     AnnotationColourGradient __rcs = (AnnotationColourGradient) _rcs;
237     assertTrue(__rcs.isSeqAssociated(),
238             "Annotation colourscheme wasn't sequence associated");
239
240     boolean diffseqcols = false, diffgseqcols = false;
241     SequenceI[] sqs = af.getViewport().getAlignment().getSequencesArray();
242     for (int p = 0,
243             pSize = af.getViewport().getAlignment().getWidth(); p < pSize
244                     && (!diffseqcols || !diffgseqcols); p++)
245     {
246       if (_rcs.findColour(sqs[0].getCharAt(p), p, sqs[0], null, 0f) != _rcs
247               .findColour(sqs[5].getCharAt(p), p, sqs[5], null, 0f))
248       {
249         diffseqcols = true;
250       }
251     }
252     assertTrue(diffseqcols, "Got Different sequence colours");
253     System.out.println(
254             "Per sequence colourscheme (Background) successfully applied and recovered.");
255
256     assertNotNull(_rgcs, "Didn't recover group colourscheme");
257     assertTrue(_rgcs instanceof AnnotationColourGradient,
258             "Didn't recover annotation colour group colourscheme");
259     __rcs = (AnnotationColourGradient) _rgcs;
260     assertTrue(__rcs.isSeqAssociated(),
261             "Group Annotation colourscheme wasn't sequence associated");
262
263     for (int p = 0,
264             pSize = af.getViewport().getAlignment().getWidth(); p < pSize
265                     && (!diffseqcols || !diffgseqcols); p++)
266     {
267       if (_rgcs.findColour(sqs[1].getCharAt(p), p, sqs[1], null,
268               0f) != _rgcs.findColour(sqs[2].getCharAt(p), p, sqs[2], null,
269                       0f))
270       {
271         diffgseqcols = true;
272       }
273     }
274     assertTrue(diffgseqcols, "Got Different group sequence colours");
275     System.out.println(
276             "Per sequence (Group) colourscheme successfully applied and recovered.");
277   }
278
279   @Test(groups = { "Functional" })
280   public void gatherViewsHere() throws Exception
281   {
282     int origCount = Desktop.getAlignFrames() == null ? 0
283             : Desktop.getAlignFrames().length;
284     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
285             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
286     assertNotNull(af, "Didn't read in the example file correctly.");
287     assertTrue(Desktop.getAlignFrames().length == 1 + origCount,
288             "Didn't gather the views in the example file.");
289
290   }
291
292   /**
293    * Test for JAL-2223 - multiple mappings in View Mapping report
294    * 
295    * @throws Exception
296    */
297   @Test(groups = { "Functional" })
298   public void noDuplicatePdbMappingsMade() throws Exception
299   {
300     StructureImportSettings.setProcessSecondaryStructure(true);
301     StructureImportSettings.setVisibleChainAnnotation(true);
302     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
303             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
304     assertNotNull(af, "Didn't read in the example file correctly.");
305
306     // locate Jmol viewer
307     // count number of PDB mappings the structure selection manager holds -
308     String pdbFile = af.getCurrentView().getStructureSelectionManager()
309             .findFileForPDBId("1A70");
310     assertEquals(
311             af.getCurrentView().getStructureSelectionManager()
312                     .getMapping(pdbFile).length,
313             2, "Expected only two mappings for 1A70");
314
315   }
316
317   @Test(groups = { "Functional" })
318   public void viewRefPdbAnnotation() throws Exception
319   {
320     StructureImportSettings.setProcessSecondaryStructure(true);
321     StructureImportSettings.setVisibleChainAnnotation(true);
322     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
323             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
324     assertNotNull(af, "Didn't read in the example file correctly.");
325     AlignmentViewPanel sps = null;
326     for (AlignmentViewPanel ap : af.alignPanel.alignFrame.getAlignPanels())
327     {
328       if ("Spinach Feredoxin Structure".equals(ap.getViewName()))
329       {
330         sps = ap;
331         break;
332       }
333     }
334     assertNotNull(sps, "Couldn't find the structure view");
335     AlignmentAnnotation refan = null;
336     for (AlignmentAnnotation ra : sps.getAlignment()
337             .getAlignmentAnnotation())
338     {
339       if (ra.graph != 0)
340       {
341         refan = ra;
342         break;
343       }
344     }
345     assertNotNull(refan, "Annotation secondary structure not found.");
346     SequenceI sq = sps.getAlignment().findName("1A70|");
347     assertNotNull(sq, "Couldn't find 1a70 null chain");
348     // compare the manually added temperature factor annotation
349     // to the track automatically transferred from the pdb structure on load
350     assertNotNull(sq.getDatasetSequence().getAnnotation(),
351             "1a70 has no annotation");
352     for (AlignmentAnnotation ala : sq.getDatasetSequence().getAnnotation())
353     {
354       AlignmentAnnotation alaa;
355       sq.addAlignmentAnnotation(alaa = new AlignmentAnnotation(ala));
356       alaa.adjustForAlignment();
357       if (ala.graph == refan.graph)
358       {
359         for (int p = 0; p < ala.annotations.length; p++)
360         {
361           sq.findPosition(p);
362           try
363           {
364             assertTrue((alaa.annotations[p] == null
365                     && refan.annotations[p] == null)
366                     || alaa.annotations[p].value == refan.annotations[p].value,
367                     "Mismatch at alignment position " + p);
368           } catch (NullPointerException q)
369           {
370             Assert.fail("Mismatch of alignment annotations at position " + p
371                     + " Ref seq ann: " + refan.annotations[p]
372                     + " alignment " + alaa.annotations[p]);
373           }
374         }
375       }
376     }
377
378   }
379
380   @Test(groups = { "Functional" })
381   public void testCopyViewSettings() throws Exception
382   {
383     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
384             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
385     assertNotNull(af, "Didn't read in the example file correctly.");
386     AlignmentViewPanel sps = null, groups = null;
387     for (AlignmentViewPanel ap : af.alignPanel.alignFrame.getAlignPanels())
388     {
389       if ("Spinach Feredoxin Structure".equals(ap.getViewName()))
390       {
391         sps = ap;
392       }
393       if (ap.getViewName().contains("MAFFT"))
394       {
395         groups = ap;
396       }
397     }
398     assertNotNull(sps, "Couldn't find the structure view");
399     assertNotNull(groups, "Couldn't find the MAFFT view");
400
401     ViewStyleI structureStyle = sps.getAlignViewport().getViewStyle();
402     ViewStyleI groupStyle = groups.getAlignViewport().getViewStyle();
403     AssertJUnit.assertFalse(structureStyle.sameStyle(groupStyle));
404
405     groups.getAlignViewport().setViewStyle(structureStyle);
406     AssertJUnit.assertFalse(
407             groupStyle.sameStyle(groups.getAlignViewport().getViewStyle()));
408     Assert.assertTrue(structureStyle
409             .sameStyle(groups.getAlignViewport().getViewStyle()));
410
411   }
412
413   /**
414    * test store and recovery of expanded views
415    * 
416    * @throws Exception
417    */
418   @Test(groups = { "Functional" }, enabled = true)
419   public void testStoreAndRecoverExpandedviews() throws Exception
420   {
421     Desktop.instance.closeAll_actionPerformed(null);
422
423     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
424             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
425     Assert.assertEquals(Desktop.getAlignFrames().length, 1);
426     String afid = af.getViewport().getSequenceSetId();
427
428     // check FileLoader returned a reference to the one alignFrame that is
429     // actually on the Desktop
430     assertSame(af, Desktop.getAlignFrameFor(af.getViewport()),
431             "Jalview2XML.loadAlignFrame() didn't return correct AlignFrame reference for multiple view window");
432
433     Desktop.explodeViews(af);
434
435     int oldviews = Desktop.getAlignFrames().length;
436     Assert.assertEquals(Desktop.getAlignFrames().length,
437             Desktop.getAlignmentPanels(afid).length);
438     File tfile = File.createTempFile("testStoreAndRecoverExpanded", ".jvp");
439     try
440     {
441       new Jalview2XML(false).saveState(tfile);
442     } catch (Error e)
443     {
444       Assert.fail("Didn't save the expanded view state", e);
445     } catch (Exception e)
446     {
447       Assert.fail("Didn't save the expanded view state", e);
448     }
449     Desktop.instance.closeAll_actionPerformed(null);
450     if (Desktop.getAlignFrames() != null)
451     {
452       Assert.assertEquals(Desktop.getAlignFrames().length, 0);
453     }
454     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
455             DataSourceType.FILE);
456     Assert.assertNotNull(af);
457     Assert.assertEquals(Desktop.getAlignFrames().length,
458             Desktop.getAlignmentPanels(
459                     af.getViewport().getSequenceSetId()).length);
460     Assert.assertEquals(Desktop
461             .getAlignmentPanels(af.getViewport().getSequenceSetId()).length,
462             oldviews);
463   }
464
465   /**
466    * Test save and reload of a project with a different representative sequence
467    * in each view.
468    * 
469    * @throws Exception
470    */
471   @Test(groups = { "Functional" })
472   public void testStoreAndRecoverReferenceSeqSettings() throws Exception
473   {
474     Desktop.instance.closeAll_actionPerformed(null);
475     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
476             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
477     assertNotNull(af, "Didn't read in the example file correctly.");
478     String afid = af.getViewport().getSequenceSetId();
479
480     // remember reference sequence for each panel
481     Map<String, SequenceI> refseqs = new HashMap<>();
482
483     /*
484      * mark sequence 2, 3, 4.. in panels 1, 2, 3...
485      * as reference sequence for itself and the preceding sequence
486      */
487     int n = 1;
488     for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
489     {
490       AlignViewportI av = ap.getAlignViewport();
491       AlignmentI alignment = ap.getAlignment();
492       int repIndex = n % alignment.getHeight();
493       SequenceI rep = alignment.getSequenceAt(repIndex);
494       refseqs.put(ap.getViewName(), rep);
495
496       // code from mark/unmark sequence as reference in jalview.gui.PopupMenu
497       // todo refactor this to an alignment view controller
498       av.setDisplayReferenceSeq(true);
499       av.setColourByReferenceSeq(true);
500       av.getAlignment().setSeqrep(rep);
501
502       n++;
503     }
504     File tfile = File.createTempFile("testStoreAndRecoverReferenceSeq",
505             ".jvp");
506     try
507     {
508       new Jalview2XML(false).saveState(tfile);
509     } catch (Throwable e)
510     {
511       Assert.fail("Didn't save the expanded view state", e);
512     }
513     Desktop.instance.closeAll_actionPerformed(null);
514     if (Desktop.getAlignFrames() != null)
515     {
516       Assert.assertEquals(Desktop.getAlignFrames().length, 0);
517     }
518
519     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
520             DataSourceType.FILE);
521     afid = af.getViewport().getSequenceSetId();
522
523     for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
524     {
525       // check representative
526       AlignmentI alignment = ap.getAlignment();
527       SequenceI rep = alignment.getSeqrep();
528       Assert.assertNotNull(rep,
529               "Couldn't restore sequence representative from project");
530       // can't use a strong equals here, because by definition, the sequence IDs
531       // will be different.
532       // could set vamsas session save/restore flag to preserve IDs across
533       // load/saves.
534       Assert.assertEquals(refseqs.get(ap.getViewName()).toString(),
535               rep.toString(),
536               "Representative wasn't the same when recovered.");
537       Assert.assertTrue(ap.getAlignViewport().isDisplayReferenceSeq(),
538               "Display reference sequence view setting not set.");
539       Assert.assertTrue(ap.getAlignViewport().isColourByReferenceSeq(),
540               "Colour By Reference Seq view setting not set.");
541     }
542   }
543
544   @Test(groups = { "Functional" })
545   public void testIsVersionStringLaterThan()
546   {
547     /*
548      * No version / development / test / autobuild is leniently assumed to be
549      * compatible
550      */
551     assertTrue(Jalview2XML.isVersionStringLaterThan(null, null));
552     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", null));
553     assertTrue(Jalview2XML.isVersionStringLaterThan(null, "2.8.3"));
554     assertTrue(Jalview2XML.isVersionStringLaterThan(null,
555             "Development Build"));
556     assertTrue(Jalview2XML.isVersionStringLaterThan(null,
557             "DEVELOPMENT BUILD"));
558     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3",
559             "Development Build"));
560     assertTrue(Jalview2XML.isVersionStringLaterThan(null, "Test"));
561     assertTrue(Jalview2XML.isVersionStringLaterThan(null, "TEST"));
562     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "Test"));
563     assertTrue(
564             Jalview2XML.isVersionStringLaterThan(null, "Automated Build"));
565     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3",
566             "Automated Build"));
567     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3",
568             "AUTOMATED BUILD"));
569
570     /*
571      * same version returns true i.e. compatible
572      */
573     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8", "2.8"));
574     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8.3"));
575     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3b1", "2.8.3b1"));
576     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3B1", "2.8.3b1"));
577     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3b1", "2.8.3B1"));
578
579     /*
580      * later version returns true
581      */
582     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8.4"));
583     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.9"));
584     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.9.2"));
585     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8", "2.8.3"));
586     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8.3b1"));
587
588     /*
589      * earlier version returns false
590      */
591     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8"));
592     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.4", "2.8.3"));
593     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.3b1", "2.8.3"));
594     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8.2b1"));
595     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.0b2", "2.8.0b1"));
596     /*
597      * test for patch release versions
598      */
599     assertFalse(Jalview2XML.isVersionStringLaterThan("2.11.3.0", "2.11.2"));
600     assertTrue(Jalview2XML.isVersionStringLaterThan("2.11.3.0","2.11.4"));
601     assertFalse(Jalview2XML.isVersionStringLaterThan("2.12.2.0b1","2.12.2.0"));
602     assertFalse(Jalview2XML.isVersionStringLaterThan("2.12.2.3","2.12.2.2"));
603
604   }
605
606   /**
607    * Test save and reload of a project with a different sequence group (and
608    * representative sequence) in each view.
609    * 
610    * @throws Exception
611    */
612   @Test(groups = { "Functional" })
613   public void testStoreAndRecoverGroupRepSeqs() throws Exception
614   {
615     Desktop.instance.closeAll_actionPerformed(null);
616     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
617             "examples/uniref50.fa", DataSourceType.FILE);
618     assertNotNull(af, "Didn't read in the example file correctly.");
619     String afid = af.getViewport().getSequenceSetId();
620     // make a second view of the alignment
621     af.newView_actionPerformed(null);
622
623     /*
624      * remember representative and hidden sequences marked 
625      * on each panel
626      */
627     Map<String, SequenceI> repSeqs = new HashMap<>();
628     Map<String, List<String>> hiddenSeqNames = new HashMap<>();
629
630     /*
631      * mark sequence 2, 3, 4.. in panels 1, 2, 3...
632      * as reference sequence for itself and the preceding sequence
633      */
634     int n = 1;
635     for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
636     {
637       AlignViewportI av = ap.getAlignViewport();
638       AlignmentI alignment = ap.getAlignment();
639       int repIndex = n % alignment.getHeight();
640       // ensure at least one preceding sequence i.e. index >= 1
641       repIndex = Math.max(repIndex, 1);
642       SequenceI repSeq = alignment.getSequenceAt(repIndex);
643       repSeqs.put(ap.getViewName(), repSeq);
644       List<String> hiddenNames = new ArrayList<>();
645       hiddenSeqNames.put(ap.getViewName(), hiddenNames);
646
647       /*
648        * have rep sequence represent itself and the one before it
649        * this hides the group (except for the rep seq)
650        */
651       SequenceGroup sg = new SequenceGroup();
652       sg.addSequence(repSeq, false);
653       SequenceI precedingSeq = alignment.getSequenceAt(repIndex - 1);
654       sg.addSequence(precedingSeq, false);
655       sg.setSeqrep(repSeq);
656       assertTrue(sg.getSequences().contains(repSeq));
657       assertTrue(sg.getSequences().contains(precedingSeq));
658       av.setSelectionGroup(sg);
659       assertSame(repSeq, sg.getSeqrep());
660
661       /*
662        * represent group with sequence adds to a map of hidden rep sequences
663        * (it does not create a group on the alignment) 
664        */
665       ((AlignmentViewport) av).hideSequences(repSeq, true);
666       assertSame(repSeq, sg.getSeqrep());
667       assertTrue(sg.getSequences().contains(repSeq));
668       assertTrue(sg.getSequences().contains(precedingSeq));
669       assertTrue(alignment.getGroups().isEmpty(), "alignment has groups");
670       Map<SequenceI, SequenceCollectionI> hiddenRepSeqsMap = av
671               .getHiddenRepSequences();
672       assertNotNull(hiddenRepSeqsMap);
673       assertEquals(1, hiddenRepSeqsMap.size());
674       assertSame(sg, hiddenRepSeqsMap.get(repSeq));
675       assertTrue(alignment.getHiddenSequences().isHidden(precedingSeq));
676       assertFalse(alignment.getHiddenSequences().isHidden(repSeq));
677       hiddenNames.add(precedingSeq.getName());
678
679       n++;
680     }
681     File tfile = File.createTempFile("testStoreAndRecoverGroupReps",
682             ".jvp");
683     try
684     {
685       new Jalview2XML(false).saveState(tfile);
686     } catch (Throwable e)
687     {
688       Assert.fail("Didn't save the expanded view state", e);
689     }
690     Desktop.instance.closeAll_actionPerformed(null);
691     if (Desktop.getAlignFrames() != null)
692     {
693       Assert.assertEquals(Desktop.getAlignFrames().length, 0);
694     }
695
696     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
697             DataSourceType.FILE);
698     afid = af.getViewport().getSequenceSetId();
699
700     for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
701     {
702       String viewName = ap.getViewName();
703       AlignViewportI av = ap.getAlignViewport();
704       AlignmentI alignment = ap.getAlignment();
705       List<SequenceGroup> groups = alignment.getGroups();
706       assertNotNull(groups);
707       assertTrue(groups.isEmpty(), "Alignment has groups");
708       Map<SequenceI, SequenceCollectionI> hiddenRepSeqsMap = av
709               .getHiddenRepSequences();
710       assertNotNull(hiddenRepSeqsMap, "No hidden represented sequences");
711       assertEquals(1, hiddenRepSeqsMap.size());
712       assertEquals(repSeqs.get(viewName).getDisplayId(true),
713               hiddenRepSeqsMap.keySet().iterator().next()
714                       .getDisplayId(true));
715
716       /*
717        * verify hidden sequences in restored panel
718        */
719       List<String> hidden = hiddenSeqNames.get(ap.getViewName());
720       HiddenSequences hs = alignment.getHiddenSequences();
721       assertEquals(hidden.size(), hs.getSize(),
722               "wrong number of restored hidden sequences in "
723                       + ap.getViewName());
724     }
725   }
726
727   /**
728    * Test save and reload of PDBEntry in Jalview project
729    * 
730    * @throws Exception
731    */
732   @Test(groups = { "Functional" })
733   public void testStoreAndRecoverPDBEntry() throws Exception
734   {
735     Desktop.instance.closeAll_actionPerformed(null);
736     String exampleFile = "examples/3W5V.pdb";
737     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(exampleFile,
738             DataSourceType.FILE);
739     assertNotNull(af, "Didn't read in the example file correctly.");
740     String afid = af.getViewport().getSequenceSetId();
741
742     AlignmentPanel[] alignPanels = Desktop.getAlignmentPanels(afid);
743     System.out.println();
744     AlignmentViewPanel ap = alignPanels[0];
745     String tfileBase = new File(".").getAbsolutePath().replace(".", "");
746     String testFile = tfileBase + exampleFile;
747     AlignmentI alignment = ap.getAlignment();
748     System.out.println("blah");
749     SequenceI[] seqs = alignment.getSequencesArray();
750     Assert.assertNotNull(seqs[0]);
751     Assert.assertNotNull(seqs[1]);
752     Assert.assertNotNull(seqs[2]);
753     Assert.assertNotNull(seqs[3]);
754     Assert.assertNotNull(seqs[0].getDatasetSequence());
755     Assert.assertNotNull(seqs[1].getDatasetSequence());
756     Assert.assertNotNull(seqs[2].getDatasetSequence());
757     Assert.assertNotNull(seqs[3].getDatasetSequence());
758     PDBEntry[] pdbEntries = new PDBEntry[4];
759     pdbEntries[0] = new PDBEntry("3W5V", "A", Type.PDB, testFile);
760     pdbEntries[1] = new PDBEntry("3W5V", "B", Type.PDB, testFile);
761     pdbEntries[2] = new PDBEntry("3W5V", "C", Type.PDB, testFile);
762     pdbEntries[3] = new PDBEntry("3W5V", "D", Type.PDB, testFile);
763     Assert.assertEquals(
764             seqs[0].getDatasetSequence().getAllPDBEntries().get(0),
765             pdbEntries[0]);
766     Assert.assertEquals(
767             seqs[1].getDatasetSequence().getAllPDBEntries().get(0),
768             pdbEntries[1]);
769     Assert.assertEquals(
770             seqs[2].getDatasetSequence().getAllPDBEntries().get(0),
771             pdbEntries[2]);
772     Assert.assertEquals(
773             seqs[3].getDatasetSequence().getAllPDBEntries().get(0),
774             pdbEntries[3]);
775
776     File tfile = File.createTempFile("testStoreAndRecoverPDBEntry", ".jvp");
777     try
778     {
779       new Jalview2XML(false).saveState(tfile);
780     } catch (Throwable e)
781     {
782       Assert.fail("Didn't save the state", e);
783     }
784     Desktop.instance.closeAll_actionPerformed(null);
785     if (Desktop.getAlignFrames() != null)
786     {
787       Assert.assertEquals(Desktop.getAlignFrames().length, 0);
788     }
789
790     AlignFrame restoredFrame = new FileLoader().LoadFileWaitTillLoaded(
791             tfile.getAbsolutePath(), DataSourceType.FILE);
792     String rfid = restoredFrame.getViewport().getSequenceSetId();
793     AlignmentPanel[] rAlignPanels = Desktop.getAlignmentPanels(rfid);
794     AlignmentViewPanel rap = rAlignPanels[0];
795     AlignmentI rAlignment = rap.getAlignment();
796     System.out.println("blah");
797     SequenceI[] rseqs = rAlignment.getSequencesArray();
798     Assert.assertNotNull(rseqs[0]);
799     Assert.assertNotNull(rseqs[1]);
800     Assert.assertNotNull(rseqs[2]);
801     Assert.assertNotNull(rseqs[3]);
802     Assert.assertNotNull(rseqs[0].getDatasetSequence());
803     Assert.assertNotNull(rseqs[1].getDatasetSequence());
804     Assert.assertNotNull(rseqs[2].getDatasetSequence());
805     Assert.assertNotNull(rseqs[3].getDatasetSequence());
806
807     // The Asserts below are expected to fail until the PDB chainCode is
808     // recoverable from a Jalview projects
809     for (int chain = 0; chain < 4; chain++)
810     {
811       PDBEntry recov = rseqs[chain].getDatasetSequence().getAllPDBEntries()
812               .get(0);
813       PDBEntry expected = pdbEntries[chain];
814       Assert.assertEquals(recov.getId(), expected.getId(),
815               "Mismatch PDB ID");
816       Assert.assertEquals(recov.getChainCode(), expected.getChainCode(),
817               "Mismatch PDB ID");
818       Assert.assertEquals(recov.getType(), expected.getType(),
819               "Mismatch PDBEntry 'Type'");
820       Assert.assertNotNull(recov.getFile(),
821               "Recovered PDBEntry should have a non-null file entry");
822       Assert.assertEquals(
823               recov.getFile().toLowerCase(Locale.ENGLISH)
824                       .lastIndexOf("pdb"),
825               recov.getFile().length() - 3,
826               "Recovered PDBEntry file should have PDB suffix");
827     }
828   }
829
830   /**
831    * Configure an alignment and a sub-group each with distinct colour schemes,
832    * Conservation and PID thresholds, and confirm these are restored from the
833    * saved project.
834    * 
835    * @throws IOException
836    */
837   @Test(groups = { "Functional" })
838   public void testStoreAndRecoverAnnotationRowElementColours()
839           throws IOException
840   {
841     Desktop.instance.closeAll_actionPerformed(null);
842     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded("SEQ\tMNQ",
843             DataSourceType.PASTE);
844
845     AlignViewport av = af.getViewport();
846     AlignmentI al = av.getAlignment();
847     SequenceI fsq;
848     fsq = al.getSequenceAt(0);
849     Annotation annots[] = new Annotation[fsq.getLength()];
850     AlignmentAnnotation ala = new AlignmentAnnotation("Colour", "Annots",
851             annots);
852     annots[0] = new Annotation(1.0f);
853     annots[1] = new Annotation(2.0f);
854     annots[2] = new Annotation(3.0f);
855     annots[0].colour = Color.RED;
856     annots[1].colour = Color.GREEN;
857     annots[2].colour = Color.BLUE;
858     ala.validateRangeAndDisplay();
859     al.getSequenceAt(0).addAlignmentAnnotation(ala);
860     al.addAnnotation(ala);
861     /*
862      * and colour by annotation
863      */
864     AnnotationColourGradient acg = new AnnotationColourGradient(ala,
865             af.alignPanel.av.getGlobalColourScheme(), 0);
866     acg.setSeqAssociated(true);
867     acg.setPredefinedColours(true);
868     af.changeColour(acg);
869     Color seqcol[] = new Color[3];
870     for (int iStart=fsq.findIndex(fsq.getStart()),i=0;i<3;i++) {
871       seqcol[i] = af.alignPanel.getSeqPanel().seqCanvas.getSequenceRenderer().getResidueColour(fsq, iStart+i, null);
872     }
873     /*
874      * save project, close windows, reload project, verify
875      */
876     File tfile = File.createTempFile(
877             "testStoreAndRecoverAnnotRowElemColors", ".jvp");
878     tfile.deleteOnExit();
879     new Jalview2XML(false).saveState(tfile);
880     //Desktop.instance.closeAll_actionPerformed(null);
881     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
882             DataSourceType.FILE);
883     Assert.assertNotNull(af, "Failed to reload project");
884     /*
885      * verify alignment annotation has colors
886      */
887     av = af.getViewport();
888     
889     ColourSchemeI loadedCscheme = av.getGlobalColourScheme();
890     Assert.assertTrue(loadedCscheme instanceof AnnotationColourGradient,"Didn't apply Annotation colour gradient");
891     acg = (AnnotationColourGradient) loadedCscheme;
892     assertTrue(acg.isSeqAssociated());
893     assertTrue(acg.isPredefinedColours());
894
895     al = av.getAlignment();
896     fsq = al.getSequenceAt(0);
897     ala = fsq.getAnnotation()[0];
898     Assert.assertNotNull(ala, "No annotation row recovered");
899     Assert.assertNotNull(ala.annotations);
900     for (int iStart = al.getSequenceAt(0)
901             .findIndex(al.getSequenceAt(0).getStart()), i = 0; i < 3; i++)
902     {
903       Assert.assertTrue(ala.annotations[i].colour!=null);
904       Assert.assertTrue(ala.annotations[i].colour.equals(annots[i].colour));
905       Color newseqcol = af.alignPanel.getSeqPanel().seqCanvas.getSequenceRenderer().getResidueColour(fsq, iStart+i, null);
906       Assert.assertTrue(seqcol[i].equals(newseqcol),"Sequence shading is different");
907
908     }
909     
910   }
911
912   /**
913    * Configure an alignment and a sub-group each with distinct colour schemes,
914    * Conservation and PID thresholds, and confirm these are restored from the
915    * saved project.
916    * 
917    * @throws IOException
918    */
919   @Test(groups = { "Functional" })
920   public void testStoreAndRecoverColourThresholds() throws IOException
921   {
922     Desktop.instance.closeAll_actionPerformed(null);
923     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
924             "examples/uniref50.fa", DataSourceType.FILE);
925
926     AlignViewport av = af.getViewport();
927     AlignmentI al = av.getAlignment();
928
929     /*
930      * Colour alignment by Buried Index, Above 10% PID, By Conservation 20%
931      */
932     av.setColourAppliesToAllGroups(false);
933     af.changeColour_actionPerformed(JalviewColourScheme.Buried.toString());
934     assertTrue(av.getGlobalColourScheme() instanceof BuriedColourScheme);
935     af.abovePIDThreshold_actionPerformed(true);
936     SliderPanel sp = SliderPanel.getSliderPanel();
937     assertFalse(sp.isForConservation());
938     sp.valueChanged(10);
939     af.conservationMenuItem_actionPerformed(true);
940     sp = SliderPanel.getSliderPanel();
941     assertTrue(sp.isForConservation());
942     sp.valueChanged(20);
943     ResidueShaderI rs = av.getResidueShading();
944     assertEquals(rs.getThreshold(), 10);
945     assertTrue(rs.conservationApplied());
946     assertEquals(rs.getConservationInc(), 20);
947
948     /*
949      * create a group with Strand colouring, 30% Conservation
950      * and 40% PID threshold
951      * (notice menu action applies to selection group even if mouse click
952      * is at a sequence not in the group)
953      */
954     SequenceGroup sg = new SequenceGroup();
955     sg.addSequence(al.getSequenceAt(0), false);
956     sg.setStartRes(15);
957     sg.setEndRes(25);
958     av.setSelectionGroup(sg);
959     PopupMenu popupMenu = new PopupMenu(af.alignPanel, al.getSequenceAt(2),
960             null);
961     popupMenu.changeColour_actionPerformed(
962             JalviewColourScheme.Strand.toString());
963     assertTrue(sg.getColourScheme() instanceof StrandColourScheme);
964     assertEquals(al.getGroups().size(), 1);
965     assertSame(al.getGroups().get(0), sg);
966     popupMenu.conservationMenuItem_actionPerformed(true);
967     sp = SliderPanel.getSliderPanel();
968     assertTrue(sp.isForConservation());
969     sp.valueChanged(30);
970     popupMenu.abovePIDColour_actionPerformed(true);
971     sp = SliderPanel.getSliderPanel();
972     assertFalse(sp.isForConservation());
973     sp.valueChanged(40);
974     assertTrue(sg.getGroupColourScheme().conservationApplied());
975     assertEquals(sg.getGroupColourScheme().getConservationInc(), 30);
976     assertEquals(sg.getGroupColourScheme().getThreshold(), 40);
977
978     /*
979      * save project, close windows, reload project, verify
980      */
981     File tfile = File.createTempFile("testStoreAndRecoverColourThresholds",
982             ".jvp");
983     tfile.deleteOnExit();
984     new Jalview2XML(false).saveState(tfile);
985     Desktop.instance.closeAll_actionPerformed(null);
986     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
987             DataSourceType.FILE);
988     Assert.assertNotNull(af, "Failed to reload project");
989
990     /*
991      * verify alignment (background) colouring
992      */
993     rs = af.getViewport().getResidueShading();
994     assertTrue(rs.getColourScheme() instanceof BuriedColourScheme);
995     assertEquals(rs.getThreshold(), 10);
996     assertTrue(rs.conservationApplied());
997     assertEquals(rs.getConservationInc(), 20);
998
999     /*
1000      * verify group colouring
1001      */
1002     assertEquals(1, af.getViewport().getAlignment().getGroups().size(), 1);
1003     rs = af.getViewport().getAlignment().getGroups().get(0)
1004             .getGroupColourScheme();
1005     assertTrue(rs.getColourScheme() instanceof StrandColourScheme);
1006     assertEquals(rs.getThreshold(), 40);
1007     assertTrue(rs.conservationApplied());
1008     assertEquals(rs.getConservationInc(), 30);
1009   }
1010
1011   /**
1012    * Test save and reload of feature colour schemes and filter settings
1013    * 
1014    * @throws IOException
1015    */
1016   @Test(groups = { "Functional" })
1017   public void testSaveLoadFeatureColoursAndFilters() throws IOException
1018   {
1019     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1020             ">Seq1\nACDEFGHIKLM", DataSourceType.PASTE);
1021     SequenceI seq1 = af.getViewport().getAlignment().getSequenceAt(0);
1022
1023     /*
1024      * add some features to the sequence
1025      */
1026     int score = 1;
1027     addFeatures(seq1, "type1", score++);
1028     addFeatures(seq1, "type2", score++);
1029     addFeatures(seq1, "type3", score++);
1030     addFeatures(seq1, "type4", score++);
1031     addFeatures(seq1, "type5", score++);
1032
1033     /*
1034      * set colour schemes for features
1035      */
1036     FeatureRendererModel fr = af.getFeatureRenderer();
1037     fr.findAllFeatures(true);
1038
1039     // type1: red
1040     fr.setColour("type1", new FeatureColour(Color.red));
1041
1042     // type2: by label
1043     FeatureColourI byLabel = new FeatureColour();
1044     byLabel.setColourByLabel(true);
1045     fr.setColour("type2", byLabel);
1046
1047     // type3: by score above threshold
1048     FeatureColourI byScore = new FeatureColour(null, Color.BLACK,
1049             Color.BLUE, null, 1, 10);
1050     byScore.setAboveThreshold(true);
1051     byScore.setThreshold(2f);
1052     fr.setColour("type3", byScore);
1053
1054     // type4: by attribute AF
1055     FeatureColourI byAF = new FeatureColour();
1056     byAF.setColourByLabel(true);
1057     byAF.setAttributeName("AF");
1058     fr.setColour("type4", byAF);
1059
1060     // type5: by attribute CSQ:PolyPhen below threshold
1061     FeatureColourI byPolyPhen = new FeatureColour(null, Color.BLACK,
1062             Color.BLUE, null, 1, 10);
1063     byPolyPhen.setBelowThreshold(true);
1064     byPolyPhen.setThreshold(3f);
1065     byPolyPhen.setAttributeName("CSQ", "PolyPhen");
1066     fr.setColour("type5", byPolyPhen);
1067
1068     /*
1069      * set filters for feature types
1070      */
1071
1072     // filter type1 features by (label contains "x")
1073     FeatureMatcherSetI filterByX = new FeatureMatcherSet();
1074     filterByX.and(FeatureMatcher.byLabel(Condition.Contains, "x"));
1075     fr.setFeatureFilter("type1", filterByX);
1076
1077     // filter type2 features by (score <= 2.4 and score > 1.1)
1078     FeatureMatcherSetI filterByScore = new FeatureMatcherSet();
1079     filterByScore.and(FeatureMatcher.byScore(Condition.LE, "2.4"));
1080     filterByScore.and(FeatureMatcher.byScore(Condition.GT, "1.1"));
1081     fr.setFeatureFilter("type2", filterByScore);
1082
1083     // filter type3 features by (AF contains X OR CSQ:PolyPhen != 0)
1084     FeatureMatcherSetI filterByXY = new FeatureMatcherSet();
1085     filterByXY
1086             .and(FeatureMatcher.byAttribute(Condition.Contains, "X", "AF"));
1087     filterByXY.or(FeatureMatcher.byAttribute(Condition.NE, "0", "CSQ",
1088             "PolyPhen"));
1089     fr.setFeatureFilter("type3", filterByXY);
1090
1091     /*
1092      * save as Jalview project
1093      */
1094     File tfile = File.createTempFile("JalviewTest", ".jvp");
1095     tfile.deleteOnExit();
1096     String filePath = tfile.getAbsolutePath();
1097     af.saveAlignment(filePath, FileFormat.Jalview);
1098     assertTrue(af.isSaveAlignmentSuccessful(),
1099             "Failed to store as a project.");
1100
1101     /*
1102      * close current alignment and load the saved project
1103      */
1104     af.closeMenuItem_actionPerformed(true);
1105     af = null;
1106     af = new FileLoader().LoadFileWaitTillLoaded(filePath,
1107             DataSourceType.FILE);
1108     assertNotNull(af, "Failed to import new project");
1109
1110     /*
1111      * verify restored feature colour schemes and filters
1112      */
1113     fr = af.getFeatureRenderer();
1114     FeatureColourI fc = fr.getFeatureStyle("type1");
1115     assertTrue(fc.isSimpleColour());
1116     assertEquals(fc.getColour(), Color.red);
1117     fc = fr.getFeatureStyle("type2");
1118     assertTrue(fc.isColourByLabel());
1119     fc = fr.getFeatureStyle("type3");
1120     assertTrue(fc.isGraduatedColour());
1121     assertNull(fc.getAttributeName());
1122     assertTrue(fc.isAboveThreshold());
1123     assertEquals(fc.getThreshold(), 2f);
1124     fc = fr.getFeatureStyle("type4");
1125     assertTrue(fc.isColourByLabel());
1126     assertTrue(fc.isColourByAttribute());
1127     assertEquals(fc.getAttributeName(), new String[] { "AF" });
1128     fc = fr.getFeatureStyle("type5");
1129     assertTrue(fc.isGraduatedColour());
1130     assertTrue(fc.isColourByAttribute());
1131     assertEquals(fc.getAttributeName(), new String[] { "CSQ", "PolyPhen" });
1132     assertTrue(fc.isBelowThreshold());
1133     assertEquals(fc.getThreshold(), 3f);
1134
1135     assertEquals(fr.getFeatureFilter("type1").toStableString(),
1136             "Label Contains x");
1137     assertEquals(fr.getFeatureFilter("type2").toStableString(),
1138             "(Score LE 2.4) AND (Score GT 1.1)");
1139     assertEquals(fr.getFeatureFilter("type3").toStableString(),
1140             "(AF Contains X) OR (CSQ:PolyPhen NE 0)");
1141   }
1142
1143   private void addFeature(SequenceI seq, String featureType, int score)
1144   {
1145     SequenceFeature sf = new SequenceFeature(featureType, "desc", 1, 2,
1146             score, "grp");
1147     sf.setValue("AF", score);
1148     sf.setValue("CSQ", new HashMap<String, String>()
1149     {
1150       {
1151         put("PolyPhen", Integer.toString(score));
1152       }
1153     });
1154     seq.addSequenceFeature(sf);
1155   }
1156
1157   /**
1158    * Adds two features of the given type to the given sequence, also setting the
1159    * score as the value of attribute "AF" and sub-attribute "CSQ:PolyPhen"
1160    * 
1161    * @param seq
1162    * @param featureType
1163    * @param score
1164    */
1165   private void addFeatures(SequenceI seq, String featureType, int score)
1166   {
1167     addFeature(seq, featureType, score++);
1168     addFeature(seq, featureType, score);
1169   }
1170
1171   /**
1172    * pre 2.11 - jalview 2.10 erroneously created new dataset entries for each
1173    * view (JAL-3171) this test ensures we can import and merge those views
1174    */
1175   @Test(groups = { "Functional" })
1176   public void testMergeDatasetsforViews() throws IOException
1177   {
1178     // simple project - two views on one alignment
1179     AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded(
1180             "examples/testdata/projects/twoViews.jvp", DataSourceType.FILE);
1181     assertNotNull(af);
1182     assertTrue(af.getAlignPanels().size() > 1);
1183     verifyDs(af);
1184   }
1185
1186   /**
1187    * pre 2.11 - jalview 2.10 erroneously created new dataset entries for each
1188    * view (JAL-3171) this test ensures we can import and merge those views This
1189    * is a more complex project
1190    */
1191   @Test(groups = { "Functional" })
1192   public void testMergeDatasetsforManyViews() throws IOException
1193   {
1194     Desktop.instance.closeAll_actionPerformed(null);
1195
1196     // complex project - one dataset, several views on several alignments
1197     AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded(
1198             "examples/testdata/projects/manyViews.jvp",
1199             DataSourceType.FILE);
1200     assertNotNull(af);
1201
1202     AlignmentI ds = null;
1203     for (AlignFrame alignFrame : Desktop.getAlignFrames())
1204     {
1205       if (ds == null)
1206       {
1207         ds = verifyDs(alignFrame);
1208       }
1209       else
1210       {
1211         // check that this frame's dataset matches the last
1212         assertTrue(ds == verifyDs(alignFrame));
1213       }
1214     }
1215   }
1216
1217   private AlignmentI verifyDs(AlignFrame af)
1218   {
1219     AlignmentI ds = null;
1220     for (AlignmentViewPanel ap : af.getAlignPanels())
1221     {
1222       if (ds == null)
1223       {
1224         ds = ap.getAlignment().getDataset();
1225       }
1226       else
1227       {
1228         assertTrue(ap.getAlignment().getDataset() == ds,
1229                 "Dataset was not the same for imported 2.10.5 project with several alignment views");
1230       }
1231     }
1232     return ds;
1233   }
1234
1235   @Test(groups = "Functional")
1236   public void testPcaViewAssociation() throws IOException
1237   {
1238     Desktop.instance.closeAll_actionPerformed(null);
1239     final String PCAVIEWNAME = "With PCA";
1240     // create a new tempfile
1241     File tempfile = File.createTempFile("jvPCAviewAssoc", "jvp");
1242
1243     {
1244       String exampleFile = "examples/uniref50.fa";
1245       AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(exampleFile,
1246               DataSourceType.FILE);
1247       assertNotNull(af, "Didn't read in the example file correctly.");
1248       AlignmentPanel origView = (AlignmentPanel) af.getAlignPanels().get(0);
1249       AlignmentPanel newview = af.newView(PCAVIEWNAME, true);
1250       // create another for good measure
1251       af.newView("Not the PCA View", true);
1252       PCAPanel pcaPanel = new PCAPanel(origView, "BLOSUM62",
1253               new SimilarityParams(true, true, true, false));
1254       // we're in the test exec thread, so we can just run synchronously here
1255       pcaPanel.run();
1256
1257       // now switch the linked view
1258       pcaPanel.selectAssociatedView(newview);
1259
1260       assertTrue(pcaPanel.getAlignViewport() == newview.getAlignViewport(),
1261               "PCA should be associated with 'With PCA' view: test is broken");
1262
1263       // now save and reload project
1264       Jalview2XML jv2xml = new jalview.project.Jalview2XML(false);
1265       tempfile.delete();
1266       jv2xml.saveState(tempfile);
1267       assertTrue(jv2xml.errorMessage == null,
1268               "Failed to save dummy project with PCA: test broken");
1269     }
1270
1271     // load again.
1272     Desktop.instance.closeAll_actionPerformed(null);
1273     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1274             tempfile.getCanonicalPath(), DataSourceType.FILE);
1275     JInternalFrame[] frames = Desktop.instance.getAllFrames();
1276     // PCA and the tabbed alignment view should be the only two windows on the
1277     // desktop
1278     assertEquals(frames.length, 2,
1279             "PCA and the tabbed alignment view should be the only two windows on the desktop");
1280     PCAPanel pcaPanel = (PCAPanel) frames[frames[0] == af ? 1 : 0];
1281
1282     AlignmentViewPanel restoredNewView = null;
1283     for (AlignmentViewPanel alignpanel : Desktop.getAlignmentPanels(null))
1284     {
1285       if (alignpanel.getAlignViewport() == pcaPanel.getAlignViewport())
1286       {
1287         restoredNewView = alignpanel;
1288       }
1289     }
1290     assertEquals(restoredNewView.getViewName(), PCAVIEWNAME);
1291     assertTrue(
1292             restoredNewView.getAlignViewport() == pcaPanel
1293                     .getAlignViewport(),
1294             "Didn't restore correct view association for the PCA view");
1295   }
1296
1297   /**
1298    * Test save and reload of DBRefEntry including GeneLocus in project
1299    * 
1300    * @throws Exception
1301    */
1302   @Test(groups = { "Functional" })
1303   public void testStoreAndRecoverGeneLocus() throws Exception
1304   {
1305     Desktop.instance.closeAll_actionPerformed(null);
1306     String seqData = ">P30419\nACDE\n>X1235\nGCCTGTGACGAA";
1307     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
1308             DataSourceType.PASTE);
1309     assertNotNull(af, "Didn't read in the example file correctly.");
1310
1311     AlignmentViewPanel ap = Desktop.getAlignmentPanels(null)[0];
1312     SequenceI pep = ap.getAlignment().getSequenceAt(0);
1313     SequenceI cds = ap.getAlignment().getSequenceAt(1);
1314
1315     /*
1316      * give 'protein' a dbref to self, a dbref with map to CDS,
1317      * and a dbref with map to gene 'locus'
1318      */
1319     DBRefEntry dbref1 = new DBRefEntry("Uniprot", "1", "P30419", null);
1320     pep.addDBRef(dbref1);
1321     Mapping cdsmap = new Mapping(cds,
1322             new MapList(new int[]
1323             { 1, 4 }, new int[] { 1, 12 }, 1, 3));
1324     DBRefEntry dbref2 = new DBRefEntry("EMBLCDS", "2", "X1235", cdsmap);
1325     pep.addDBRef(dbref2);
1326     Mapping locusmap = new Mapping(null,
1327             new MapList(new int[]
1328             { 1, 4 }, new int[] { 2674123, 2674135 }, 1, 3));
1329     DBRefEntry dbref3 = new GeneLocus("human", "GRCh38", "5", locusmap);
1330     pep.addDBRef(dbref3);
1331
1332     File tfile = File.createTempFile("testStoreAndRecoverGeneLocus",
1333             ".jvp");
1334     try
1335     {
1336       new Jalview2XML(false).saveState(tfile);
1337     } catch (Throwable e)
1338     {
1339       Assert.fail("Didn't save the state", e);
1340     }
1341     Desktop.instance.closeAll_actionPerformed(null);
1342
1343     new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
1344             DataSourceType.FILE);
1345     AlignmentViewPanel rap = Desktop.getAlignmentPanels(null)[0];
1346     SequenceI rpep = rap.getAlignment().getSequenceAt(0);
1347     DBModList<DBRefEntry> dbrefs = rpep.getDBRefs();
1348     assertEquals(rpep.getName(), "P30419");
1349     assertEquals(dbrefs.size(), 3);
1350     DBRefEntry dbRef = dbrefs.get(0);
1351     assertFalse(dbRef instanceof GeneLocus);
1352     assertNull(dbRef.getMap());
1353     assertEquals(dbRef, dbref1);
1354
1355     /*
1356      * restored dbrefs with mapping have a different 'map to'
1357      * sequence but otherwise match the original dbrefs
1358      */
1359     dbRef = dbrefs.get(1);
1360     assertFalse(dbRef instanceof GeneLocus);
1361     assertTrue(dbRef.equalRef(dbref2));
1362     assertNotNull(dbRef.getMap());
1363     SequenceI rcds = rap.getAlignment().getSequenceAt(1);
1364     assertSame(dbRef.getMap().getTo(), rcds);
1365     // compare MapList but not map.to
1366     assertEquals(dbRef.getMap().getMap(), dbref2.getMap().getMap());
1367
1368     /*
1369      * GeneLocus map.to is null so can compare Mapping objects
1370      */
1371     dbRef = dbrefs.get(2);
1372     assertTrue(dbRef instanceof GeneLocus);
1373     assertEquals(dbRef, dbref3);
1374   }
1375
1376   /**
1377    * test store and recovery of Overview windows
1378    * 
1379    * @throws Exception
1380    */
1381   @Test(groups = { "Functional" }, enabled = true)
1382   public void testStoreAndRecoverOverview() throws Exception
1383   {
1384     Desktop.instance.closeAll_actionPerformed(null);
1385
1386     Cache.setProperty("SHOW_OVERVIEW", "false");
1387     Cache.setProperty(Preferences.USE_LEGACY_GAP, "false");
1388     Cache.setColourProperty(Preferences.GAP_COLOUR, Color.green);
1389     Cache.setColourProperty(Preferences.HIDDEN_COLOUR, Color.yellow);
1390     Cache.setProperty(Preferences.SHOW_OV_HIDDEN_AT_START, "true");
1391
1392     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1393             "examples/uniref50.fa", DataSourceType.FILE);
1394
1395     /*
1396      * open and resize / reposition overview 
1397      */
1398     af.overviewMenuItem_actionPerformed(null);
1399     OverviewPanel ov1 = af.alignPanel.getOverviewPanel();
1400     assertNotNull(ov1);
1401     ov1.setFrameBounds(20, 30, 200, 400);
1402     assertEquals(ov1.getTitle(), "Overview examples/uniref50.fa");
1403     assertTrue(ov1.isShowHiddenRegions());
1404
1405     /*
1406      * open a New View and its Overview and reposition it
1407      */
1408     af.newView_actionPerformed(null);
1409     af.overviewMenuItem_actionPerformed(null);
1410     OverviewPanel ov2 = af.alignPanel.getOverviewPanel();
1411     assertNotNull(ov2);
1412     assertNotSame(ov1, ov2);
1413     ov2.setFrameBounds(25, 35, 205, 405);
1414     assertEquals(ov1.getTitle(), "Overview examples/uniref50.fa Original");
1415     assertEquals(ov2.getTitle(), "Overview examples/uniref50.fa View 1");
1416
1417     File tfile = File.createTempFile("testStoreAndRecoverOverview", ".jvp");
1418     new Jalview2XML(false).saveState(tfile);
1419     Desktop.instance.closeAll_actionPerformed(null);
1420
1421     /*
1422      * change preferences (should _not_ affect reloaded Overviews)
1423      */
1424     Cache.setProperty("SHOW_OVERVIEW", "true");
1425     Cache.setProperty(Preferences.USE_LEGACY_GAP, "true");
1426     Cache.setColourProperty(Preferences.GAP_COLOUR, Color.blue);
1427     Cache.setColourProperty(Preferences.HIDDEN_COLOUR, Color.orange);
1428     Cache.setProperty(Preferences.SHOW_OV_HIDDEN_AT_START, "false");
1429
1430     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
1431             DataSourceType.FILE);
1432
1433     /*
1434      * workaround: explicitly select View 1 (not in focus after restore)
1435      */
1436     af.tabSelectionChanged(1);
1437
1438     /*
1439      * verify restored overview for View 1
1440      */
1441     ov2 = af.alignPanel.getOverviewPanel();
1442     assertEquals(ov2.getCanvas().getGapColour(), Color.green);
1443     // 'non-legacy' colouring uses white for non-gapped residues
1444     assertEquals(ov2.getCanvas().getResidueColour(), Color.white);
1445     assertEquals(ov2.getCanvas().getHiddenColour(), Color.yellow);
1446     assertEquals(ov2.getTitle(), "Overview examples/uniref50.fa View 1");
1447     assertEquals(ov2.getFrameBounds(), new Rectangle(25, 35, 205, 405));
1448     assertTrue(ov2.isShowHiddenRegions());
1449
1450     /*
1451      * verify restored overview for Original view
1452      */
1453     af.tabSelectionChanged(0);
1454     ov1 = af.alignPanel.getOverviewPanel();
1455     assertEquals(ov1.getCanvas().getGapColour(), Color.green);
1456     // 'non-legacy' colouring uses white for non-gapped residues
1457     assertEquals(ov1.getCanvas().getResidueColour(), Color.white);
1458     assertEquals(ov1.getCanvas().getHiddenColour(), Color.yellow);
1459     assertEquals(ov1.getTitle(), "Overview examples/uniref50.fa Original");
1460     assertEquals(ov1.getFrameBounds(), new Rectangle(20, 30, 200, 400));
1461     assertTrue(ov1.isShowHiddenRegions());
1462   }
1463
1464   /**
1465    * Test that a view with no Overview is restored with no Overview, even if
1466    * 'Open Overview' is selected in Preferences
1467    * 
1468    * @throws Exception
1469    */
1470   @Test(groups = { "Functional" }, enabled = true)
1471   public void testStoreAndRecoverNoOverview() throws Exception
1472   {
1473     Cache.setProperty("SHOW_OVERVIEW", "false");
1474     Desktop.instance.closeAll_actionPerformed(null);
1475     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1476             ">seq1\nMATRSQFLVNF\n", DataSourceType.PASTE);
1477
1478     File tfile = File.createTempFile("testStoreAndRecoverOverview", ".jvp");
1479     new Jalview2XML(false).saveState(tfile);
1480     Desktop.instance.closeAll_actionPerformed(null);
1481
1482     Cache.setProperty("SHOW_OVERVIEW", "true");
1483     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
1484             DataSourceType.FILE);
1485
1486     assertNull(af.alignPanel.getOverviewPanel());
1487   }
1488
1489   /**
1490    * Test that a view from an older version of Jalview is restored with Overview automatically shown when the preference is set
1491    * 
1492    * @throws Exception
1493    */
1494   @Test(groups = { "Functional" }, enabled = true)
1495   public void testAutoShowOverviewForLegacyProjects() throws Exception
1496   {
1497     Desktop.instance.closeAll_actionPerformed(null);
1498     Cache.setProperty("SHOW_OVERVIEW", "true");
1499     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1500             "examples/exampleFile.jvp", DataSourceType.FILE);
1501
1502     Cache.setProperty("SHOW_OVERVIEW", "false");
1503     assertNotNull(af.alignPanel.getOverviewPanel());
1504   }
1505
1506   /**
1507    * Test that loading example.jvp, doing some stuff, then hitting reload
1508    * doesn't leave the modified window still open
1509    * 
1510    * See JAL-4127 - interactively performing the same actions and reloading
1511    * works fine, but programmatically they do not
1512    * 
1513    * @throws Exception
1514    */
1515   @Test(groups = {"Functional"}, enabled=false)
1516   public void testReloadActuallyReloads() throws Exception
1517   {
1518     Desktop.instance.closeAll_actionPerformed(null);
1519     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1520             "examples/exampleFile.jvp", DataSourceType.FILE);
1521     af.getViewport().getColumnSelection().addElement(3);
1522     af.hideSelColumns_actionPerformed(null);
1523     af.newView("new", true);
1524     af.reload_actionPerformed(null);
1525     Thread.sleep(30);
1526     // af exists still but isn't shown
1527     assertTrue(af.isClosed());
1528   }
1529 }