JAL-3690 Remove references to old AlignCalcManager.
[jalview.git] / test / jalview / gui / AlignViewportTest.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.gui;
22
23 import static org.testng.AssertJUnit.assertEquals;
24 import static org.testng.AssertJUnit.assertFalse;
25 import static org.testng.AssertJUnit.assertNotNull;
26 import static org.testng.AssertJUnit.assertNotSame;
27 import static org.testng.AssertJUnit.assertSame;
28 import static org.testng.AssertJUnit.assertTrue;
29
30 import jalview.api.AlignViewportI;
31 import java.util.ArrayList;
32 import java.util.List;
33
34 import org.testng.Assert;
35 import org.testng.annotations.BeforeClass;
36 import org.testng.annotations.BeforeMethod;
37 import org.testng.annotations.Test;
38
39 import jalview.bin.Cache;
40 import jalview.bin.Jalview;
41 import jalview.datamodel.AlignedCodonFrame;
42 import jalview.datamodel.Alignment;
43 import jalview.datamodel.AlignmentAnnotation;
44 import jalview.datamodel.AlignmentI;
45 import jalview.datamodel.Annotation;
46 import jalview.datamodel.SearchResults;
47 import jalview.datamodel.SearchResultsI;
48 import jalview.datamodel.Sequence;
49 import jalview.datamodel.SequenceGroup;
50 import jalview.datamodel.SequenceI;
51 import jalview.io.DataSourceType;
52 import jalview.io.FileLoader;
53 import jalview.schemes.ClustalxColourScheme;
54 import jalview.schemes.ColourSchemeI;
55 import jalview.schemes.PIDColourScheme;
56 import jalview.structure.StructureSelectionManager;
57 import jalview.util.MapList;
58 import jalview.viewmodel.AlignmentViewport;
59 import jalview.viewmodel.ViewportRanges;
60
61 public class AlignViewportTest
62 {
63
64   @BeforeClass(alwaysRun = true)
65   public void setUpJvOptionPane()
66   {
67     JvOptionPane.setInteractiveMode(false);
68     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
69   }
70
71   AlignmentI al;
72
73   AlignmentViewport testee;
74
75   @BeforeClass(alwaysRun = true)
76   public static void setUpBeforeClass() throws Exception
77   {
78     Jalview.main(new String[] {
79         //"-jabaws", "none", 
80         "-nonews", "-props",
81         "test/jalview/testProps.jvprops" });
82
83     /*
84      * remove any sequence mappings left lying around by other tests
85      */
86     StructureSelectionManager ssm = StructureSelectionManager
87             .getStructureSelectionManager(Desktop.getInstance());
88     ssm.resetAll();
89   }
90
91   @BeforeMethod(alwaysRun = true)
92   public void setUp()
93   {
94     SequenceI seq1 = new Sequence("Seq1", "ABC");
95     SequenceI seq2 = new Sequence("Seq2", "ABC");
96     SequenceI seq3 = new Sequence("Seq3", "ABC");
97     SequenceI[] seqs = new SequenceI[] { seq1, seq2, seq3 };
98     al = new Alignment(seqs);
99     al.setDataset(null);
100     testee = new AlignViewport(al);
101   }
102
103   /**
104    * Test that a mapping is not deregistered when a second view is closed but
105    * the first still holds a reference to the mapping
106    */
107   @Test(groups = { "Functional" })
108   public void testDeregisterMapping_onCloseView()
109   {
110     /*
111      * alignment with reference to mappings
112      */
113     AlignFrame af1 = new FileLoader().LoadFileWaitTillLoaded(
114             ">Seq1\nCAGT\n", DataSourceType.PASTE);
115
116     SequenceI s1 = af1.getViewport().getAlignment().getSequenceAt(0);
117     AlignedCodonFrame acf1 = new AlignedCodonFrame();
118     acf1.addMap(s1, s1, new MapList(new int[] { 1, 4 }, new int[] { 1, 4 },
119             1, 1));
120     AlignedCodonFrame acf2 = new AlignedCodonFrame();
121     acf2.addMap(s1, s1, new MapList(new int[] { 1, 4 }, new int[] { 4, 1 },
122             1, 1));
123
124     List<AlignedCodonFrame> mappings = new ArrayList<>();
125     mappings.add(acf1);
126     mappings.add(acf2);
127     af1.getViewport().getAlignment().setCodonFrames(mappings);
128     af1.newView_actionPerformed(null);
129
130     /*
131      * Verify that creating the alignment for the new View has registered the
132      * mappings
133      */
134     StructureSelectionManager ssm = StructureSelectionManager
135             .getStructureSelectionManager(Desktop.getInstance());
136     List<AlignedCodonFrame> sequenceMappings = ssm.getSequenceMappings();
137     assertEquals(2, sequenceMappings.size());
138     assertTrue(sequenceMappings.contains(acf1));
139     assertTrue(sequenceMappings.contains(acf2));
140
141     /*
142      * Close the second view. Verify that mappings are not removed as the first
143      * view still holds a reference to them.
144      */
145     af1.closeMenuItem_actionPerformed(false);
146     assertEquals(2, sequenceMappings.size());
147     assertTrue(sequenceMappings.contains(acf1));
148     assertTrue(sequenceMappings.contains(acf2));
149   }
150
151   /**
152    * Test that a mapping is deregistered if no alignment holds a reference to it
153    */
154   @Test(groups = { "Functional" })
155   public void testDeregisterMapping_withNoReference()
156   {
157     Desktop d = Desktop.getInstance();
158     assertNotNull(d);
159     StructureSelectionManager ssm = StructureSelectionManager
160             .getStructureSelectionManager(Desktop.getInstance());
161     ssm.resetAll();
162
163     AlignFrame af1 = new FileLoader().LoadFileWaitTillLoaded(
164             ">Seq1\nRSVQ\n", DataSourceType.PASTE);
165     AlignFrame af2 = new FileLoader().LoadFileWaitTillLoaded(
166             ">Seq2\nDGEL\n", DataSourceType.PASTE);
167     SequenceI cs1 = new Sequence("cseq1", "CCCGGGTTTAAA");
168     SequenceI cs2 = new Sequence("cseq2", "CTTGAGTCTAGA");
169     SequenceI s1 = af1.getViewport().getAlignment().getSequenceAt(0);
170     SequenceI s2 = af2.getViewport().getAlignment().getSequenceAt(0);
171     // need to be distinct
172     AlignedCodonFrame acf1 = new AlignedCodonFrame();
173     acf1.addMap(cs1, s1, new MapList(new int[] { 1, 4 },
174             new int[] { 1, 12 }, 1, 3));
175     AlignedCodonFrame acf2 = new AlignedCodonFrame();
176     acf2.addMap(cs2, s2, new MapList(new int[] { 1, 4 },
177             new int[] { 1, 12 }, 1, 3));
178     AlignedCodonFrame acf3 = new AlignedCodonFrame();
179     acf3.addMap(cs2, cs2, new MapList(new int[] { 1, 12 }, new int[] { 1,
180         12 }, 1, 1));
181
182     List<AlignedCodonFrame> mappings1 = new ArrayList<>();
183     mappings1.add(acf1);
184     af1.getViewport().getAlignment().setCodonFrames(mappings1);
185
186     List<AlignedCodonFrame> mappings2 = new ArrayList<>();
187     mappings2.add(acf2);
188     mappings2.add(acf3);
189     af2.getViewport().getAlignment().setCodonFrames(mappings2);
190
191     /*
192      * AlignFrame1 has mapping acf1, AlignFrame2 has acf2 and acf3
193      */
194
195     List<AlignedCodonFrame> ssmMappings = ssm.getSequenceMappings();
196     assertEquals(0, ssmMappings.size());
197     ssm.registerMapping(acf1);
198     assertEquals(1, ssmMappings.size());
199     ssm.registerMapping(acf2);
200     assertEquals(2, ssmMappings.size());
201     ssm.registerMapping(acf3);
202     assertEquals(3, ssmMappings.size());
203
204     /*
205      * Closing AlignFrame2 should remove its mappings from
206      * StructureSelectionManager, since AlignFrame1 has no reference to them
207      */
208     af2.closeMenuItem_actionPerformed(true);
209     assertEquals(1, ssmMappings.size());
210     assertTrue(ssmMappings.contains(acf1));
211   }
212
213   /**
214    * Test that a mapping is not deregistered if another alignment holds a
215    * reference to it
216    */
217   @Test(groups = { "Functional" })
218   public void testDeregisterMapping_withReference()
219   {
220     Desktop d = Desktop.getInstance();
221     assertNotNull(d);
222     StructureSelectionManager ssm = StructureSelectionManager
223             .getStructureSelectionManager(Desktop.getInstance());
224     ssm.resetAll();
225
226     AlignFrame af1 = new FileLoader().LoadFileWaitTillLoaded(
227             ">Seq1\nRSVQ\n", DataSourceType.PASTE);
228     AlignFrame af2 = new FileLoader().LoadFileWaitTillLoaded(
229             ">Seq2\nDGEL\n", DataSourceType.PASTE);
230     SequenceI cs1 = new Sequence("cseq1", "CCCGGGTTTAAA");
231     SequenceI cs2 = new Sequence("cseq2", "CTTGAGTCTAGA");
232     SequenceI s1 = af1.getViewport().getAlignment().getSequenceAt(0);
233     SequenceI s2 = af2.getViewport().getAlignment().getSequenceAt(0);
234     // need to be distinct
235     AlignedCodonFrame acf1 = new AlignedCodonFrame();
236     acf1.addMap(cs1, s1, new MapList(new int[] { 1, 4 },
237             new int[] { 1, 12 }, 1, 3));
238     AlignedCodonFrame acf2 = new AlignedCodonFrame();
239     acf2.addMap(cs2, s2, new MapList(new int[] { 1, 4 },
240             new int[] { 1, 12 }, 1, 3));
241     AlignedCodonFrame acf3 = new AlignedCodonFrame();
242     acf3.addMap(cs2, cs2, new MapList(new int[] { 1, 12 }, new int[] { 1,
243         12 }, 1, 1));
244
245     List<AlignedCodonFrame> mappings1 = new ArrayList<>();
246     mappings1.add(acf1);
247     mappings1.add(acf2);
248     af1.getViewport().getAlignment().setCodonFrames(mappings1);
249
250     List<AlignedCodonFrame> mappings2 = new ArrayList<>();
251     mappings2.add(acf2);
252     mappings2.add(acf3);
253     af2.getViewport().getAlignment().setCodonFrames(mappings2);
254
255     /*
256      * AlignFrame1 has mappings acf1 and acf2, AlignFrame2 has acf2 and acf3
257      */
258
259     List<AlignedCodonFrame> ssmMappings = ssm.getSequenceMappings();
260     assertEquals(0, ssmMappings.size());
261     ssm.registerMapping(acf1);
262     assertEquals(1, ssmMappings.size());
263     ssm.registerMapping(acf2);
264     assertEquals(2, ssmMappings.size());
265     ssm.registerMapping(acf3);
266     assertEquals(3, ssmMappings.size());
267
268     /*
269      * Closing AlignFrame2 should remove mapping acf3 from
270      * StructureSelectionManager, but not acf2, since AlignFrame1 still has a
271      * reference to it
272      */
273     af2.closeMenuItem_actionPerformed(true);
274     assertEquals(2, ssmMappings.size());
275     assertTrue(ssmMappings.contains(acf1));
276     assertTrue(ssmMappings.contains(acf2));
277     assertFalse(ssmMappings.contains(acf3));
278   }
279
280   /**
281    * Test for JAL-1306 - conservation thread should run even when only Quality
282    * (and not Conservation) is enabled in Preferences
283    */
284   @Test(groups = { "Functional" }, timeOut=2000)
285   public void testUpdateConservation_qualityOnly()
286   {
287     Cache.setPropertyNoSave("SHOW_ANNOTATIONS",
288             Boolean.TRUE.toString());
289     Cache.setPropertyNoSave("SHOW_QUALITY",
290             Boolean.TRUE.toString());
291     Cache.setPropertyNoSave("SHOW_CONSERVATION",
292             Boolean.FALSE.toString());
293     Cache.setPropertyNoSave("SHOW_OCCUPANCY",
294             Boolean.FALSE.toString());
295     Cache.setPropertyNoSave("SHOW_IDENTITY",
296             Boolean.FALSE.toString());
297     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
298             "examples/uniref50.fa", DataSourceType.FILE);
299
300     /*
301      * wait for Conservation thread to complete
302      */
303     AlignViewport viewport = af.getViewport();
304     waitForCalculations(viewport);
305     AlignmentAnnotation[] anns = viewport.getAlignment()
306             .getAlignmentAnnotation();
307     assertNotNull("No annotations found", anns);
308     assertEquals("More than one annotation found", 1, anns.length);
309     assertTrue("Annotation is not Quality",
310             anns[0].description.startsWith("Alignment Quality"));
311     Annotation[] annotations = anns[0].annotations;
312     assertNotNull("Quality annotations are null", annotations);
313     assertNotNull("Quality in column 1 is null", annotations[0]);
314     assertTrue("No quality value in column 1", annotations[0].value > 10f);
315   }
316
317   /**
318    * Wait for consensus etc calculation threads to complete
319    * 
320    * @param viewport
321    */
322   protected void waitForCalculations(AlignViewport viewport)
323   {
324     synchronized (this)
325     {
326       System.out.print("waiting...");
327       int n = 3;
328       while (--n >= 0 || viewport.getCalcManager().isWorking())
329       {
330         try
331         {
332           wait(50);
333         } catch (InterruptedException e)
334         {
335         }
336       }
337            System.out.println("...done");
338     }
339   }
340
341   @Test(groups = { "Functional" })
342   public void testSetGlobalColourScheme()
343   {
344     /*
345      * test for JAL-2283: don't inadvertently turn on colour by conservation
346      */
347     Cache.setPropertyNoSave("DEFAULT_COLOUR_PROT", "None");
348     Cache.setPropertyNoSave("SHOW_CONSERVATION",
349             Boolean.TRUE.toString());
350     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
351             "examples/uniref50.fa", DataSourceType.FILE);
352     ColourSchemeI cs = new PIDColourScheme();
353     AlignViewport viewport = af.getViewport();
354     viewport.setGlobalColourScheme(cs);
355     assertFalse(viewport.getResidueShading()
356             .conservationApplied());
357
358     /*
359      * JAL-3201 groups have their own ColourSchemeI instances
360      */
361     AlignmentI aln = viewport.getAlignment();
362     SequenceGroup sg1 = new SequenceGroup();
363     sg1.addSequence(aln.getSequenceAt(0), false);
364     sg1.addSequence(aln.getSequenceAt(2), false);
365     SequenceGroup sg2 = new SequenceGroup();
366     sg2.addSequence(aln.getSequenceAt(1), false);
367     sg2.addSequence(aln.getSequenceAt(3), false);
368     aln.addGroup(sg1);
369     aln.addGroup(sg2);
370     viewport.setColourAppliesToAllGroups(true);
371     viewport.setGlobalColourScheme(new ClustalxColourScheme());
372     ColourSchemeI cs0 = viewport.getGlobalColourScheme();
373     ColourSchemeI cs1 = sg1.getColourScheme();
374     ColourSchemeI cs2 = sg2.getColourScheme();
375     assertTrue(cs0 instanceof ClustalxColourScheme);
376     assertTrue(cs1 instanceof ClustalxColourScheme);
377     assertTrue(cs2 instanceof ClustalxColourScheme);
378     assertNotSame(cs0, cs1);
379     assertNotSame(cs0, cs2);
380     assertNotSame(cs1, cs2);
381   }
382
383   @Test(groups = { "Functional" })
384   public void testSetGetHasSearchResults()
385   {
386     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
387             "examples/uniref50.fa", DataSourceType.FILE);
388     SearchResultsI sr = new SearchResults();
389     SequenceI s1 = af.getViewport().getAlignment().getSequenceAt(0);
390
391     // create arbitrary range on first sequence
392     sr.addResult(s1, s1.getStart() + 10, s1.getStart() + 15);
393
394     // test set
395     af.getViewport().setSearchResults(sr);
396     // has -> true
397     assertTrue(af.getViewport().hasSearchResults());
398     // get == original
399     assertEquals(sr, af.getViewport().getSearchResults());
400
401     // set(null) results in has -> false
402
403     af.getViewport().setSearchResults(null);
404     assertFalse(af.getViewport().hasSearchResults());
405   }
406
407   /**
408    * Verify that setting the selection group has the side-effect of setting the
409    * context on the group, unless it already has one, but does not change
410    * whether the group is defined or not.
411    */
412   @Test(groups = { "Functional" })
413   public void testSetSelectionGroup()
414   {
415     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
416             "examples/uniref50.fa", DataSourceType.FILE);
417     AlignViewportI av = af.getViewport();
418     SequenceGroup sg1 = new SequenceGroup();
419     SequenceGroup sg2 = new SequenceGroup();
420     SequenceGroup sg3 = new SequenceGroup();
421
422     av.setSelectionGroup(sg1);
423     assertSame(sg1.getContext(), av.getAlignment()); // context set
424     assertFalse(sg1.isDefined()); // group not defined
425
426     sg2.setContext(sg1, false);
427     av.setSelectionGroup(sg2);
428     assertFalse(sg2.isDefined()); // unchanged
429     assertSame(sg2.getContext(), sg1); // unchanged
430
431     // create a defined group
432     sg3.setContext(av.getAlignment(), true);
433     av.setSelectionGroup(sg3);
434     assertTrue(sg3.isDefined()); // unchanged
435   }
436   /**
437    * Verify that setting/clearing SHOW_OCCUPANCY preference adds or omits occupancy row from viewport
438    */
439   @Test(groups = { "Functional" })
440   public void testShowOrDontShowOccupancy()
441   {
442     // disable occupancy
443     jalview.bin.Cache.setProperty("SHOW_OCCUPANCY", Boolean.FALSE.toString());
444     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
445             "examples/uniref50.fa", DataSourceType.FILE);
446     AlignViewportI av = af.getViewport();
447     Assert.assertNull(av.getAlignmentGapAnnotation(),
448             "Preference did not disable occupancy row.");
449     int c = 0;
450     for (AlignmentAnnotation aa : av.getAlignment().findAnnotations(null,
451             null, "Occupancy"))
452     {
453       c++;
454     }
455     Assert.assertEquals(c, 0, "Expected zero occupancy rows.");
456     
457     // enable occupancy
458     jalview.bin.Cache.setProperty("SHOW_OCCUPANCY", Boolean.TRUE.toString());
459     af = new FileLoader().LoadFileWaitTillLoaded(
460             "examples/uniref50.fa", DataSourceType.FILE);
461     av = af.getViewport();
462     Assert.assertNotNull(av.getAlignmentGapAnnotation(),
463             "Preference did not enable occupancy row.");
464     c = 0;
465     for (AlignmentAnnotation aa : av.getAlignment().findAnnotations(null,
466             null, av.getAlignmentGapAnnotation().label))
467     {
468       c++;
469     }
470     ;
471     Assert.assertEquals(c, 1, "Expected to find one occupancy row.");
472   }
473
474   @Test(groups = { "Functional" })
475   public void testGetConsensusSeq()
476   {
477     /*
478      * A-C
479      * A-C
480      * A-D
481      * --D
482      * consensus expected to be A-C
483      */
484     String fasta = ">s1\nA-C\n>s2\nA-C\n>s3\nA-D\n>s4\n--D\n";
485     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(fasta,
486             DataSourceType.PASTE);
487     AlignViewport testme = af.getViewport();
488     waitForCalculations(testme);
489     SequenceI cons = testme.getConsensusSeq();
490     String s = cons.getSequenceAsString();
491     System.out.println("s is " + s);
492     
493     assertEquals("A-C", s);
494   }
495
496   @Test(groups = { "Functional" })
497   public void testHideRevealSequences()
498   {
499     ViewportRanges ranges = testee.getRanges();
500     assertEquals(3, al.getHeight());
501     assertEquals(0, ranges.getStartSeq());
502     assertEquals(2, ranges.getEndSeq());
503
504     /*
505      * hide first sequence
506      */
507     testee.hideSequence(new SequenceI[] { al.getSequenceAt(0) });
508     assertEquals(2, al.getHeight());
509     assertEquals(0, ranges.getStartSeq());
510     assertEquals(1, ranges.getEndSeq());
511
512     /*
513      * reveal hidden sequences above the first
514      */
515     testee.showSequence(0);
516     assertEquals(3, al.getHeight());
517     assertEquals(0, ranges.getStartSeq());
518     assertEquals(2, ranges.getEndSeq());
519
520     /*
521      * hide first and third sequences
522      */
523     testee.hideSequence(new SequenceI[] { al.getSequenceAt(0),
524         al.getSequenceAt(2) });
525     assertEquals(1, al.getHeight());
526     assertEquals(0, ranges.getStartSeq());
527     assertEquals(0, ranges.getEndSeq());
528
529     /*
530      * reveal all hidden sequences
531      */
532     testee.showAllHiddenSeqs();
533     assertEquals(3, al.getHeight());
534     assertEquals(0, ranges.getStartSeq());
535     assertEquals(2, ranges.getEndSeq());
536   }
537 }