Merge branch 'develop' into improvement/JAL-4124_dont_duplacate_PAE_data_acrossviews
[jalview.git] / test / jalview / renderer / ContactGeometryTest.java
diff --git a/test/jalview/renderer/ContactGeometryTest.java b/test/jalview/renderer/ContactGeometryTest.java
new file mode 100644 (file)
index 0000000..6e38e89
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.renderer;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.testng.annotations.Test;
+
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactRange;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.SeqDistanceContactMatrix;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.util.MapList;
+import jalview.util.StringUtils;
+import jalview.ws.datamodel.MappableContactMatrixI;
+
+public class ContactGeometryTest
+{
+  @Test(groups="Functional")
+  public void testCoverageofRange()
+  {
+    // a really dumb test to make sure we really cover the requested pixel and
+    // contactList range for any dimension of each
+    for (int range = 12; range < 2000; range += 35)
+    {
+      StringBuilder sb = new StringBuilder();
+      while (sb.length() < range)
+      {
+        sb.append("c");
+      }
+      SequenceI sq = new Sequence("a", sb.toString());
+      MappableContactMatrixI cm = new SeqDistanceContactMatrix(range);
+      AlignmentAnnotation cm_aan = sq.addContactList(cm);
+      ContactListI cl = sq.getContactListFor(cm_aan, 10);
+      assertNotNull(cl);
+      for (int ht = range / 2; ht < range * 3; ht++)
+      {
+        ContactGeometry clgeom = new ContactGeometry(cl, ht);
+        assertNotNull(clgeom.allSteps());
+      }
+    }
+  }
+  @Test(groups = "Functional")
+  public void testContactGeometry()
+  {
+    SequenceI sq = new Sequence("a", "SSSQ");
+    MappableContactMatrixI cm = new SeqDistanceContactMatrix(4);
+    AlignmentAnnotation cm_aan = sq.addContactList(cm);
+    checkConsistencyFor(sq,cm_aan);
+    // Also check all is good when there's a sequence mapping involved
+    MappableContactMatrixI newcm=cm.liftOver(sq,
+            new Mapping(sq, new MapList(new int[]
+            { 1, 4 }, new int[] { 1, 4 }, 1, 1)));
+    AlignmentAnnotation mapped_cm = sq.addContactList(newcm);
+    checkConsistencyFor(sq,mapped_cm);    
+  }
+  // Do some asserts for a sequence and a contact matrix
+  private void checkConsistencyFor(SequenceI sq, AlignmentAnnotation cm_aan)
+  {
+    int col=1;
+    ContactListI cl = sq.getContactListFor(cm_aan, col);
+    assertNotNull(cl);
+    assertEquals(cl.getContactHeight(),4);
+    
+    // Map contacts 0 to 3 to a tiny range and check    
+    ContactGeometry  testee = new ContactGeometry(cl,2);
+    assertEquals(testee.contacts_per_pixel,2d);
+    ContactGeometry.contactInterval lastInterval = testee.mapFor(1);
+    assertEquals(lastInterval.cStart,2);
+    assertEquals(lastInterval.cEnd,3);
+    assertEquals(lastInterval.pStart,1);
+    assertEquals(lastInterval.pEnd,1);
+    ContactGeometry.contactInterval another = testee.mapFor(1,2); 
+    assertEquals(lastInterval,another);
+    // Also check for a big pixel range
+    testee = new ContactGeometry(cl, 395);
+    lastInterval = testee.mapFor(390, 395); // 395 is one over limit.
+    assertNotNull(lastInterval);
+    assertEquals(lastInterval.cEnd,3);
+    assertEquals(lastInterval.pEnd,394);
+    // Map contacts 0 to 3 to Pixels 0-9, 10-19, 20-29, 30-39
+    testee = new ContactGeometry(cl, 40);
+
+    // verify mapping from pixel to contacts
+    
+    // renderer thinks base 0 for pixel coordinates
+    // contact coordinates are base 1
+    for (int p = 0; p < 40; p++)
+    {
+      int expectC=(p / 10);
+      int expectP=(expectC)*10;
+      ContactGeometry.contactInterval ci_at = testee.mapFor(p),
+              ci_from = testee.mapFor(p, p);
+      assertNotNull(ci_at);
+      // mapFor and map should locate the same pixel window
+      assertEquals(ci_at.cStart, expectC,"Different cStart at position "+p);
+      assertEquals(ci_at.cEnd, expectC,"Different cEnd at position "+p);
+      assertEquals(ci_at.pStart,expectP, "Different pStart at position "+p);
+      assertEquals(ci_at.pEnd,expectP+9, "Different pEnd at position "+p);
+      
+      assertEquals(ci_from,ci_at, "Different contactIntervals at position "+p);
+      // also test getRangeFor
+      ContactRange cr = cl.getRangeFor(ci_at.cStart, ci_at.cEnd);
+      assertEquals(cr.getFrom_column(),cr.getTo_column());
+      assertEquals((double) cr.getMean(),(double)Math.abs(col-cr.getFrom_column()), "Didn't resolve expected value at position "+p);
+    }
+    
+    ContactGeometry.contactInterval ci_at0 = testee.mapFor(0);
+    ContactGeometry.contactInterval ci_at9 = testee.mapFor(9);
+    assertNotNull(ci_at9);
+    
+    assertEquals(ci_at0,ci_at9);
+
+    // Adjacent cell
+    ContactGeometry.contactInterval ci_at10 = testee.mapFor(10);
+    assertNotNull(ci_at10);
+    ContactGeometry.contactInterval ci_at11 = testee.mapFor(11);
+    assertNotNull(ci_at11);
+
+    assertEquals(ci_at11,ci_at10,"Off-by-one in ContactGeometry mapping.");
+
+    assertNotEquals(ci_at0,ci_at10,"Expected adjacent cells to be not equal.");
+    
+    // verify adjacent window is mapped
+    assertEquals(ci_at11.cStart,ci_at9.cStart+1);
+    
+    assertEquals(ci_at9.cEnd+1,ci_at11.cStart);
+    assertEquals(ci_at9.cEnd+1,ci_at11.cEnd);
+    
+    // verify interval/intersection
+    // column selection is base 0
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(2);
+
+    boolean mask = false;
+    do
+    {
+      assertFalse(testee.intersects(ci_at0, cs, null, mask));
+      assertFalse(testee.intersects(ci_at11, cs, null, mask));
+      assertTrue(testee.intersects(testee.mapFor(21), cs, null, mask));
+      assertFalse(testee.intersects(testee.mapFor(31), cs, null, mask));
+      cs.addElement(3);
+      assertTrue(testee.intersects(testee.mapFor(31), cs, null, mask));
+      cs.removeElement(2);
+      assertFalse(testee.intersects(testee.mapFor(21), cs, null, mask));
+      mask = !mask;
+    } while (!mask);    
+    
+  }
+}