JAL-98 use Profile to store consensus, ResidueCount for fast compact
[jalview.git] / test / jalview / analysis / ResidueCountTest.java
diff --git a/test/jalview/analysis/ResidueCountTest.java b/test/jalview/analysis/ResidueCountTest.java
new file mode 100644 (file)
index 0000000..a26252c
--- /dev/null
@@ -0,0 +1,292 @@
+package jalview.analysis;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import jalview.analysis.ResidueCount.SymbolCounts;
+
+import org.junit.Assert;
+import org.testng.annotations.Test;
+
+public class ResidueCountTest
+{
+  /**
+   * Test a mix of add and put for nucleotide counting
+   */
+  @Test(groups = "Functional")
+  public void test_countNucleotide()
+  {
+    ResidueCount rc = new ResidueCount(true);
+    assertEquals(rc.getCount('A'), 0);
+    assertEquals(rc.getGapCount(), 0);
+    // add then add
+    assertEquals(rc.add('A'), 1);
+    assertEquals(rc.add('a'), 2);
+    // put then add
+    rc.put('g', 3);
+    assertEquals(rc.add('G'), 4);
+    // add then put
+    assertEquals(rc.add('c'), 1);
+    rc.put('C', 4);
+    assertEquals(rc.add('N'), 1);
+
+    assertEquals(rc.getCount('a'), 2);
+    assertEquals(rc.getCount('A'), 2);
+    assertEquals(rc.getCount('G'), 4);
+    assertEquals(rc.getCount('c'), 4);
+    assertEquals(rc.getCount('T'), 0); // never seen
+    assertEquals(rc.getCount('N'), 1);
+    assertEquals(rc.getCount('?'), 0);
+    assertEquals(rc.getCount('-'), 0);
+
+    assertFalse(rc.isCountingInts());
+    assertFalse(rc.isUsingOtherData());
+  }
+
+  /**
+   * Test adding to gap count (either using addGap or add)
+   */
+  @Test(groups = "Functional")
+  public void testAddGap()
+  {
+    ResidueCount rc = new ResidueCount(true);
+    rc.addGap();
+    rc.add('-');
+    rc.add('.');
+    rc.add(' ');
+    
+    assertEquals(rc.getGapCount(), 4);
+    assertEquals(rc.getCount(' '), 4);
+    assertEquals(rc.getCount('-'), 4);
+    assertEquals(rc.getCount('.'), 4);
+    assertFalse(rc.isUsingOtherData());
+    assertFalse(rc.isCountingInts());
+  }
+
+  @Test(groups = "Functional")
+  public void testOverflow()
+  {
+    /*
+     * overflow from add
+     */
+    ResidueCount rc = new ResidueCount(true);
+    rc.put('A', Short.MAX_VALUE - 1);
+    assertFalse(rc.isCountingInts());
+    rc.add('A');
+    assertFalse(rc.isCountingInts());
+    rc.add('A');
+    assertTrue(rc.isCountingInts());
+    assertEquals(rc.getCount('a'), Short.MAX_VALUE + 1);
+
+    /*
+     * overflow from put
+     */
+    rc = new ResidueCount(true);
+    rc.put('G', Short.MAX_VALUE + 1);
+    assertTrue(rc.isCountingInts());
+    assertEquals(rc.getCount('g'), Short.MAX_VALUE + 1);
+  }
+
+  /**
+   * Test a mix of add and put for peptide counting
+   */
+  @Test(groups = "Functional")
+  public void test_countPeptide()
+  {
+    ResidueCount rc = new ResidueCount(false);
+    rc.put('q', 4);
+    rc.add('Q');
+    rc.add('X');
+    rc.add('x');
+    rc.add('W');
+    rc.put('w', 7);
+    rc.put('m', 12);
+    rc.put('M', 13);
+
+    assertEquals(rc.getCount('q'), 5);
+    assertEquals(rc.getCount('X'), 2);
+    assertEquals(rc.getCount('W'), 7);
+    assertEquals(rc.getCount('m'), 13);
+    assertEquals(rc.getCount('G'), 0);
+    assertEquals(rc.getCount('-'), 0);
+
+    assertFalse(rc.isCountingInts());
+    assertFalse(rc.isUsingOtherData());
+  }
+
+  @Test(groups = "Functional")
+  public void test_unexpectedPeptide()
+  {
+    ResidueCount rc = new ResidueCount(false);
+    // expected characters (upper or lower case):
+    String aas = "ACDEFGHIKLMNPQRSTVWXY";
+    String lower = aas.toLowerCase();
+    for (int i = 0; i < aas.length(); i++)
+    {
+      rc.put(aas.charAt(i), i);
+      rc.add(lower.charAt(i));
+    }
+    for (int i = 0; i < aas.length(); i++)
+    {
+      assertEquals(rc.getCount(aas.charAt(i)), i + 1);
+    }
+    assertFalse(rc.isUsingOtherData());
+
+    rc.put('J', 4);
+    assertTrue(rc.isUsingOtherData());
+  }
+
+  @Test(groups = "Functional")
+  public void test_unexpectedNucleotide()
+  {
+    ResidueCount rc = new ResidueCount(true);
+    // expected characters (upper or lower case):
+    String nucs = "ACGTUN";
+    String lower = nucs.toLowerCase();
+    for (int i = 0; i < nucs.length(); i++)
+    {
+      rc.put(nucs.charAt(i), i);
+      rc.add(lower.charAt(i));
+    }
+    for (int i = 0; i < nucs.length(); i++)
+    {
+      assertEquals(rc.getCount(nucs.charAt(i)), i + 1);
+    }
+    assertFalse(rc.isUsingOtherData());
+
+    rc.add('J');
+    assertTrue(rc.isUsingOtherData());
+  }
+
+  @Test(groups = "Functional")
+  public void testGetModalCount()
+  {
+    ResidueCount rc = new ResidueCount();
+    rc.add('c');
+    rc.add('g');
+    rc.add('c');
+    assertEquals(rc.getModalCount(), 2);
+
+    // modal count is in the 'short overflow' counts
+    rc = new ResidueCount();
+    rc.add('c');
+    rc.put('g', Short.MAX_VALUE);
+    rc.add('G');
+    assertEquals(rc.getModalCount(), Short.MAX_VALUE + 1);
+
+    // modal count is in the 'other data' counts
+    rc = new ResidueCount();
+    rc.add('Q');
+    rc.add('{');
+    rc.add('{');
+    assertEquals(rc.getModalCount(), 2);
+
+    // verify modal count excludes gap
+    rc = new ResidueCount();
+    rc.add('Q');
+    rc.add('P');
+    rc.add('Q');
+    rc.addGap();
+    rc.addGap();
+    rc.addGap();
+    assertEquals(rc.getModalCount(), 2);
+  }
+
+  @Test(groups = "Functional")
+  public void testGetResiduesForCount()
+  {
+    ResidueCount rc = new ResidueCount();
+    rc.add('c');
+    rc.add('g');
+    rc.add('c');
+    assertEquals(rc.getResiduesForCount(2), "C");
+    assertEquals(rc.getResiduesForCount(1), "G");
+    assertEquals(rc.getResiduesForCount(3), "");
+    assertEquals(rc.getResiduesForCount(0), "");
+    assertEquals(rc.getResiduesForCount(-1), "");
+
+    // modal count is in the 'short overflow' counts
+    rc = new ResidueCount();
+    rc.add('c');
+    rc.put('g', Short.MAX_VALUE);
+    rc.add('G');
+    assertEquals(rc.getResiduesForCount(Short.MAX_VALUE + 1), "G");
+    assertEquals(rc.getResiduesForCount(1), "C");
+  
+    // modal count is in the 'other data' counts
+    rc = new ResidueCount();
+    rc.add('Q');
+    rc.add('{');
+    rc.add('{');
+    assertEquals(rc.getResiduesForCount(1), "Q");
+    assertEquals(rc.getResiduesForCount(2), "{");
+
+    // residues share modal count
+    rc = new ResidueCount();
+    rc.add('G');
+    rc.add('G');
+    rc.add('c');
+    rc.add('C');
+    rc.add('U');
+    assertEquals(rc.getResiduesForCount(1), "U");
+    assertEquals(rc.getResiduesForCount(2), "CG");
+
+    // expected and unexpected symbols share modal count
+    rc = new ResidueCount();
+    rc.add('G');
+    rc.add('t');
+    rc.add('[');
+    rc.add('[');
+    rc.add('t');
+    rc.add('G');
+    rc.add('c');
+    rc.add('C');
+    rc.add('U');
+    assertEquals(rc.getResiduesForCount(1), "U");
+    assertEquals(rc.getResiduesForCount(2), "CGT[");
+  }
+
+  @Test(groups = "Functional")
+  public void testGetSymbolCounts()
+  {
+    ResidueCount rc = new ResidueCount();
+    rc.add('q');
+    rc.add('c');
+    rc.add('Q');
+    rc.add('J'); // 'otherData'
+    rc.add('q');
+    rc.add('x');
+
+    SymbolCounts sc = rc.getSymbolCounts();
+    Assert.assertArrayEquals(new char[] { 'C', 'Q', 'X', 'J' }, sc.symbols);
+    Assert.assertArrayEquals(new int[] { 1, 3, 1, 1 }, sc.values);
+
+    // now with overflow to int counts
+    rc.put('g', Short.MAX_VALUE);
+    rc.add('g');
+    sc = rc.getSymbolCounts();
+    Assert.assertArrayEquals(new char[] { 'C', 'G', 'Q', 'X', 'J' },
+            sc.symbols);
+    Assert.assertArrayEquals(new int[] { 1, 32768, 3, 1, 1 }, sc.values);
+  }
+
+  @Test(groups = "Functional")
+  public void testToString()
+  {
+    ResidueCount rc = new ResidueCount();
+    rc.add('q');
+    rc.add('c');
+    rc.add('Q');
+    assertEquals(rc.toString(), "[ C:1 Q:2 ]");
+
+    // add 'other data'
+    rc.add('{');
+    assertEquals(rc.toString(), "[ C:1 Q:2 {:1 ]");
+
+    // switch from short to int counting:
+    rc.put('G', Short.MAX_VALUE);
+    rc.add('g');
+    assertEquals(rc.toString(), "[ C:1 G:32768 Q:2 {:1 ]");
+  }
+}