Clover icon

Coverage Report

  1. Project Clover database Mon Nov 11 2024 15:14:12 GMT
  2. Package jalview.analysis

File AlignmentAnnotationUtilsTest.java

 

Code metrics

2
192
9
1
444
283
10
0.05
21.33
9
1.11

Classes

Class Line # Actions
AlignmentAnnotationUtilsTest 47 192 10
1.0100%
 

Contributing tests

This file is covered by 5 tests. .

Source view

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.analysis;
22   
23    import static org.testng.AssertJUnit.assertEquals;
24    import static org.testng.AssertJUnit.assertFalse;
25    import static org.testng.AssertJUnit.assertTrue;
26   
27    import jalview.datamodel.AlignmentAnnotation;
28    import jalview.datamodel.AlignmentI;
29    import jalview.datamodel.Annotation;
30    import jalview.datamodel.SequenceI;
31    import jalview.gui.JvOptionPane;
32    import jalview.io.DataSourceType;
33    import jalview.io.FileFormat;
34   
35    import java.io.IOException;
36    import java.util.ArrayList;
37    import java.util.BitSet;
38    import java.util.Collection;
39    import java.util.HashMap;
40    import java.util.List;
41    import java.util.Map;
42   
43    import org.testng.annotations.BeforeClass;
44    import org.testng.annotations.BeforeMethod;
45    import org.testng.annotations.Test;
46   
 
47    public class AlignmentAnnotationUtilsTest
48    {
49   
 
50  1 toggle @BeforeClass(alwaysRun = true)
51    public void setUpJvOptionPane()
52    {
53  1 JvOptionPane.setInteractiveMode(false);
54  1 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
55    }
56   
57    // 4 sequences x 13 positions
58    final static String EOL = "\n";
59   
60    // @formatter:off
61    final static String TEST_DATA =
62    ">FER_CAPAA Ferredoxin" + EOL +
63    "TIETHKEAELVG-" + EOL +
64    ">FER_CAPAN Ferredoxin, chloroplast precursor" + EOL +
65    "TIETHKEAELVG-" + EOL +
66    ">FER1_SOLLC Ferredoxin-1, chloroplast precursor" + EOL +
67    "TIETHKEEELTA-" + EOL +
68    ">Q93XJ9_SOLTU Ferredoxin I precursor" + EOL +
69    "TIETHKEEELTA-" + EOL;
70    // @formatter:on
71   
72    private static final int SEQ_ANN_COUNT = 12;
73   
74    private AlignmentI alignment;
75   
76    /**
77    * Test method that converts a (possibly null) array to a list.
78    */
 
79  1 toggle @Test(groups = { "Functional" })
80    public void testAsList()
81    {
82    // null array
83  1 Collection<AlignmentAnnotation> c1 = AlignmentAnnotationUtils
84    .asList(null);
85  1 assertTrue(c1.isEmpty());
86   
87    // empty array
88  1 AlignmentAnnotation[] anns = new AlignmentAnnotation[0];
89  1 c1 = AlignmentAnnotationUtils.asList(anns);
90  1 assertTrue(c1.isEmpty());
91   
92    // non-empty array
93  1 anns = new AlignmentAnnotation[2];
94  1 anns[0] = new AlignmentAnnotation("label0", "desc0", 0.0f);
95  1 anns[1] = new AlignmentAnnotation("label1", "desc1", 1.0f);
96  1 c1 = AlignmentAnnotationUtils.asList(anns);
97  1 assertEquals(2, c1.size());
98  1 assertTrue(c1.contains(anns[0]));
99  1 assertTrue(c1.contains(anns[1]));
100    }
101   
102    /**
103    * This output is not part of the test but may help make sense of it...
104    *
105    * @param shownTypes
106    * @param hiddenTypes
107    */
 
108  2 toggle protected void consoleDebug(Map<String, List<List<String>>> shownTypes,
109    Map<String, List<List<String>>> hiddenTypes)
110    {
111  2 for (String calcId : shownTypes.keySet())
112    {
113  3 System.out.println("Visible annotation types for calcId=" + calcId);
114  3 for (List<String> type : shownTypes.get(calcId))
115    {
116  3 System.out.println(" " + type);
117    }
118    }
119  2 for (String calcId : hiddenTypes.keySet())
120    {
121  4 System.out.println("Hidden annotation types for calcId=" + calcId);
122  4 for (List<String> type : hiddenTypes.get(calcId))
123    {
124  5 System.out.println(" " + type);
125    }
126    }
127    }
128   
129    /**
130    * Add a sequence group to the alignment with the specified sequences (base 0)
131    * in it
132    *
133    * @param i
134    * @param more
135    */
 
136  2 toggle private List<SequenceI> selectSequences(int... selected)
137    {
138  2 List<SequenceI> result = new ArrayList<SequenceI>();
139  2 SequenceI[] seqs = alignment.getSequencesArray();
140  2 for (int i : selected)
141    {
142  4 result.add(seqs[i]);
143    }
144  2 return result;
145    }
146   
147    /**
148    * Load the test alignment and generate annotations on it
149    *
150    * @throws IOException
151    */
 
152  5 toggle @BeforeMethod(alwaysRun = true)
153    public void setUp() throws IOException
154    {
155  5 alignment = new jalview.io.FormatAdapter().readFile(TEST_DATA,
156    DataSourceType.PASTE, FileFormat.Fasta);
157   
158  5 AlignmentAnnotation[] anns = new AlignmentAnnotation[SEQ_ANN_COUNT];
159  65 for (int i = 0; i < anns.length; i++)
160    {
161    /*
162    * Use the constructor for a positional annotation (with an Annotation
163    * array)
164    */
165  60 anns[i] = new AlignmentAnnotation("Label" + i, "Desc " + i,
166    new Annotation[] {});
167  60 anns[i].setCalcId("CalcId" + i);
168  60 anns[i].visible = true;
169  60 alignment.addAnnotation(anns[i]);
170    }
171    }
172   
173    /**
174    * Test a mixture of show/hidden annotations in/outside selection group.
175    */
 
176  1 toggle @Test(groups = { "Functional" })
177    public void testGetShownHiddenTypes_forSelectionGroup()
178    {
179  1 Map<String, List<List<String>>> shownTypes = new HashMap<String, List<List<String>>>();
180  1 Map<String, List<List<String>>> hiddenTypes = new HashMap<String, List<List<String>>>();
181  1 AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation();
182  1 SequenceI[] seqs = alignment.getSequencesArray();
183   
184    /*
185    * Configure annotation properties for test
186    */
187    // not in selection group (should be ignored):
188    // hidden annotation Label4 not in selection group
189  1 anns[4].sequenceRef = seqs[2];
190  1 anns[4].visible = false;
191  1 anns[7].sequenceRef = seqs[1];
192  1 anns[7].visible = true;
193   
194    /*
195    * in selection group, hidden:
196    */
197  1 anns[2].sequenceRef = seqs[3]; // CalcId2/Label2
198  1 anns[2].visible = false;
199  1 anns[3].sequenceRef = seqs[3]; // CalcId3/Label2
200  1 anns[3].visible = false;
201  1 anns[3].label = "Label2";
202  1 anns[4].sequenceRef = seqs[3]; // CalcId2/Label3
203  1 anns[4].visible = false;
204  1 anns[4].label = "Label3";
205  1 anns[4].setCalcId("CalcId2");
206  1 anns[8].sequenceRef = seqs[0]; // CalcId9/Label9
207  1 anns[8].visible = false;
208  1 anns[8].label = "Label9";
209  1 anns[8].setCalcId("CalcId9");
210    /*
211    * in selection group, visible
212    */
213  1 anns[6].sequenceRef = seqs[0]; // CalcId6/Label6
214  1 anns[6].visible = true;
215  1 anns[9].sequenceRef = seqs[3]; // CalcId9/Label9
216  1 anns[9].visible = true;
217   
218  1 List<SequenceI> selected = selectSequences(0, 3);
219  1 AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes,
220    AlignmentAnnotationUtils.asList(anns), selected);
221   
222    // check results; note CalcId9/Label9 is both hidden and shown (for
223    // different sequences) so should be in both
224    // shown: CalcId6/Label6 and CalcId9/Label9
225  1 assertEquals(2, shownTypes.size());
226  1 assertEquals(1, shownTypes.get("CalcId6").size());
227  1 assertEquals(1, shownTypes.get("CalcId6").get(0).size());
228  1 assertEquals("Label6", shownTypes.get("CalcId6").get(0).get(0));
229  1 assertEquals(1, shownTypes.get("CalcId9").size());
230  1 assertEquals(1, shownTypes.get("CalcId9").get(0).size());
231  1 assertEquals("Label9", shownTypes.get("CalcId9").get(0).get(0));
232   
233    // hidden: CalcId2/Label2, CalcId2/Label3, CalcId3/Label2, CalcId9/Label9
234  1 assertEquals(3, hiddenTypes.size());
235  1 assertEquals(2, hiddenTypes.get("CalcId2").size());
236  1 assertEquals(1, hiddenTypes.get("CalcId2").get(0).size());
237  1 assertEquals("Label2", hiddenTypes.get("CalcId2").get(0).get(0));
238  1 assertEquals(1, hiddenTypes.get("CalcId2").get(1).size());
239  1 assertEquals("Label3", hiddenTypes.get("CalcId2").get(1).get(0));
240  1 assertEquals(1, hiddenTypes.get("CalcId3").size());
241  1 assertEquals(1, hiddenTypes.get("CalcId3").get(0).size());
242  1 assertEquals("Label2", hiddenTypes.get("CalcId3").get(0).get(0));
243  1 assertEquals(1, hiddenTypes.get("CalcId9").size());
244  1 assertEquals(1, hiddenTypes.get("CalcId9").get(0).size());
245  1 assertEquals("Label9", hiddenTypes.get("CalcId9").get(0).get(0));
246   
247  1 consoleDebug(shownTypes, hiddenTypes);
248    }
249   
250    /**
251    * Test case where there are 'grouped' annotations, visible and hidden, within
252    * and without the selection group.
253    */
 
254  1 toggle @Test(groups = { "Functional" })
255    public void testGetShownHiddenTypes_withGraphGroups()
256    {
257  1 final int GROUP_3 = 3;
258  1 final int GROUP_4 = 4;
259  1 final int GROUP_5 = 5;
260  1 final int GROUP_6 = 6;
261   
262  1 Map<String, List<List<String>>> shownTypes = new HashMap<String, List<List<String>>>();
263  1 Map<String, List<List<String>>> hiddenTypes = new HashMap<String, List<List<String>>>();
264  1 AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation();
265  1 SequenceI[] seqs = alignment.getSequencesArray();
266   
267    /*
268    * Annotations for selection group and graph group
269    *
270    * Hidden annotations Label2, Label3, in (hidden) group 5
271    */
272  1 anns[2].sequenceRef = seqs[3];
273  1 anns[2].visible = false;
274  1 anns[2].graph = AlignmentAnnotation.LINE_GRAPH;
275  1 anns[2].graphGroup = GROUP_5; // not a visible group
276  1 anns[3].sequenceRef = seqs[0];
277  1 anns[3].visible = false;
278  1 anns[3].graph = AlignmentAnnotation.LINE_GRAPH;
279  1 anns[3].graphGroup = GROUP_5;
280    // need to ensure annotations have the same calcId as well
281  1 anns[3].setCalcId("CalcId2");
282    // annotations for a different hidden group generating the same group label
283  1 anns[10].sequenceRef = seqs[0];
284  1 anns[10].visible = false;
285  1 anns[10].graph = AlignmentAnnotation.LINE_GRAPH;
286  1 anns[10].graphGroup = GROUP_3;
287  1 anns[10].label = "Label3";
288  1 anns[10].setCalcId("CalcId2");
289  1 anns[11].sequenceRef = seqs[3];
290  1 anns[11].visible = false;
291  1 anns[11].graph = AlignmentAnnotation.LINE_GRAPH;
292  1 anns[11].graphGroup = GROUP_3;
293  1 anns[11].label = "Label2";
294  1 anns[11].setCalcId("CalcId2");
295   
296    // annotations Label1 (hidden), Label5 (visible) in group 6 (visible)
297  1 anns[1].sequenceRef = seqs[3];
298    // being in a visible group should take precedence over this visibility
299  1 anns[1].visible = false;
300  1 anns[1].graph = AlignmentAnnotation.LINE_GRAPH;
301  1 anns[1].graphGroup = GROUP_6;
302  1 anns[5].sequenceRef = seqs[0];
303  1 anns[5].visible = true;
304  1 anns[5].graph = AlignmentAnnotation.LINE_GRAPH;
305  1 anns[5].graphGroup = GROUP_6;
306  1 anns[5].setCalcId("CalcId1");
307    /*
308    * Annotations 0 and 4 are visible, for a different CalcId and graph group.
309    * They produce the same label as annotations 1 and 5, which should not be
310    * duplicated in the results. This case corresponds to (e.g.) many
311    * occurrences of an IUPred Short/Long annotation group, one per sequence.
312    */
313  1 anns[4].sequenceRef = seqs[0];
314  1 anns[4].visible = false;
315  1 anns[4].graph = AlignmentAnnotation.LINE_GRAPH;
316  1 anns[4].graphGroup = GROUP_4;
317  1 anns[4].label = "Label1";
318  1 anns[4].setCalcId("CalcId1");
319  1 anns[0].sequenceRef = seqs[0];
320  1 anns[0].visible = true;
321  1 anns[0].graph = AlignmentAnnotation.LINE_GRAPH;
322  1 anns[0].graphGroup = GROUP_4;
323  1 anns[0].label = "Label5";
324  1 anns[0].setCalcId("CalcId1");
325   
326    /*
327    * Annotations outwith selection group - should be ignored.
328    */
329    // Hidden grouped annotations
330  1 anns[6].sequenceRef = seqs[2];
331  1 anns[6].visible = false;
332  1 anns[6].graph = AlignmentAnnotation.LINE_GRAPH;
333  1 anns[6].graphGroup = GROUP_4;
334  1 anns[8].sequenceRef = seqs[1];
335  1 anns[8].visible = false;
336  1 anns[8].graph = AlignmentAnnotation.LINE_GRAPH;
337  1 anns[8].graphGroup = GROUP_4;
338   
339    // visible grouped annotations Label7, Label9
340  1 anns[7].sequenceRef = seqs[2];
341  1 anns[7].visible = true;
342  1 anns[7].graph = AlignmentAnnotation.LINE_GRAPH;
343  1 anns[7].graphGroup = GROUP_4;
344  1 anns[9].sequenceRef = seqs[1];
345  1 anns[9].visible = true;
346  1 anns[9].graph = AlignmentAnnotation.LINE_GRAPH;
347  1 anns[9].graphGroup = GROUP_4;
348   
349    /*
350    * Generate annotations[] arrays to match aligned columns
351    */
352    // adjustForAlignment(anns);
353   
354  1 List<SequenceI> selected = selectSequences(0, 3);
355  1 AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes,
356    AlignmentAnnotationUtils.asList(anns), selected);
357   
358  1 consoleDebug(shownTypes, hiddenTypes);
359   
360    // CalcId1 / Label1, Label5 (only) should be 'shown', once, as a compound
361    // type
362  1 assertEquals(1, shownTypes.size());
363  1 assertEquals(1, shownTypes.get("CalcId1").size());
364  1 assertEquals(2, shownTypes.get("CalcId1").get(0).size());
365  1 assertEquals("Label1", shownTypes.get("CalcId1").get(0).get(0));
366  1 assertEquals("Label5", shownTypes.get("CalcId1").get(0).get(1));
367   
368    // CalcId2 / Label2, Label3 (only) should be 'hidden'
369  1 assertEquals(1, hiddenTypes.size());
370  1 assertEquals(1, hiddenTypes.get("CalcId2").size());
371  1 assertEquals(2, hiddenTypes.get("CalcId2").get(0).size());
372  1 assertEquals("Label2", hiddenTypes.get("CalcId2").get(0).get(0));
373  1 assertEquals("Label3", hiddenTypes.get("CalcId2").get(0).get(1));
374    }
375   
376    /**
377    * Test method that determines visible graph groups.
378    */
 
379  1 toggle @Test(groups = { "Functional" })
380    public void testGetVisibleGraphGroups()
381    {
382  1 AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation();
383    /*
384    * a bar graph group is not included
385    */
386  1 anns[0].graph = AlignmentAnnotation.BAR_GRAPH;
387  1 anns[0].graphGroup = 1;
388  1 anns[0].visible = true;
389   
390    /*
391    * a line graph group is included as long as one of its members is visible
392    */
393  1 anns[1].graph = AlignmentAnnotation.LINE_GRAPH;
394  1 anns[1].graphGroup = 5;
395  1 anns[1].visible = false;
396  1 anns[2].graph = AlignmentAnnotation.LINE_GRAPH;
397  1 anns[2].graphGroup = 5;
398  1 anns[2].visible = true;
399   
400    /*
401    * a line graph group with no visible rows is not included
402    */
403  1 anns[3].graph = AlignmentAnnotation.LINE_GRAPH;
404  1 anns[3].graphGroup = 3;
405  1 anns[3].visible = false;
406   
407    // a visible line graph with no graph group is not included
408  1 anns[4].graph = AlignmentAnnotation.LINE_GRAPH;
409  1 anns[4].graphGroup = -1;
410  1 anns[4].visible = true;
411   
412  1 BitSet result = AlignmentAnnotationUtils.getVisibleLineGraphGroups(
413    AlignmentAnnotationUtils.asList(anns));
414  1 assertTrue(result.get(5));
415  1 assertFalse(result.get(0));
416  1 assertFalse(result.get(1));
417  1 assertFalse(result.get(2));
418  1 assertFalse(result.get(3));
419    }
420   
421    /**
422    * Test for case where no sequence is selected. Shouldn't normally arise but
423    * check it handles it gracefully.
424    */
 
425  1 toggle @Test(groups = { "Functional" })
426    public void testGetShownHiddenTypes_noSequenceSelected()
427    {
428  1 Map<String, List<List<String>>> shownTypes = new HashMap<String, List<List<String>>>();
429  1 Map<String, List<List<String>>> hiddenTypes = new HashMap<String, List<List<String>>>();
430  1 AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation();
431    // selected sequences null
432  1 AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes,
433    AlignmentAnnotationUtils.asList(anns), null);
434  1 assertTrue(shownTypes.isEmpty());
435  1 assertTrue(hiddenTypes.isEmpty());
436   
437  1 List<SequenceI> sequences = new ArrayList<SequenceI>();
438    // selected sequences empty list
439  1 AlignmentAnnotationUtils.getShownHiddenTypes(shownTypes, hiddenTypes,
440    AlignmentAnnotationUtils.asList(anns), sequences);
441  1 assertTrue(shownTypes.isEmpty());
442  1 assertTrue(hiddenTypes.isEmpty());
443    }
444    }