JAL-2717 JAL-2668 fixes to HMMER colour scheme display names, enabled state, test...
[jalview.git] / test / jalview / datamodel / ResidueCountTest.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.datamodel;
22
23 import static org.testng.Assert.assertEquals;
24 import static org.testng.Assert.assertFalse;
25 import static org.testng.Assert.assertTrue;
26
27 import jalview.datamodel.ResidueCount.SymbolCounts;
28 import jalview.gui.JvOptionPane;
29
30 import java.util.Arrays;
31
32 import org.junit.Assert;
33 import org.testng.annotations.BeforeClass;
34 import org.testng.annotations.Test;
35
36 public class ResidueCountTest
37 {
38
39   @BeforeClass(alwaysRun = true)
40   public void setUpJvOptionPane()
41   {
42     JvOptionPane.setInteractiveMode(false);
43     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
44   }
45
46   /**
47    * Test a mix of add and put for nucleotide counting
48    */
49   @Test(groups = "Functional")
50   public void test_countNucleotide()
51   {
52     ResidueCount rc = new ResidueCount(true);
53     assertEquals(rc.getCount('A'), 0);
54     assertEquals(rc.getGapCount(), 0);
55     // add then add
56     assertEquals(rc.add('A'), 1);
57     assertEquals(rc.add('a'), 2);
58     // put then add
59     rc.put('g', 3);
60     assertEquals(rc.add('G'), 4);
61     // add then put
62     assertEquals(rc.add('c'), 1);
63     rc.put('C', 4);
64     assertEquals(rc.add('N'), 1);
65
66     assertEquals(rc.getCount('a'), 2);
67     assertEquals(rc.getCount('A'), 2);
68     assertEquals(rc.getCount('G'), 4);
69     assertEquals(rc.getCount('c'), 4);
70     assertEquals(rc.getCount('T'), 0); // never seen
71     assertEquals(rc.getCount('N'), 1);
72     assertEquals(rc.getCount('?'), 0);
73     assertEquals(rc.getCount('-'), 0);
74
75     assertFalse(rc.isCountingInts());
76     assertFalse(rc.isUsingOtherData());
77   }
78
79   /**
80    * Test adding to gap count (either using addGap or add)
81    */
82   @Test(groups = "Functional")
83   public void testAddGap()
84   {
85     ResidueCount rc = new ResidueCount(true);
86     rc.addGap();
87     rc.add('-');
88     rc.add('.');
89     rc.add(' ');
90     
91     assertEquals(rc.getGapCount(), 4);
92     assertEquals(rc.getCount(' '), 4);
93     assertEquals(rc.getCount('-'), 4);
94     assertEquals(rc.getCount('.'), 4);
95     assertFalse(rc.isUsingOtherData());
96     assertFalse(rc.isCountingInts());
97   }
98
99   @Test(groups = "Functional")
100   public void testOverflow()
101   {
102     /*
103      * overflow from add
104      */
105     ResidueCount rc = new ResidueCount(true);
106     rc.addGap();
107     rc.put('A', Short.MAX_VALUE - 1);
108     assertFalse(rc.isCountingInts());
109     rc.add('A');
110     assertFalse(rc.isCountingInts());
111     rc.add('A');
112     assertTrue(rc.isCountingInts());
113     assertEquals(rc.getCount('a'), Short.MAX_VALUE + 1);
114     rc.add('A');
115     assertTrue(rc.isCountingInts());
116     assertEquals(rc.getCount('a'), Short.MAX_VALUE + 2);
117     assertEquals(rc.getGapCount(), 1);
118     rc.addGap();
119     assertEquals(rc.getGapCount(), 2);
120
121     /*
122      * overflow from put
123      */
124     rc = new ResidueCount(true);
125     rc.put('G', Short.MAX_VALUE + 1);
126     assertTrue(rc.isCountingInts());
127     assertEquals(rc.getCount('g'), Short.MAX_VALUE + 1);
128     rc.put('G', 1);
129     assertTrue(rc.isCountingInts());
130     assertEquals(rc.getCount('g'), 1);
131
132     /*
133      * underflow from put
134      */
135     rc = new ResidueCount(true);
136     rc.put('G', Short.MIN_VALUE - 1);
137     assertTrue(rc.isCountingInts());
138     assertEquals(rc.getCount('g'), Short.MIN_VALUE - 1);
139   }
140
141   /**
142    * Test a mix of add and put for peptide counting
143    */
144   @Test(groups = "Functional")
145   public void test_countPeptide()
146   {
147     ResidueCount rc = new ResidueCount(false);
148     rc.put('q', 4);
149     rc.add('Q');
150     rc.add('X');
151     rc.add('x');
152     rc.add('W');
153     rc.put('w', 7);
154     rc.put('m', 12);
155     rc.put('M', 13);
156
157     assertEquals(rc.getCount('q'), 5);
158     assertEquals(rc.getCount('X'), 2);
159     assertEquals(rc.getCount('W'), 7);
160     assertEquals(rc.getCount('m'), 13);
161     assertEquals(rc.getCount('G'), 0);
162     assertEquals(rc.getCount('-'), 0);
163
164     assertFalse(rc.isCountingInts());
165     assertFalse(rc.isUsingOtherData());
166   }
167
168   @Test(groups = "Functional")
169   public void test_unexpectedPeptide()
170   {
171     ResidueCount rc = new ResidueCount(false);
172     // expected characters (upper or lower case):
173     String aas = "ACDEFGHIKLMNPQRSTVWXY";
174     String lower = aas.toLowerCase();
175     for (int i = 0; i < aas.length(); i++)
176     {
177       rc.put(aas.charAt(i), i);
178       rc.add(lower.charAt(i));
179     }
180     for (int i = 0; i < aas.length(); i++)
181     {
182       assertEquals(rc.getCount(aas.charAt(i)), i + 1);
183     }
184     assertFalse(rc.isUsingOtherData());
185
186     rc.put('J', 4);
187     assertTrue(rc.isUsingOtherData());
188     assertEquals(rc.getCount('J'), 4);
189     rc.add('j');
190     assertEquals(rc.getCount('J'), 5);
191   }
192
193   @Test(groups = "Functional")
194   public void test_unexpectedNucleotide()
195   {
196     ResidueCount rc = new ResidueCount(true);
197     // expected characters (upper or lower case):
198     String nucs = "ACGTUN";
199     String lower = nucs.toLowerCase();
200     for (int i = 0; i < nucs.length(); i++)
201     {
202       rc.put(nucs.charAt(i), i);
203       rc.add(lower.charAt(i));
204     }
205     for (int i = 0; i < nucs.length(); i++)
206     {
207       assertEquals(rc.getCount(nucs.charAt(i)), i + 1);
208     }
209     assertFalse(rc.isUsingOtherData());
210
211     rc.add('J');
212     assertTrue(rc.isUsingOtherData());
213   }
214
215   @Test(groups = "Functional")
216   public void testGetModalCount()
217   {
218     ResidueCount rc = new ResidueCount(true);
219     rc.add('c');
220     rc.add('g');
221     rc.add('c');
222     assertEquals(rc.getModalCount(), 2);
223
224     // modal count is in the 'short overflow' counts
225     rc = new ResidueCount();
226     rc.add('c');
227     rc.put('g', Short.MAX_VALUE);
228     rc.add('G');
229     assertEquals(rc.getModalCount(), Short.MAX_VALUE + 1);
230
231     // modal count is in the 'other data' counts
232     rc = new ResidueCount(false);
233     rc.add('Q');
234     rc.add('{');
235     rc.add('{');
236     assertEquals(rc.getModalCount(), 2);
237
238     // verify modal count excludes gap
239     rc = new ResidueCount();
240     rc.add('Q');
241     rc.add('P');
242     rc.add('Q');
243     rc.addGap();
244     rc.addGap();
245     rc.addGap();
246     assertEquals(rc.getModalCount(), 2);
247   }
248
249   @Test(groups = "Functional")
250   public void testGetResiduesForCount()
251   {
252     ResidueCount rc = new ResidueCount(true);
253     rc.add('c');
254     rc.add('g');
255     rc.add('c');
256     assertEquals(rc.getResiduesForCount(2), "C");
257     assertEquals(rc.getResiduesForCount(1), "G");
258     assertEquals(rc.getResiduesForCount(3), "");
259     assertEquals(rc.getResiduesForCount(0), "");
260     assertEquals(rc.getResiduesForCount(-1), "");
261
262     // modal count is in the 'short overflow' counts
263     rc = new ResidueCount(true);
264     rc.add('c');
265     rc.put('g', Short.MAX_VALUE);
266     rc.add('G');
267     assertEquals(rc.getResiduesForCount(Short.MAX_VALUE + 1), "G");
268     assertEquals(rc.getResiduesForCount(1), "C");
269
270     // peptide modal count is in the 'short overflow' counts
271     rc = new ResidueCount(false);
272     rc.add('c');
273     rc.put('p', Short.MAX_VALUE);
274     rc.add('P');
275     assertEquals(rc.getResiduesForCount(Short.MAX_VALUE + 1), "P");
276     assertEquals(rc.getResiduesForCount(1), "C");
277   
278     // modal count is in the 'other data' counts
279     rc = new ResidueCount();
280     rc.add('Q');
281     rc.add('{');
282     rc.add('{');
283     assertEquals(rc.getResiduesForCount(1), "Q");
284     assertEquals(rc.getResiduesForCount(2), "{");
285
286     // residues share modal count
287     rc = new ResidueCount();
288     rc.add('G');
289     rc.add('G');
290     rc.add('c');
291     rc.add('C');
292     rc.add('U');
293     assertEquals(rc.getResiduesForCount(1), "U");
294     assertEquals(rc.getResiduesForCount(2), "CG");
295
296     // expected and unexpected symbols share modal count
297     rc = new ResidueCount();
298     rc.add('G');
299     rc.add('t');
300     rc.add('[');
301     rc.add('[');
302     rc.add('t');
303     rc.add('G');
304     rc.add('c');
305     rc.add('C');
306     rc.add('U');
307     assertEquals(rc.getResiduesForCount(1), "U");
308     assertEquals(rc.getResiduesForCount(2), "CGT[");
309   }
310
311   @Test(groups = "Functional")
312   public void testGetSymbolCounts_nucleotide()
313   {
314     ResidueCount rc = new ResidueCount(true);
315     rc.add('g');
316     rc.add('c');
317     rc.add('G');
318     rc.add('J'); // 'otherData'
319     rc.add('g');
320     rc.add('N');
321     rc.put('[', 0); // 'otherdata'
322
323     SymbolCounts sc = rc.getSymbolCounts();
324     Assert.assertArrayEquals(new char[] { 'C', 'G', 'N', 'J', '[' },
325             sc.symbols);
326     Assert.assertArrayEquals(new int[] { 1, 3, 1, 1, 0 }, sc.values);
327
328     // now with overflow to int counts
329     rc.put('U', Short.MAX_VALUE);
330     rc.add('u');
331     sc = rc.getSymbolCounts();
332     Assert.assertArrayEquals(new char[] { 'C', 'G', 'N', 'U', 'J', '[' },
333             sc.symbols);
334     Assert.assertArrayEquals(new int[] { 1, 3, 1, 32768, 1, 0 }, sc.values);
335   }
336
337   @Test(groups = "Functional")
338   public void testGetSymbolCounts_peptide()
339   {
340     ResidueCount rc = new ResidueCount(false);
341     rc.add('W');
342     rc.add('q');
343     rc.add('W');
344     rc.add('Z'); // 'otherData'
345     rc.add('w');
346     rc.add('L');
347
348     SymbolCounts sc = rc.getSymbolCounts();
349     Assert.assertArrayEquals(new char[] { 'L', 'Q', 'W', 'Z' }, sc.symbols);
350     Assert.assertArrayEquals(new int[] { 1, 1, 3, 1 }, sc.values);
351
352     // now with overflow to int counts
353     rc.put('W', Short.MAX_VALUE);
354     rc.add('W');
355     sc = rc.getSymbolCounts();
356     Assert.assertArrayEquals(new char[] { 'L', 'Q', 'W', 'Z' }, sc.symbols);
357     Assert.assertArrayEquals(new int[] { 1, 1, 32768, 1 }, sc.values);
358   }
359
360   @Test(groups = "Functional")
361   public void testToString()
362   {
363     ResidueCount rc = new ResidueCount();
364     rc.add('q');
365     rc.add('c');
366     rc.add('Q');
367     assertEquals(rc.toString(), "[ C:1 Q:2 ]");
368
369     // add 'other data'
370     rc.add('{');
371     assertEquals(rc.toString(), "[ C:1 Q:2 {:1 ]");
372
373     // switch from short to int counting:
374     rc.put('G', Short.MAX_VALUE);
375     rc.add('g');
376     assertEquals(rc.toString(), "[ C:1 G:32768 Q:2 {:1 ]");
377   }
378
379   @Test(groups = "Functional")
380   public void testGetTooltip()
381   {
382     ResidueCount rc = new ResidueCount();
383
384     // no counts!
385     assertEquals(rc.getTooltip(20, 1), "");
386
387     /*
388      * count 7 C, 6 K, 7 Q, 10 P, 9 W, 1 F (total 40)
389      */
390     for (int i = 0; i < 7; i++)
391     {
392       rc.add('c');
393       rc.add('q');
394     }
395     for (int i = 0; i < 10; i++)
396     {
397       rc.add('p');
398     }
399     for (int i = 0; i < 9; i++)
400     {
401       rc.add('W');
402     }
403     for (int i = 0; i < 6; i++)
404     {
405       rc.add('K');
406     }
407     rc.add('F');
408     
409     /*
410      * percentages are rounded (0.5 rounded up)
411      * 10/40 9/40 7/40 6/40 1/40
412      */
413     assertEquals(rc.getTooltip(40, 0),
414             "P 25%; W 23%; C 18%; Q 18%; K 15%; F 3%");
415
416     rc.add('Q');
417     /*
418      * 10/30 9/30 8/30 7/30 6/30 1/30
419      */
420     assertEquals(rc.getTooltip(30, 1),
421             "P 33.3%; W 30.0%; Q 26.7%; C 23.3%; K 20.0%; F 3.3%");
422   }
423
424   @Test(groups = "Functional")
425   public void testPut()
426   {
427     ResidueCount rc = new ResidueCount();
428     rc.put('q', 3);
429     assertEquals(rc.getCount('Q'), 3);
430     rc.put(' ', 4);
431     assertEquals(rc.getGapCount(), 4);
432     rc.put('.', 5);
433     assertEquals(rc.getGapCount(), 5);
434     rc.put('-', 6);
435     assertEquals(rc.getGapCount(), 6);
436
437     rc.put('?', 5);
438     assertEquals(rc.getCount('?'), 5);
439     rc.put('?', 6);
440     rc.put('!', 7);
441     assertEquals(rc.getCount('?'), 6);
442     assertEquals(rc.getCount('!'), 7);
443   }
444
445   @Test(groups = "Functional")
446   public void testConstructor_forSequences()
447   {
448     SequenceI seq1 = new Sequence("seq1", "abcde--. FCD");
449     SequenceI seq2 = new Sequence("seq2", "ab.kKqBd-.");
450     ResidueCount rc = new ResidueCount(Arrays.asList(seq1, seq2));
451
452     assertEquals(rc.getGapCount(), 7);
453     assertEquals(rc.getTotalCount(), 15); // excludes gaps
454     assertEquals(rc.getCount('a'), 2);
455     assertEquals(rc.getCount('A'), 2);
456     assertEquals(rc.getCount('B'), 3);
457     assertEquals(rc.getCount('c'), 2);
458     assertEquals(rc.getCount('D'), 3);
459     assertEquals(rc.getCount('f'), 1);
460     assertEquals(rc.getCount('K'), 2);
461     assertEquals(rc.getCount('Q'), 1);
462   }
463 }