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