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