JAL-2371 CollectionColourScheme wraps ColourSchemeI
[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.assertSame;
27 import static org.testng.AssertJUnit.assertTrue;
28
29 import jalview.bin.Cache;
30 import jalview.bin.Jalview;
31 import jalview.datamodel.AlignedCodonFrame;
32 import jalview.datamodel.Alignment;
33 import jalview.datamodel.AlignmentAnnotation;
34 import jalview.datamodel.AlignmentI;
35 import jalview.datamodel.Annotation;
36 import jalview.datamodel.PDBEntry;
37 import jalview.datamodel.PDBEntry.Type;
38 import jalview.datamodel.SearchResults;
39 import jalview.datamodel.SearchResultsI;
40 import jalview.datamodel.Sequence;
41 import jalview.datamodel.SequenceI;
42 import jalview.io.DataSourceType;
43 import jalview.io.FileLoader;
44 import jalview.schemes.ColourSchemeI;
45 import jalview.schemes.PIDColourScheme;
46 import jalview.structure.StructureSelectionManager;
47 import jalview.util.MapList;
48
49 import java.util.ArrayList;
50 import java.util.List;
51
52 import org.testng.annotations.BeforeClass;
53 import org.testng.annotations.BeforeMethod;
54 import org.testng.annotations.Test;
55
56 public class AlignViewportTest
57 {
58
59   @BeforeClass(alwaysRun = true)
60   public void setUpJvOptionPane()
61   {
62     JvOptionPane.setInteractiveMode(false);
63     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
64   }
65
66   AlignmentI al;
67
68   AlignViewport testee;
69
70   @BeforeClass(alwaysRun = true)
71   public static void setUpBeforeClass() throws Exception
72   {
73     Jalview.main(new String[] { "-props", "test/jalview/testProps.jvprops" });
74   }
75
76   @BeforeMethod(alwaysRun = true)
77   public void setUp()
78   {
79     SequenceI seq1 = new Sequence("Seq1", "ABC");
80     SequenceI seq2 = new Sequence("Seq2", "ABC");
81     SequenceI seq3 = new Sequence("Seq3", "ABC");
82     SequenceI[] seqs = new SequenceI[] { seq1, seq2, seq3 };
83     al = new Alignment(seqs);
84     al.setDataset(null);
85     testee = new AlignViewport(al);
86   }
87
88   @Test(groups = { "Functional" })
89   public void testCollateForPdb()
90   {
91     // JBP: What behaviour is this supposed to test ?
92     /*
93      * Set up sequence pdb ids
94      */
95     PDBEntry pdb1 = new PDBEntry("1ABC", "B", Type.PDB, "1ABC.pdb");
96     PDBEntry pdb2 = new PDBEntry("2ABC", "C", Type.PDB, "2ABC.pdb");
97     PDBEntry pdb3 = new PDBEntry("3ABC", "D", Type.PDB, "3ABC.pdb");
98
99     /*
100      * seq1 and seq3 refer to 1abcB, seq2 to 2abcC, none to 3abcD
101      */
102     al.getSequenceAt(0).getDatasetSequence()
103             .addPDBId(new PDBEntry("1ABC", "B", Type.PDB, "1ABC.pdb"));
104     al.getSequenceAt(2).getDatasetSequence()
105             .addPDBId(new PDBEntry("1ABC", "B", Type.PDB, "1ABC.pdb"));
106     al.getSequenceAt(1).getDatasetSequence()
107             .addPDBId(new PDBEntry("2ABC", "C", Type.PDB, "2ABC.pdb"));
108     /*
109      * Add a second chain PDB xref to Seq2 - should not result in a duplicate in
110      * the results
111      */
112     al.getSequenceAt(1).getDatasetSequence()
113             .addPDBId(new PDBEntry("2ABC", "D", Type.PDB, "2ABC.pdb"));
114     /*
115      * Seq3 refers to 3abc - this does not match 3ABC (as the code stands)
116      */
117     al.getSequenceAt(2).getDatasetSequence()
118             .addPDBId(new PDBEntry("3abc", "D", Type.PDB, "3ABC.pdb"));
119
120     /*
121      * run method under test
122      */
123     SequenceI[][] seqs = testee.collateForPDB(new PDBEntry[] { pdb1, pdb2,
124         pdb3 });
125
126     // seq1 and seq3 refer to PDBEntry[0]
127     assertEquals(2, seqs[0].length);
128     assertSame(al.getSequenceAt(0), seqs[0][0]);
129     assertSame(al.getSequenceAt(2), seqs[0][1]);
130
131     // seq2 refers to PDBEntry[1]
132     assertEquals(1, seqs[1].length);
133     assertSame(al.getSequenceAt(1), seqs[1][0]);
134
135     // no sequence refers to PDBEntry[2]
136     assertEquals(0, seqs[2].length);
137   }
138
139   /**
140    * Test that a mapping is not deregistered when a second view is closed but
141    * the first still holds a reference to the mapping
142    */
143   @Test(groups = { "Functional" })
144   public void testDeregisterMapping_onCloseView()
145   {
146     /*
147      * alignment with reference to mappings
148      */
149     AlignFrame af1 = new FileLoader().LoadFileWaitTillLoaded(
150             ">Seq1\nCAGT\n", DataSourceType.PASTE);
151
152     SequenceI s1 = af1.getViewport().getAlignment().getSequenceAt(0);
153     AlignedCodonFrame acf1 = new AlignedCodonFrame();
154     acf1.addMap(s1, s1, new MapList(new int[] { 1, 4 }, new int[] { 1, 4 },
155             1, 1));
156     AlignedCodonFrame acf2 = new AlignedCodonFrame();
157     acf2.addMap(s1, s1, new MapList(new int[] { 1, 4 }, new int[] { 4, 1 },
158             1, 1));
159
160     List<AlignedCodonFrame> mappings = new ArrayList<AlignedCodonFrame>();
161     mappings.add(acf1);
162     mappings.add(acf2);
163     af1.getViewport().getAlignment().setCodonFrames(mappings);
164     af1.newView_actionPerformed(null);
165
166     /*
167      * Verify that creating the alignment for the new View has registered the
168      * mappings
169      */
170     StructureSelectionManager ssm = StructureSelectionManager
171             .getStructureSelectionManager(Desktop.instance);
172     assertEquals(2, ssm.getSequenceMappings().size());
173     assertTrue(ssm.getSequenceMappings().contains(acf1));
174     assertTrue(ssm.getSequenceMappings().contains(acf2));
175
176     /*
177      * Close the second view. Verify that mappings are not removed as the first
178      * view still holds a reference to them.
179      */
180     af1.closeMenuItem_actionPerformed(false);
181     assertEquals(2, ssm.getSequenceMappings().size());
182     assertTrue(ssm.getSequenceMappings().contains(acf1));
183     assertTrue(ssm.getSequenceMappings().contains(acf2));
184   }
185
186   /**
187    * Test that a mapping is deregistered if no alignment holds a reference to it
188    */
189   @Test(groups = { "Functional" })
190   public void testDeregisterMapping_withNoReference()
191   {
192     Desktop d = Desktop.instance;
193     assertNotNull(d);
194     StructureSelectionManager ssm = StructureSelectionManager
195             .getStructureSelectionManager(Desktop.instance);
196     ssm.resetAll();
197
198     AlignFrame af1 = new FileLoader().LoadFileWaitTillLoaded(
199             ">Seq1\nRSVQ\n", DataSourceType.PASTE);
200     AlignFrame af2 = new FileLoader().LoadFileWaitTillLoaded(
201             ">Seq2\nDGEL\n", DataSourceType.PASTE);
202     SequenceI cs1 = new Sequence("cseq1", "CCCGGGTTTAAA");
203     SequenceI cs2 = new Sequence("cseq2", "CTTGAGTCTAGA");
204     SequenceI s1 = af1.getViewport().getAlignment().getSequenceAt(0);
205     SequenceI s2 = af2.getViewport().getAlignment().getSequenceAt(0);
206     // need to be distinct
207     AlignedCodonFrame acf1 = new AlignedCodonFrame();
208     acf1.addMap(cs1, s1, new MapList(new int[] { 1, 4 },
209             new int[] { 1, 12 }, 1, 3));
210     AlignedCodonFrame acf2 = new AlignedCodonFrame();
211     acf2.addMap(cs2, s2, new MapList(new int[] { 1, 4 },
212             new int[] { 1, 12 }, 1, 3));
213     AlignedCodonFrame acf3 = new AlignedCodonFrame();
214     acf3.addMap(cs2, cs2, new MapList(new int[] { 1, 12 }, new int[] { 1,
215         12 }, 1, 1));
216
217     List<AlignedCodonFrame> mappings1 = new ArrayList<AlignedCodonFrame>();
218     mappings1.add(acf1);
219     af1.getViewport().getAlignment().setCodonFrames(mappings1);
220
221     List<AlignedCodonFrame> mappings2 = new ArrayList<AlignedCodonFrame>();
222     mappings2.add(acf2);
223     mappings2.add(acf3);
224     af2.getViewport().getAlignment().setCodonFrames(mappings2);
225
226     /*
227      * AlignFrame1 has mapping acf1, AlignFrame2 has acf2 and acf3
228      */
229
230     List<AlignedCodonFrame> ssmMappings = ssm.getSequenceMappings();
231     assertEquals(0, ssmMappings.size());
232     ssm.registerMapping(acf1);
233     assertEquals(1, ssmMappings.size());
234     ssm.registerMapping(acf2);
235     assertEquals(2, ssmMappings.size());
236     ssm.registerMapping(acf3);
237     assertEquals(3, ssmMappings.size());
238
239     /*
240      * Closing AlignFrame2 should remove its mappings from
241      * StructureSelectionManager, since AlignFrame1 has no reference to them
242      */
243     af2.closeMenuItem_actionPerformed(true);
244     assertEquals(1, ssmMappings.size());
245     assertTrue(ssmMappings.contains(acf1));
246   }
247
248   /**
249    * Test that a mapping is not deregistered if another alignment holds a
250    * reference to it
251    */
252   @Test(groups = { "Functional" })
253   public void testDeregisterMapping_withReference()
254   {
255     Desktop d = Desktop.instance;
256     assertNotNull(d);
257     StructureSelectionManager ssm = StructureSelectionManager
258             .getStructureSelectionManager(Desktop.instance);
259     ssm.resetAll();
260
261     AlignFrame af1 = new FileLoader().LoadFileWaitTillLoaded(
262             ">Seq1\nRSVQ\n", DataSourceType.PASTE);
263     AlignFrame af2 = new FileLoader().LoadFileWaitTillLoaded(
264             ">Seq2\nDGEL\n", DataSourceType.PASTE);
265     SequenceI cs1 = new Sequence("cseq1", "CCCGGGTTTAAA");
266     SequenceI cs2 = new Sequence("cseq2", "CTTGAGTCTAGA");
267     SequenceI s1 = af1.getViewport().getAlignment().getSequenceAt(0);
268     SequenceI s2 = af2.getViewport().getAlignment().getSequenceAt(0);
269     // need to be distinct
270     AlignedCodonFrame acf1 = new AlignedCodonFrame();
271     acf1.addMap(cs1, s1, new MapList(new int[] { 1, 4 },
272             new int[] { 1, 12 }, 1, 3));
273     AlignedCodonFrame acf2 = new AlignedCodonFrame();
274     acf2.addMap(cs2, s2, new MapList(new int[] { 1, 4 },
275             new int[] { 1, 12 }, 1, 3));
276     AlignedCodonFrame acf3 = new AlignedCodonFrame();
277     acf3.addMap(cs2, cs2, new MapList(new int[] { 1, 12 }, new int[] { 1,
278         12 }, 1, 1));
279
280     List<AlignedCodonFrame> mappings1 = new ArrayList<AlignedCodonFrame>();
281     mappings1.add(acf1);
282     mappings1.add(acf2);
283     af1.getViewport().getAlignment().setCodonFrames(mappings1);
284
285     List<AlignedCodonFrame> mappings2 = new ArrayList<AlignedCodonFrame>();
286     mappings2.add(acf2);
287     mappings2.add(acf3);
288     af2.getViewport().getAlignment().setCodonFrames(mappings2);
289
290     /*
291      * AlignFrame1 has mappings acf1 and acf2, AlignFrame2 has acf2 and acf3
292      */
293
294     List<AlignedCodonFrame> ssmMappings = ssm.getSequenceMappings();
295     assertEquals(0, ssmMappings.size());
296     ssm.registerMapping(acf1);
297     assertEquals(1, ssmMappings.size());
298     ssm.registerMapping(acf2);
299     assertEquals(2, ssmMappings.size());
300     ssm.registerMapping(acf3);
301     assertEquals(3, ssmMappings.size());
302
303     /*
304      * Closing AlignFrame2 should remove mapping acf3 from
305      * StructureSelectionManager, but not acf2, since AlignFrame1 still has a
306      * reference to it
307      */
308     af2.closeMenuItem_actionPerformed(true);
309     assertEquals(2, ssmMappings.size());
310     assertTrue(ssmMappings.contains(acf1));
311     assertTrue(ssmMappings.contains(acf2));
312     assertFalse(ssmMappings.contains(acf3));
313   }
314
315   /**
316    * Test for JAL-1306 - conservation thread should run even when only Quality
317    * (and not Conservation) is enabled in Preferences
318    */
319   @Test(groups = { "Functional" })
320   public void testUpdateConservation_qualityOnly()
321   {
322     Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS",
323             Boolean.TRUE.toString());
324     Cache.applicationProperties.setProperty("SHOW_QUALITY",
325             Boolean.TRUE.toString());
326     Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
327             Boolean.FALSE.toString());
328     Cache.applicationProperties.setProperty("SHOW_IDENTITY",
329             Boolean.FALSE.toString());
330     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
331             "examples/uniref50.fa", DataSourceType.FILE);
332     AlignmentAnnotation[] anns = af.viewport.getAlignment()
333             .getAlignmentAnnotation();
334     assertNotNull("No annotations found", anns);
335     assertEquals("More than one annotation found", 1, anns.length);
336     assertTrue("Annotation is not Quality",
337             anns[0].description.startsWith("Alignment Quality"));
338     Annotation[] annotations = anns[0].annotations;
339     assertNotNull("Quality annotations are null", annotations);
340     assertNotNull("Quality in column 1 is null", annotations[0]);
341     assertTrue("No quality value in column 1", annotations[0].value > 10f);
342   }
343
344   @Test(groups = { "Functional" })
345   public void testSetGlobalColourScheme()
346   {
347     /*
348      * test for JAL-2283: don't inadvertently turn on colour by conservation
349      */
350     Cache.applicationProperties.setProperty("DEFAULT_COLOUR_PROT", "None");
351     Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
352             Boolean.TRUE.toString());
353     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
354             "examples/uniref50.fa", DataSourceType.FILE);
355     ColourSchemeI cs = new PIDColourScheme();
356     af.getViewport().setGlobalColourScheme(cs);
357     assertFalse(af.getViewport().getViewportColourScheme()
358             .conservationApplied());
359   }
360
361   @Test(groups = { "Functional" })
362   public void testSetGetHasSearchResults()
363   {
364     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
365             "examples/uniref50.fa", DataSourceType.FILE);
366     SearchResultsI sr = new SearchResults();
367     SequenceI s1 = af.getViewport().getAlignment().getSequenceAt(0);
368
369     // create arbitrary range on first sequence
370     sr.addResult(s1, s1.getStart() + 10, s1.getStart() + 15);
371
372     // test set
373     af.getViewport().setSearchResults(sr);
374     // has -> true
375     assertTrue(af.getViewport().hasSearchResults());
376     // get == original
377     assertEquals(sr, af.getViewport().getSearchResults());
378
379     // set(null) results in has -> false
380
381     af.getViewport().setSearchResults(null);
382     assertFalse(af.getViewport().hasSearchResults());
383   }
384 }