Merge branch 'develop' into feature/JAL-1713_overviewInProject
[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
598   /**
599    * Test save and reload of a project with a different sequence group (and
600    * representative sequence) in each view.
601    * 
602    * @throws Exception
603    */
604   @Test(groups = { "Functional" })
605   public void testStoreAndRecoverGroupRepSeqs() throws Exception
606   {
607     Desktop.instance.closeAll_actionPerformed(null);
608     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
609             "examples/uniref50.fa", DataSourceType.FILE);
610     assertNotNull(af, "Didn't read in the example file correctly.");
611     String afid = af.getViewport().getSequenceSetId();
612     // make a second view of the alignment
613     af.newView_actionPerformed(null);
614
615     /*
616      * remember representative and hidden sequences marked 
617      * on each panel
618      */
619     Map<String, SequenceI> repSeqs = new HashMap<>();
620     Map<String, List<String>> hiddenSeqNames = new HashMap<>();
621
622     /*
623      * mark sequence 2, 3, 4.. in panels 1, 2, 3...
624      * as reference sequence for itself and the preceding sequence
625      */
626     int n = 1;
627     for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
628     {
629       AlignViewportI av = ap.getAlignViewport();
630       AlignmentI alignment = ap.getAlignment();
631       int repIndex = n % alignment.getHeight();
632       // ensure at least one preceding sequence i.e. index >= 1
633       repIndex = Math.max(repIndex, 1);
634       SequenceI repSeq = alignment.getSequenceAt(repIndex);
635       repSeqs.put(ap.getViewName(), repSeq);
636       List<String> hiddenNames = new ArrayList<>();
637       hiddenSeqNames.put(ap.getViewName(), hiddenNames);
638
639       /*
640        * have rep sequence represent itself and the one before it
641        * this hides the group (except for the rep seq)
642        */
643       SequenceGroup sg = new SequenceGroup();
644       sg.addSequence(repSeq, false);
645       SequenceI precedingSeq = alignment.getSequenceAt(repIndex - 1);
646       sg.addSequence(precedingSeq, false);
647       sg.setSeqrep(repSeq);
648       assertTrue(sg.getSequences().contains(repSeq));
649       assertTrue(sg.getSequences().contains(precedingSeq));
650       av.setSelectionGroup(sg);
651       assertSame(repSeq, sg.getSeqrep());
652
653       /*
654        * represent group with sequence adds to a map of hidden rep sequences
655        * (it does not create a group on the alignment) 
656        */
657       ((AlignmentViewport) av).hideSequences(repSeq, true);
658       assertSame(repSeq, sg.getSeqrep());
659       assertTrue(sg.getSequences().contains(repSeq));
660       assertTrue(sg.getSequences().contains(precedingSeq));
661       assertTrue(alignment.getGroups().isEmpty(), "alignment has groups");
662       Map<SequenceI, SequenceCollectionI> hiddenRepSeqsMap = av
663               .getHiddenRepSequences();
664       assertNotNull(hiddenRepSeqsMap);
665       assertEquals(1, hiddenRepSeqsMap.size());
666       assertSame(sg, hiddenRepSeqsMap.get(repSeq));
667       assertTrue(alignment.getHiddenSequences().isHidden(precedingSeq));
668       assertFalse(alignment.getHiddenSequences().isHidden(repSeq));
669       hiddenNames.add(precedingSeq.getName());
670
671       n++;
672     }
673     File tfile = File.createTempFile("testStoreAndRecoverGroupReps",
674             ".jvp");
675     try
676     {
677       new Jalview2XML(false).saveState(tfile);
678     } catch (Throwable e)
679     {
680       Assert.fail("Didn't save the expanded view state", e);
681     }
682     Desktop.instance.closeAll_actionPerformed(null);
683     if (Desktop.getAlignFrames() != null)
684     {
685       Assert.assertEquals(Desktop.getAlignFrames().length, 0);
686     }
687
688     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
689             DataSourceType.FILE);
690     afid = af.getViewport().getSequenceSetId();
691
692     for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
693     {
694       String viewName = ap.getViewName();
695       AlignViewportI av = ap.getAlignViewport();
696       AlignmentI alignment = ap.getAlignment();
697       List<SequenceGroup> groups = alignment.getGroups();
698       assertNotNull(groups);
699       assertTrue(groups.isEmpty(), "Alignment has groups");
700       Map<SequenceI, SequenceCollectionI> hiddenRepSeqsMap = av
701               .getHiddenRepSequences();
702       assertNotNull(hiddenRepSeqsMap, "No hidden represented sequences");
703       assertEquals(1, hiddenRepSeqsMap.size());
704       assertEquals(repSeqs.get(viewName).getDisplayId(true),
705               hiddenRepSeqsMap.keySet().iterator().next()
706                       .getDisplayId(true));
707
708       /*
709        * verify hidden sequences in restored panel
710        */
711       List<String> hidden = hiddenSeqNames.get(ap.getViewName());
712       HiddenSequences hs = alignment.getHiddenSequences();
713       assertEquals(hidden.size(), hs.getSize(),
714               "wrong number of restored hidden sequences in "
715                       + ap.getViewName());
716     }
717   }
718
719   /**
720    * Test save and reload of PDBEntry in Jalview project
721    * 
722    * @throws Exception
723    */
724   @Test(groups = { "Functional" })
725   public void testStoreAndRecoverPDBEntry() throws Exception
726   {
727     Desktop.instance.closeAll_actionPerformed(null);
728     String exampleFile = "examples/3W5V.pdb";
729     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(exampleFile,
730             DataSourceType.FILE);
731     assertNotNull(af, "Didn't read in the example file correctly.");
732     String afid = af.getViewport().getSequenceSetId();
733
734     AlignmentPanel[] alignPanels = Desktop.getAlignmentPanels(afid);
735     System.out.println();
736     AlignmentViewPanel ap = alignPanels[0];
737     String tfileBase = new File(".").getAbsolutePath().replace(".", "");
738     String testFile = tfileBase + exampleFile;
739     AlignmentI alignment = ap.getAlignment();
740     System.out.println("blah");
741     SequenceI[] seqs = alignment.getSequencesArray();
742     Assert.assertNotNull(seqs[0]);
743     Assert.assertNotNull(seqs[1]);
744     Assert.assertNotNull(seqs[2]);
745     Assert.assertNotNull(seqs[3]);
746     Assert.assertNotNull(seqs[0].getDatasetSequence());
747     Assert.assertNotNull(seqs[1].getDatasetSequence());
748     Assert.assertNotNull(seqs[2].getDatasetSequence());
749     Assert.assertNotNull(seqs[3].getDatasetSequence());
750     PDBEntry[] pdbEntries = new PDBEntry[4];
751     pdbEntries[0] = new PDBEntry("3W5V", "A", Type.PDB, testFile);
752     pdbEntries[1] = new PDBEntry("3W5V", "B", Type.PDB, testFile);
753     pdbEntries[2] = new PDBEntry("3W5V", "C", Type.PDB, testFile);
754     pdbEntries[3] = new PDBEntry("3W5V", "D", Type.PDB, testFile);
755     Assert.assertEquals(
756             seqs[0].getDatasetSequence().getAllPDBEntries().get(0),
757             pdbEntries[0]);
758     Assert.assertEquals(
759             seqs[1].getDatasetSequence().getAllPDBEntries().get(0),
760             pdbEntries[1]);
761     Assert.assertEquals(
762             seqs[2].getDatasetSequence().getAllPDBEntries().get(0),
763             pdbEntries[2]);
764     Assert.assertEquals(
765             seqs[3].getDatasetSequence().getAllPDBEntries().get(0),
766             pdbEntries[3]);
767
768     File tfile = File.createTempFile("testStoreAndRecoverPDBEntry", ".jvp");
769     try
770     {
771       new Jalview2XML(false).saveState(tfile);
772     } catch (Throwable e)
773     {
774       Assert.fail("Didn't save the state", e);
775     }
776     Desktop.instance.closeAll_actionPerformed(null);
777     if (Desktop.getAlignFrames() != null)
778     {
779       Assert.assertEquals(Desktop.getAlignFrames().length, 0);
780     }
781
782     AlignFrame restoredFrame = new FileLoader().LoadFileWaitTillLoaded(
783             tfile.getAbsolutePath(), DataSourceType.FILE);
784     String rfid = restoredFrame.getViewport().getSequenceSetId();
785     AlignmentPanel[] rAlignPanels = Desktop.getAlignmentPanels(rfid);
786     AlignmentViewPanel rap = rAlignPanels[0];
787     AlignmentI rAlignment = rap.getAlignment();
788     System.out.println("blah");
789     SequenceI[] rseqs = rAlignment.getSequencesArray();
790     Assert.assertNotNull(rseqs[0]);
791     Assert.assertNotNull(rseqs[1]);
792     Assert.assertNotNull(rseqs[2]);
793     Assert.assertNotNull(rseqs[3]);
794     Assert.assertNotNull(rseqs[0].getDatasetSequence());
795     Assert.assertNotNull(rseqs[1].getDatasetSequence());
796     Assert.assertNotNull(rseqs[2].getDatasetSequence());
797     Assert.assertNotNull(rseqs[3].getDatasetSequence());
798
799     // The Asserts below are expected to fail until the PDB chainCode is
800     // recoverable from a Jalview projects
801     for (int chain = 0; chain < 4; chain++)
802     {
803       PDBEntry recov = rseqs[chain].getDatasetSequence().getAllPDBEntries()
804               .get(0);
805       PDBEntry expected = pdbEntries[chain];
806       Assert.assertEquals(recov.getId(), expected.getId(),
807               "Mismatch PDB ID");
808       Assert.assertEquals(recov.getChainCode(), expected.getChainCode(),
809               "Mismatch PDB ID");
810       Assert.assertEquals(recov.getType(), expected.getType(),
811               "Mismatch PDBEntry 'Type'");
812       Assert.assertNotNull(recov.getFile(),
813               "Recovered PDBEntry should have a non-null file entry");
814       Assert.assertEquals(
815               recov.getFile().toLowerCase(Locale.ENGLISH)
816                       .lastIndexOf("pdb"),
817               recov.getFile().length() - 3,
818               "Recovered PDBEntry file should have PDB suffix");
819     }
820   }
821
822   /**
823    * Configure an alignment and a sub-group each with distinct colour schemes,
824    * Conservation and PID thresholds, and confirm these are restored from the
825    * saved project.
826    * 
827    * @throws IOException
828    */
829   @Test(groups = { "Functional" })
830   public void testStoreAndRecoverAnnotationRowElementColours()
831           throws IOException
832   {
833     Desktop.instance.closeAll_actionPerformed(null);
834     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded("SEQ\tMNQ",
835             DataSourceType.PASTE);
836
837     AlignViewport av = af.getViewport();
838     AlignmentI al = av.getAlignment();
839     SequenceI fsq;
840     fsq = al.getSequenceAt(0);
841     Annotation annots[] = new Annotation[fsq.getLength()];
842     AlignmentAnnotation ala = new AlignmentAnnotation("Colour", "Annots",
843             annots);
844     annots[0] = new Annotation(1.0f);
845     annots[1] = new Annotation(2.0f);
846     annots[2] = new Annotation(3.0f);
847     annots[0].colour = Color.RED;
848     annots[1].colour = Color.GREEN;
849     annots[2].colour = Color.BLUE;
850     ala.validateRangeAndDisplay();
851     al.getSequenceAt(0).addAlignmentAnnotation(ala);
852     al.addAnnotation(ala);
853     /*
854      * and colour by annotation
855      */
856     AnnotationColourGradient acg = new AnnotationColourGradient(ala,
857             af.alignPanel.av.getGlobalColourScheme(), 0);
858     acg.setSeqAssociated(true);
859     acg.setPredefinedColours(true);
860     af.changeColour(acg);
861     Color seqcol[] = new Color[3];
862     for (int iStart=fsq.findIndex(fsq.getStart()),i=0;i<3;i++) {
863       seqcol[i] = af.alignPanel.getSeqPanel().seqCanvas.getSequenceRenderer().getResidueColour(fsq, iStart+i, null);
864     }
865     /*
866      * save project, close windows, reload project, verify
867      */
868     File tfile = File.createTempFile(
869             "testStoreAndRecoverAnnotRowElemColors", ".jvp");
870     tfile.deleteOnExit();
871     new Jalview2XML(false).saveState(tfile);
872     //Desktop.instance.closeAll_actionPerformed(null);
873     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
874             DataSourceType.FILE);
875     Assert.assertNotNull(af, "Failed to reload project");
876     /*
877      * verify alignment annotation has colors
878      */
879     av = af.getViewport();
880     
881     ColourSchemeI loadedCscheme = av.getGlobalColourScheme();
882     Assert.assertTrue(loadedCscheme instanceof AnnotationColourGradient,"Didn't apply Annotation colour gradient");
883     acg = (AnnotationColourGradient) loadedCscheme;
884     assertTrue(acg.isSeqAssociated());
885     assertTrue(acg.isPredefinedColours());
886
887     al = av.getAlignment();
888     fsq = al.getSequenceAt(0);
889     ala = fsq.getAnnotation()[0];
890     Assert.assertNotNull(ala, "No annotation row recovered");
891     Assert.assertNotNull(ala.annotations);
892     for (int iStart = al.getSequenceAt(0)
893             .findIndex(al.getSequenceAt(0).getStart()), i = 0; i < 3; i++)
894     {
895       Assert.assertTrue(ala.annotations[i].colour!=null);
896       Assert.assertTrue(ala.annotations[i].colour.equals(annots[i].colour));
897       Color newseqcol = af.alignPanel.getSeqPanel().seqCanvas.getSequenceRenderer().getResidueColour(fsq, iStart+i, null);
898       Assert.assertTrue(seqcol[i].equals(newseqcol),"Sequence shading is different");
899
900     }
901     
902   }
903
904   /**
905    * Configure an alignment and a sub-group each with distinct colour schemes,
906    * Conservation and PID thresholds, and confirm these are restored from the
907    * saved project.
908    * 
909    * @throws IOException
910    */
911   @Test(groups = { "Functional" })
912   public void testStoreAndRecoverColourThresholds() throws IOException
913   {
914     Desktop.instance.closeAll_actionPerformed(null);
915     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
916             "examples/uniref50.fa", DataSourceType.FILE);
917
918     AlignViewport av = af.getViewport();
919     AlignmentI al = av.getAlignment();
920
921     /*
922      * Colour alignment by Buried Index, Above 10% PID, By Conservation 20%
923      */
924     av.setColourAppliesToAllGroups(false);
925     af.changeColour_actionPerformed(JalviewColourScheme.Buried.toString());
926     assertTrue(av.getGlobalColourScheme() instanceof BuriedColourScheme);
927     af.abovePIDThreshold_actionPerformed(true);
928     SliderPanel sp = SliderPanel.getSliderPanel();
929     assertFalse(sp.isForConservation());
930     sp.valueChanged(10);
931     af.conservationMenuItem_actionPerformed(true);
932     sp = SliderPanel.getSliderPanel();
933     assertTrue(sp.isForConservation());
934     sp.valueChanged(20);
935     ResidueShaderI rs = av.getResidueShading();
936     assertEquals(rs.getThreshold(), 10);
937     assertTrue(rs.conservationApplied());
938     assertEquals(rs.getConservationInc(), 20);
939
940     /*
941      * create a group with Strand colouring, 30% Conservation
942      * and 40% PID threshold
943      * (notice menu action applies to selection group even if mouse click
944      * is at a sequence not in the group)
945      */
946     SequenceGroup sg = new SequenceGroup();
947     sg.addSequence(al.getSequenceAt(0), false);
948     sg.setStartRes(15);
949     sg.setEndRes(25);
950     av.setSelectionGroup(sg);
951     PopupMenu popupMenu = new PopupMenu(af.alignPanel, al.getSequenceAt(2),
952             null);
953     popupMenu.changeColour_actionPerformed(
954             JalviewColourScheme.Strand.toString());
955     assertTrue(sg.getColourScheme() instanceof StrandColourScheme);
956     assertEquals(al.getGroups().size(), 1);
957     assertSame(al.getGroups().get(0), sg);
958     popupMenu.conservationMenuItem_actionPerformed(true);
959     sp = SliderPanel.getSliderPanel();
960     assertTrue(sp.isForConservation());
961     sp.valueChanged(30);
962     popupMenu.abovePIDColour_actionPerformed(true);
963     sp = SliderPanel.getSliderPanel();
964     assertFalse(sp.isForConservation());
965     sp.valueChanged(40);
966     assertTrue(sg.getGroupColourScheme().conservationApplied());
967     assertEquals(sg.getGroupColourScheme().getConservationInc(), 30);
968     assertEquals(sg.getGroupColourScheme().getThreshold(), 40);
969
970     /*
971      * save project, close windows, reload project, verify
972      */
973     File tfile = File.createTempFile("testStoreAndRecoverColourThresholds",
974             ".jvp");
975     tfile.deleteOnExit();
976     new Jalview2XML(false).saveState(tfile);
977     Desktop.instance.closeAll_actionPerformed(null);
978     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
979             DataSourceType.FILE);
980     Assert.assertNotNull(af, "Failed to reload project");
981
982     /*
983      * verify alignment (background) colouring
984      */
985     rs = af.getViewport().getResidueShading();
986     assertTrue(rs.getColourScheme() instanceof BuriedColourScheme);
987     assertEquals(rs.getThreshold(), 10);
988     assertTrue(rs.conservationApplied());
989     assertEquals(rs.getConservationInc(), 20);
990
991     /*
992      * verify group colouring
993      */
994     assertEquals(1, af.getViewport().getAlignment().getGroups().size(), 1);
995     rs = af.getViewport().getAlignment().getGroups().get(0)
996             .getGroupColourScheme();
997     assertTrue(rs.getColourScheme() instanceof StrandColourScheme);
998     assertEquals(rs.getThreshold(), 40);
999     assertTrue(rs.conservationApplied());
1000     assertEquals(rs.getConservationInc(), 30);
1001   }
1002
1003   /**
1004    * Test save and reload of feature colour schemes and filter settings
1005    * 
1006    * @throws IOException
1007    */
1008   @Test(groups = { "Functional" })
1009   public void testSaveLoadFeatureColoursAndFilters() throws IOException
1010   {
1011     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1012             ">Seq1\nACDEFGHIKLM", DataSourceType.PASTE);
1013     SequenceI seq1 = af.getViewport().getAlignment().getSequenceAt(0);
1014
1015     /*
1016      * add some features to the sequence
1017      */
1018     int score = 1;
1019     addFeatures(seq1, "type1", score++);
1020     addFeatures(seq1, "type2", score++);
1021     addFeatures(seq1, "type3", score++);
1022     addFeatures(seq1, "type4", score++);
1023     addFeatures(seq1, "type5", score++);
1024
1025     /*
1026      * set colour schemes for features
1027      */
1028     FeatureRendererModel fr = af.getFeatureRenderer();
1029     fr.findAllFeatures(true);
1030
1031     // type1: red
1032     fr.setColour("type1", new FeatureColour(Color.red));
1033
1034     // type2: by label
1035     FeatureColourI byLabel = new FeatureColour();
1036     byLabel.setColourByLabel(true);
1037     fr.setColour("type2", byLabel);
1038
1039     // type3: by score above threshold
1040     FeatureColourI byScore = new FeatureColour(null, Color.BLACK,
1041             Color.BLUE, null, 1, 10);
1042     byScore.setAboveThreshold(true);
1043     byScore.setThreshold(2f);
1044     fr.setColour("type3", byScore);
1045
1046     // type4: by attribute AF
1047     FeatureColourI byAF = new FeatureColour();
1048     byAF.setColourByLabel(true);
1049     byAF.setAttributeName("AF");
1050     fr.setColour("type4", byAF);
1051
1052     // type5: by attribute CSQ:PolyPhen below threshold
1053     FeatureColourI byPolyPhen = new FeatureColour(null, Color.BLACK,
1054             Color.BLUE, null, 1, 10);
1055     byPolyPhen.setBelowThreshold(true);
1056     byPolyPhen.setThreshold(3f);
1057     byPolyPhen.setAttributeName("CSQ", "PolyPhen");
1058     fr.setColour("type5", byPolyPhen);
1059
1060     /*
1061      * set filters for feature types
1062      */
1063
1064     // filter type1 features by (label contains "x")
1065     FeatureMatcherSetI filterByX = new FeatureMatcherSet();
1066     filterByX.and(FeatureMatcher.byLabel(Condition.Contains, "x"));
1067     fr.setFeatureFilter("type1", filterByX);
1068
1069     // filter type2 features by (score <= 2.4 and score > 1.1)
1070     FeatureMatcherSetI filterByScore = new FeatureMatcherSet();
1071     filterByScore.and(FeatureMatcher.byScore(Condition.LE, "2.4"));
1072     filterByScore.and(FeatureMatcher.byScore(Condition.GT, "1.1"));
1073     fr.setFeatureFilter("type2", filterByScore);
1074
1075     // filter type3 features by (AF contains X OR CSQ:PolyPhen != 0)
1076     FeatureMatcherSetI filterByXY = new FeatureMatcherSet();
1077     filterByXY
1078             .and(FeatureMatcher.byAttribute(Condition.Contains, "X", "AF"));
1079     filterByXY.or(FeatureMatcher.byAttribute(Condition.NE, "0", "CSQ",
1080             "PolyPhen"));
1081     fr.setFeatureFilter("type3", filterByXY);
1082
1083     /*
1084      * save as Jalview project
1085      */
1086     File tfile = File.createTempFile("JalviewTest", ".jvp");
1087     tfile.deleteOnExit();
1088     String filePath = tfile.getAbsolutePath();
1089     af.saveAlignment(filePath, FileFormat.Jalview);
1090     assertTrue(af.isSaveAlignmentSuccessful(),
1091             "Failed to store as a project.");
1092
1093     /*
1094      * close current alignment and load the saved project
1095      */
1096     af.closeMenuItem_actionPerformed(true);
1097     af = null;
1098     af = new FileLoader().LoadFileWaitTillLoaded(filePath,
1099             DataSourceType.FILE);
1100     assertNotNull(af, "Failed to import new project");
1101
1102     /*
1103      * verify restored feature colour schemes and filters
1104      */
1105     fr = af.getFeatureRenderer();
1106     FeatureColourI fc = fr.getFeatureStyle("type1");
1107     assertTrue(fc.isSimpleColour());
1108     assertEquals(fc.getColour(), Color.red);
1109     fc = fr.getFeatureStyle("type2");
1110     assertTrue(fc.isColourByLabel());
1111     fc = fr.getFeatureStyle("type3");
1112     assertTrue(fc.isGraduatedColour());
1113     assertNull(fc.getAttributeName());
1114     assertTrue(fc.isAboveThreshold());
1115     assertEquals(fc.getThreshold(), 2f);
1116     fc = fr.getFeatureStyle("type4");
1117     assertTrue(fc.isColourByLabel());
1118     assertTrue(fc.isColourByAttribute());
1119     assertEquals(fc.getAttributeName(), new String[] { "AF" });
1120     fc = fr.getFeatureStyle("type5");
1121     assertTrue(fc.isGraduatedColour());
1122     assertTrue(fc.isColourByAttribute());
1123     assertEquals(fc.getAttributeName(), new String[] { "CSQ", "PolyPhen" });
1124     assertTrue(fc.isBelowThreshold());
1125     assertEquals(fc.getThreshold(), 3f);
1126
1127     assertEquals(fr.getFeatureFilter("type1").toStableString(),
1128             "Label Contains x");
1129     assertEquals(fr.getFeatureFilter("type2").toStableString(),
1130             "(Score LE 2.4) AND (Score GT 1.1)");
1131     assertEquals(fr.getFeatureFilter("type3").toStableString(),
1132             "(AF Contains X) OR (CSQ:PolyPhen NE 0)");
1133   }
1134
1135   private void addFeature(SequenceI seq, String featureType, int score)
1136   {
1137     SequenceFeature sf = new SequenceFeature(featureType, "desc", 1, 2,
1138             score, "grp");
1139     sf.setValue("AF", score);
1140     sf.setValue("CSQ", new HashMap<String, String>()
1141     {
1142       {
1143         put("PolyPhen", Integer.toString(score));
1144       }
1145     });
1146     seq.addSequenceFeature(sf);
1147   }
1148
1149   /**
1150    * Adds two features of the given type to the given sequence, also setting the
1151    * score as the value of attribute "AF" and sub-attribute "CSQ:PolyPhen"
1152    * 
1153    * @param seq
1154    * @param featureType
1155    * @param score
1156    */
1157   private void addFeatures(SequenceI seq, String featureType, int score)
1158   {
1159     addFeature(seq, featureType, score++);
1160     addFeature(seq, featureType, score);
1161   }
1162
1163   /**
1164    * pre 2.11 - jalview 2.10 erroneously created new dataset entries for each
1165    * view (JAL-3171) this test ensures we can import and merge those views
1166    */
1167   @Test(groups = { "Functional" })
1168   public void testMergeDatasetsforViews() throws IOException
1169   {
1170     // simple project - two views on one alignment
1171     AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded(
1172             "examples/testdata/projects/twoViews.jvp", DataSourceType.FILE);
1173     assertNotNull(af);
1174     assertTrue(af.getAlignPanels().size() > 1);
1175     verifyDs(af);
1176   }
1177
1178   /**
1179    * pre 2.11 - jalview 2.10 erroneously created new dataset entries for each
1180    * view (JAL-3171) this test ensures we can import and merge those views This
1181    * is a more complex project
1182    */
1183   @Test(groups = { "Functional" })
1184   public void testMergeDatasetsforManyViews() throws IOException
1185   {
1186     Desktop.instance.closeAll_actionPerformed(null);
1187
1188     // complex project - one dataset, several views on several alignments
1189     AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded(
1190             "examples/testdata/projects/manyViews.jvp",
1191             DataSourceType.FILE);
1192     assertNotNull(af);
1193
1194     AlignmentI ds = null;
1195     for (AlignFrame alignFrame : Desktop.getAlignFrames())
1196     {
1197       if (ds == null)
1198       {
1199         ds = verifyDs(alignFrame);
1200       }
1201       else
1202       {
1203         // check that this frame's dataset matches the last
1204         assertTrue(ds == verifyDs(alignFrame));
1205       }
1206     }
1207   }
1208
1209   private AlignmentI verifyDs(AlignFrame af)
1210   {
1211     AlignmentI ds = null;
1212     for (AlignmentViewPanel ap : af.getAlignPanels())
1213     {
1214       if (ds == null)
1215       {
1216         ds = ap.getAlignment().getDataset();
1217       }
1218       else
1219       {
1220         assertTrue(ap.getAlignment().getDataset() == ds,
1221                 "Dataset was not the same for imported 2.10.5 project with several alignment views");
1222       }
1223     }
1224     return ds;
1225   }
1226
1227   @Test(groups = "Functional")
1228   public void testPcaViewAssociation() throws IOException
1229   {
1230     Desktop.instance.closeAll_actionPerformed(null);
1231     final String PCAVIEWNAME = "With PCA";
1232     // create a new tempfile
1233     File tempfile = File.createTempFile("jvPCAviewAssoc", "jvp");
1234
1235     {
1236       String exampleFile = "examples/uniref50.fa";
1237       AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(exampleFile,
1238               DataSourceType.FILE);
1239       assertNotNull(af, "Didn't read in the example file correctly.");
1240       AlignmentPanel origView = (AlignmentPanel) af.getAlignPanels().get(0);
1241       AlignmentPanel newview = af.newView(PCAVIEWNAME, true);
1242       // create another for good measure
1243       af.newView("Not the PCA View", true);
1244       PCAPanel pcaPanel = new PCAPanel(origView, "BLOSUM62",
1245               new SimilarityParams(true, true, true, false));
1246       // we're in the test exec thread, so we can just run synchronously here
1247       pcaPanel.run();
1248
1249       // now switch the linked view
1250       pcaPanel.selectAssociatedView(newview);
1251
1252       assertTrue(pcaPanel.getAlignViewport() == newview.getAlignViewport(),
1253               "PCA should be associated with 'With PCA' view: test is broken");
1254
1255       // now save and reload project
1256       Jalview2XML jv2xml = new jalview.project.Jalview2XML(false);
1257       tempfile.delete();
1258       jv2xml.saveState(tempfile);
1259       assertTrue(jv2xml.errorMessage == null,
1260               "Failed to save dummy project with PCA: test broken");
1261     }
1262
1263     // load again.
1264     Desktop.instance.closeAll_actionPerformed(null);
1265     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1266             tempfile.getCanonicalPath(), DataSourceType.FILE);
1267     JInternalFrame[] frames = Desktop.instance.getAllFrames();
1268     // PCA and the tabbed alignment view should be the only two windows on the
1269     // desktop
1270     assertEquals(frames.length, 2,
1271             "PCA and the tabbed alignment view should be the only two windows on the desktop");
1272     PCAPanel pcaPanel = (PCAPanel) frames[frames[0] == af ? 1 : 0];
1273
1274     AlignmentViewPanel restoredNewView = null;
1275     for (AlignmentViewPanel alignpanel : Desktop.getAlignmentPanels(null))
1276     {
1277       if (alignpanel.getAlignViewport() == pcaPanel.getAlignViewport())
1278       {
1279         restoredNewView = alignpanel;
1280       }
1281     }
1282     assertEquals(restoredNewView.getViewName(), PCAVIEWNAME);
1283     assertTrue(
1284             restoredNewView.getAlignViewport() == pcaPanel
1285                     .getAlignViewport(),
1286             "Didn't restore correct view association for the PCA view");
1287   }
1288
1289   /**
1290    * Test save and reload of DBRefEntry including GeneLocus in project
1291    * 
1292    * @throws Exception
1293    */
1294   @Test(groups = { "Functional" })
1295   public void testStoreAndRecoverGeneLocus() throws Exception
1296   {
1297     Desktop.instance.closeAll_actionPerformed(null);
1298     String seqData = ">P30419\nACDE\n>X1235\nGCCTGTGACGAA";
1299     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
1300             DataSourceType.PASTE);
1301     assertNotNull(af, "Didn't read in the example file correctly.");
1302
1303     AlignmentViewPanel ap = Desktop.getAlignmentPanels(null)[0];
1304     SequenceI pep = ap.getAlignment().getSequenceAt(0);
1305     SequenceI cds = ap.getAlignment().getSequenceAt(1);
1306
1307     /*
1308      * give 'protein' a dbref to self, a dbref with map to CDS,
1309      * and a dbref with map to gene 'locus'
1310      */
1311     DBRefEntry dbref1 = new DBRefEntry("Uniprot", "1", "P30419", null);
1312     pep.addDBRef(dbref1);
1313     Mapping cdsmap = new Mapping(cds,
1314             new MapList(new int[]
1315             { 1, 4 }, new int[] { 1, 12 }, 1, 3));
1316     DBRefEntry dbref2 = new DBRefEntry("EMBLCDS", "2", "X1235", cdsmap);
1317     pep.addDBRef(dbref2);
1318     Mapping locusmap = new Mapping(null,
1319             new MapList(new int[]
1320             { 1, 4 }, new int[] { 2674123, 2674135 }, 1, 3));
1321     DBRefEntry dbref3 = new GeneLocus("human", "GRCh38", "5", locusmap);
1322     pep.addDBRef(dbref3);
1323
1324     File tfile = File.createTempFile("testStoreAndRecoverGeneLocus",
1325             ".jvp");
1326     try
1327     {
1328       new Jalview2XML(false).saveState(tfile);
1329     } catch (Throwable e)
1330     {
1331       Assert.fail("Didn't save the state", e);
1332     }
1333     Desktop.instance.closeAll_actionPerformed(null);
1334
1335     new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
1336             DataSourceType.FILE);
1337     AlignmentViewPanel rap = Desktop.getAlignmentPanels(null)[0];
1338     SequenceI rpep = rap.getAlignment().getSequenceAt(0);
1339     DBModList<DBRefEntry> dbrefs = rpep.getDBRefs();
1340     assertEquals(rpep.getName(), "P30419");
1341     assertEquals(dbrefs.size(), 3);
1342     DBRefEntry dbRef = dbrefs.get(0);
1343     assertFalse(dbRef instanceof GeneLocus);
1344     assertNull(dbRef.getMap());
1345     assertEquals(dbRef, dbref1);
1346
1347     /*
1348      * restored dbrefs with mapping have a different 'map to'
1349      * sequence but otherwise match the original dbrefs
1350      */
1351     dbRef = dbrefs.get(1);
1352     assertFalse(dbRef instanceof GeneLocus);
1353     assertTrue(dbRef.equalRef(dbref2));
1354     assertNotNull(dbRef.getMap());
1355     SequenceI rcds = rap.getAlignment().getSequenceAt(1);
1356     assertSame(dbRef.getMap().getTo(), rcds);
1357     // compare MapList but not map.to
1358     assertEquals(dbRef.getMap().getMap(), dbref2.getMap().getMap());
1359
1360     /*
1361      * GeneLocus map.to is null so can compare Mapping objects
1362      */
1363     dbRef = dbrefs.get(2);
1364     assertTrue(dbRef instanceof GeneLocus);
1365     assertEquals(dbRef, dbref3);
1366   }
1367
1368   /**
1369    * test store and recovery of Overview windows
1370    * 
1371    * @throws Exception
1372    */
1373   @Test(groups = { "Functional" }, enabled = true)
1374   public void testStoreAndRecoverOverview() throws Exception
1375   {
1376     Desktop.instance.closeAll_actionPerformed(null);
1377
1378     Cache.setProperty("SHOW_OVERVIEW", "false");
1379     Cache.setProperty(Preferences.USE_LEGACY_GAP, "false");
1380     Cache.setColourProperty(Preferences.GAP_COLOUR, Color.green);
1381     Cache.setColourProperty(Preferences.HIDDEN_COLOUR, Color.yellow);
1382     Cache.setProperty(Preferences.SHOW_OV_HIDDEN_AT_START, "true");
1383
1384     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1385             "examples/uniref50.fa", DataSourceType.FILE);
1386
1387     /*
1388      * open and resize / reposition overview 
1389      */
1390     af.overviewMenuItem_actionPerformed(null);
1391     OverviewPanel ov1 = af.alignPanel.getOverviewPanel();
1392     assertNotNull(ov1);
1393     ov1.setFrameBounds(20, 30, 200, 400);
1394     assertEquals(ov1.getTitle(), "Overview examples/uniref50.fa");
1395     assertTrue(ov1.isShowHiddenRegions());
1396
1397     /*
1398      * open a New View and its Overview and reposition it
1399      */
1400     af.newView_actionPerformed(null);
1401     af.overviewMenuItem_actionPerformed(null);
1402     OverviewPanel ov2 = af.alignPanel.getOverviewPanel();
1403     assertNotNull(ov2);
1404     assertNotSame(ov1, ov2);
1405     ov2.setFrameBounds(25, 35, 205, 405);
1406     assertEquals(ov1.getTitle(), "Overview examples/uniref50.fa Original");
1407     assertEquals(ov2.getTitle(), "Overview examples/uniref50.fa View 1");
1408
1409     File tfile = File.createTempFile("testStoreAndRecoverOverview", ".jvp");
1410     new Jalview2XML(false).saveState(tfile);
1411     Desktop.instance.closeAll_actionPerformed(null);
1412
1413     /*
1414      * change preferences (should _not_ affect reloaded Overviews)
1415      */
1416     Cache.setProperty("SHOW_OVERVIEW", "true");
1417     Cache.setProperty(Preferences.USE_LEGACY_GAP, "true");
1418     Cache.setColourProperty(Preferences.GAP_COLOUR, Color.blue);
1419     Cache.setColourProperty(Preferences.HIDDEN_COLOUR, Color.orange);
1420     Cache.setProperty(Preferences.SHOW_OV_HIDDEN_AT_START, "false");
1421
1422     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
1423             DataSourceType.FILE);
1424
1425     /*
1426      * workaround: explicitly select View 1 (not in focus after restore)
1427      */
1428     af.tabSelectionChanged(1);
1429
1430     /*
1431      * verify restored overview for View 1
1432      */
1433     ov2 = af.alignPanel.getOverviewPanel();
1434     assertEquals(ov2.getCanvas().getGapColour(), Color.green);
1435     // 'non-legacy' colouring uses white for non-gapped residues
1436     assertEquals(ov2.getCanvas().getResidueColour(), Color.white);
1437     assertEquals(ov2.getCanvas().getHiddenColour(), Color.yellow);
1438     assertEquals(ov2.getTitle(), "Overview examples/uniref50.fa View 1");
1439     assertEquals(ov2.getFrameBounds(), new Rectangle(25, 35, 205, 405));
1440     assertTrue(ov2.isShowHiddenRegions());
1441
1442     /*
1443      * verify restored overview for Original view
1444      */
1445     af.tabSelectionChanged(0);
1446     ov1 = af.alignPanel.getOverviewPanel();
1447     assertEquals(ov1.getCanvas().getGapColour(), Color.green);
1448     // 'non-legacy' colouring uses white for non-gapped residues
1449     assertEquals(ov1.getCanvas().getResidueColour(), Color.white);
1450     assertEquals(ov1.getCanvas().getHiddenColour(), Color.yellow);
1451     assertEquals(ov1.getTitle(), "Overview examples/uniref50.fa Original");
1452     assertEquals(ov1.getFrameBounds(), new Rectangle(20, 30, 200, 400));
1453     assertTrue(ov1.isShowHiddenRegions());
1454   }
1455
1456   /**
1457    * Test that a view with no Overview is restored with no Overview, even if
1458    * 'Open Overview' is selected in Preferences
1459    * 
1460    * @throws Exception
1461    */
1462   @Test(groups = { "Functional" }, enabled = true)
1463   public void testStoreAndRecoverNoOverview() throws Exception
1464   {
1465     Cache.setProperty("SHOW_OVERVIEW", "false");
1466     Desktop.instance.closeAll_actionPerformed(null);
1467     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1468             ">seq1\nMATRSQFLVNF\n", DataSourceType.PASTE);
1469
1470     File tfile = File.createTempFile("testStoreAndRecoverOverview", ".jvp");
1471     new Jalview2XML(false).saveState(tfile);
1472     Desktop.instance.closeAll_actionPerformed(null);
1473
1474     Cache.setProperty("SHOW_OVERVIEW", "true");
1475     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
1476             DataSourceType.FILE);
1477
1478     assertNull(af.alignPanel.getOverviewPanel());
1479   }
1480
1481   /**
1482    * Test that loading example.jvp, doing some stuff, then hitting reload
1483    * doesn't leave the modified window still open
1484    * 
1485    * See JAL-4127 - interactively performing the same actions and reloading
1486    * works fine, but programmatically they do not
1487    * 
1488    * @throws Exception
1489    */
1490   @Test(groups = {"Functional"}, enabled=false)
1491   public void testReloadActuallyReloads() throws Exception
1492   {
1493     Desktop.instance.closeAll_actionPerformed(null);
1494     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
1495             "examples/exampleFile.jvp", DataSourceType.FILE);
1496     af.getViewport().getColumnSelection().addElement(3);
1497     af.hideSelColumns_actionPerformed(null);
1498     af.newView("new", true);
1499     af.reload_actionPerformed(null);
1500     Thread.sleep(30);
1501     // af exists still but isn't shown
1502     assertTrue(af.isClosed());
1503   }
1504 }