JAL-2480 cache min-max score values per sequence and feature type
[jalview.git] / test / jalview / datamodel / features / SequenceFeaturesTest.java
index 4b7609a..eaf20b0 100644 (file)
@@ -16,7 +16,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testGetPositionalFeatures()
   {
-    SequenceFeatures store = new SequenceFeatures();
+    SequenceFeaturesI store = new SequenceFeatures();
     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
             Float.NaN, null);
     store.add(sf1);
@@ -70,7 +70,7 @@ public class SequenceFeaturesTest
     /*
      * get features by type
      */
-    assertTrue(store.getPositionalFeatures(null).isEmpty());
+    assertTrue(store.getPositionalFeatures((String) null).isEmpty());
     assertTrue(store.getPositionalFeatures("Cath").isEmpty());
     assertTrue(store.getPositionalFeatures("METAL").isEmpty());
 
@@ -96,7 +96,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testGetContactFeatures()
   {
-    SequenceFeatures store = new SequenceFeatures();
+    SequenceFeaturesI store = new SequenceFeatures();
     // non-contact
     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
             Float.NaN, null);
@@ -131,7 +131,7 @@ public class SequenceFeaturesTest
     /*
      * get contact features by type
      */
-    assertTrue(store.getContactFeatures(null).isEmpty());
+    assertTrue(store.getContactFeatures((String) null).isEmpty());
     assertTrue(store.getContactFeatures("Cath").isEmpty());
     assertTrue(store.getContactFeatures("Pfam").isEmpty());
     assertTrue(store.getContactFeatures("DISULPHIDE BOND").isEmpty());
@@ -148,7 +148,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testGetNonPositionalFeatures()
   {
-    SequenceFeatures store = new SequenceFeatures();
+    SequenceFeaturesI store = new SequenceFeatures();
     // positional
     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
             Float.NaN, null);
@@ -188,7 +188,7 @@ public class SequenceFeaturesTest
     /*
      * get non-positional features by type
      */
-    assertTrue(store.getNonPositionalFeatures(null).isEmpty());
+    assertTrue(store.getNonPositionalFeatures((String) null).isEmpty());
     assertTrue(store.getNonPositionalFeatures("Cath").isEmpty());
     assertTrue(store.getNonPositionalFeatures("PFAM").isEmpty());
   
@@ -211,7 +211,7 @@ public class SequenceFeaturesTest
    * @param to
    * @return
    */
-  SequenceFeature addFeature(SequenceFeatures sf, String type, int from,
+  SequenceFeature addFeature(SequenceFeaturesI sf, String type, int from,
           int to)
   {
     SequenceFeature sf1 = new SequenceFeature(type, "", from, to,
@@ -224,7 +224,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testFindFeatures()
   {
-    SequenceFeatures sf = new SequenceFeatures();
+    SequenceFeaturesI sf = new SequenceFeatures();
     SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
     SequenceFeature sf2 = addFeature(sf, "Pfam", 1, 15);
     SequenceFeature sf3 = addFeature(sf, "Pfam", 20, 30);
@@ -240,36 +240,36 @@ public class SequenceFeaturesTest
     // null type is weird but possible:
     SequenceFeature sf13 = addFeature(sf, null, 5, 12);
   
-    List<SequenceFeature> overlaps = sf.findFeatures("Pfam", 200, 200);
+    List<SequenceFeature> overlaps = sf.findFeatures(200, 200, "Pfam");
     assertTrue(overlaps.isEmpty());
   
-    overlaps = sf.findFeatures("Pfam", 1, 9);
+    overlaps = sf.findFeatures( 1, 9, "Pfam");
     assertEquals(overlaps.size(), 1);
     assertTrue(overlaps.contains(sf2));
   
-    overlaps = sf.findFeatures("Pfam", 5, 18);
+    overlaps = sf.findFeatures( 5, 18, "Pfam");
     assertEquals(overlaps.size(), 2);
     assertTrue(overlaps.contains(sf1));
     assertTrue(overlaps.contains(sf2));
   
-    overlaps = sf.findFeatures("Pfam", 30, 40);
+    overlaps = sf.findFeatures(30, 40, "Pfam");
     assertEquals(overlaps.size(), 3);
     assertTrue(overlaps.contains(sf1));
     assertTrue(overlaps.contains(sf3));
     assertTrue(overlaps.contains(sf4));
   
-    overlaps = sf.findFeatures("Pfam", 80, 90);
+    overlaps = sf.findFeatures( 80, 90, "Pfam");
     assertEquals(overlaps.size(), 2);
     assertTrue(overlaps.contains(sf4));
     assertTrue(overlaps.contains(sf5));
   
-    overlaps = sf.findFeatures("Pfam", 68, 70);
+    overlaps = sf.findFeatures( 68, 70, "Pfam");
     assertEquals(overlaps.size(), 3);
     assertTrue(overlaps.contains(sf4));
     assertTrue(overlaps.contains(sf5));
     assertTrue(overlaps.contains(sf6));
 
-    overlaps = sf.findFeatures("Cath", 16, 69);
+    overlaps = sf.findFeatures(16, 69, "Cath");
     assertEquals(overlaps.size(), 4);
     assertTrue(overlaps.contains(sf7));
     assertFalse(overlaps.contains(sf8));
@@ -278,9 +278,9 @@ public class SequenceFeaturesTest
     assertTrue(overlaps.contains(sf11));
     assertFalse(overlaps.contains(sf12));
 
-    assertTrue(sf.findFeatures("Metal", 0, 1000).isEmpty());
+    assertTrue(sf.findFeatures(0, 1000, "Metal").isEmpty());
 
-    overlaps = sf.findFeatures(null, 7, 7);
+    overlaps = sf.findFeatures(7, 7, (String) null);
     assertEquals(overlaps.size(), 1);
     assertTrue(overlaps.contains(sf13));
   }
@@ -288,7 +288,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testDelete()
   {
-    SequenceFeatures sf = new SequenceFeatures();
+    SequenceFeaturesI sf = new SequenceFeatures();
     SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
     assertTrue(sf.getPositionalFeatures().contains(sf1));
 
@@ -302,7 +302,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testHasFeatures()
   {
-    SequenceFeatures sf = new SequenceFeatures();
+    SequenceFeaturesI sf = new SequenceFeatures();
     assertFalse(sf.hasFeatures());
 
     SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
@@ -319,7 +319,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testGetFeatureGroups()
   {
-    SequenceFeatures sf = new SequenceFeatures();
+    SequenceFeaturesI sf = new SequenceFeatures();
     assertTrue(sf.getFeatureGroups(true).isEmpty());
     assertTrue(sf.getFeatureGroups(false).isEmpty());
 
@@ -412,7 +412,7 @@ public class SequenceFeaturesTest
   @Test(groups = "Functional")
   public void testGetFeatureTypesForGroups()
   {
-    SequenceFeatures sf = new SequenceFeatures();
+    SequenceFeaturesI sf = new SequenceFeatures();
     assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
   
     /*
@@ -493,4 +493,341 @@ public class SequenceFeaturesTest
     assertTrue(groups.contains("turn"));
     assertTrue(groups.contains("strand"));
   }
+
+  @Test(groups = "Functional")
+  public void testGetFeatureTypes()
+  {
+    SequenceFeaturesI store = new SequenceFeatures();
+    Set<String> types = store.getFeatureTypes();
+    assertTrue(types.isEmpty());
+
+    SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
+            Float.NaN, null);
+    store.add(sf1);
+    types = store.getFeatureTypes();
+    assertEquals(types.size(), 1);
+    assertTrue(types.contains("Metal"));
+
+    // null type is possible...
+    SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20,
+            Float.NaN, null);
+    store.add(sf2);
+    types = store.getFeatureTypes();
+    assertEquals(types.size(), 2);
+    assertTrue(types.contains(null));
+    assertTrue(types.contains("Metal"));
+
+    /*
+     * add non-positional feature
+     */
+    SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
+            Float.NaN, null);
+    store.add(sf3);
+    types = store.getFeatureTypes();
+    assertEquals(types.size(), 3);
+    assertTrue(types.contains("Pfam"));
+
+    /*
+     * add contact feature
+     */
+    SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc",
+            10, 20, Float.NaN, null);
+    store.add(sf4);
+    types = store.getFeatureTypes();
+    assertEquals(types.size(), 4);
+    assertTrue(types.contains("Disulphide Bond"));
+
+    /*
+     * add another Pfam
+     */
+    SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
+            Float.NaN, null);
+    store.add(sf5);
+    types = store.getFeatureTypes();
+    assertEquals(types.size(), 4); // unchanged
+
+    /*
+     * delete first Pfam - still have one
+     */
+    assertTrue(store.delete(sf3));
+    types = store.getFeatureTypes();
+    assertEquals(types.size(), 4);
+    assertTrue(types.contains("Pfam"));
+
+    /*
+     * delete second Pfam - no longer have one
+     */
+    assertTrue(store.delete(sf5));
+    types = store.getFeatureTypes();
+    assertEquals(types.size(), 3);
+    assertFalse(types.contains("Pfam"));
+  }
+
+  @Test(groups = "Functional")
+  public void testGetFeatureCount()
+  {
+    SequenceFeaturesI store = new SequenceFeatures();
+    assertEquals(store.getFeatureCount(true), 0);
+    assertEquals(store.getFeatureCount(false), 0);
+  
+    /*
+     * add positional
+     */
+    SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
+            Float.NaN, null);
+    store.add(sf1);
+    assertEquals(store.getFeatureCount(true), 1);
+    assertEquals(store.getFeatureCount(false), 0);
+
+    /*
+     * another positional
+     */
+    SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20,
+            Float.NaN, null);
+    store.add(sf2);
+    assertEquals(store.getFeatureCount(true), 2);
+    assertEquals(store.getFeatureCount(false), 0);
+  
+    /*
+     * add non-positional feature
+     */
+    SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
+            Float.NaN, null);
+    store.add(sf3);
+    assertEquals(store.getFeatureCount(true), 2);
+    assertEquals(store.getFeatureCount(false), 1);
+  
+    /*
+     * add contact feature (counts as 1)
+     */
+    SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc",
+            10, 20, Float.NaN, null);
+    store.add(sf4);
+    assertEquals(store.getFeatureCount(true), 3);
+    assertEquals(store.getFeatureCount(false), 1);
+  
+    /*
+     * add another Pfam
+     */
+    SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
+            Float.NaN, null);
+    store.add(sf5);
+    assertEquals(store.getFeatureCount(true), 4);
+    assertEquals(store.getFeatureCount(false), 1);
+    assertEquals(store.getFeatureCount(true, "Pfam"), 1);
+    assertEquals(store.getFeatureCount(false, "Pfam"), 1);
+    // search for type==null
+    assertEquals(store.getFeatureCount(true, (String) null), 1);
+    // search with no type specified
+    assertEquals(store.getFeatureCount(true, (String[]) null), 4);
+    assertEquals(store.getFeatureCount(true, "Metal", "Cath"), 1);
+    assertEquals(store.getFeatureCount(true, "Disulphide Bond"), 1);
+    assertEquals(store.getFeatureCount(true, "Metal", "Pfam", null), 3);
+
+    /*
+     * delete first Pfam (non-positional)
+     */
+    assertTrue(store.delete(sf3));
+    assertEquals(store.getFeatureCount(true), 4);
+    assertEquals(store.getFeatureCount(false), 0);
+  
+    /*
+     * delete second Pfam (positional)
+     */
+    assertTrue(store.delete(sf5));
+    assertEquals(store.getFeatureCount(true), 3);
+    assertEquals(store.getFeatureCount(false), 0);
+  }
+
+  @Test(groups = "Functional")
+  public void testGetAllFeatures()
+  {
+    SequenceFeaturesI store = new SequenceFeatures();
+    List<SequenceFeature> features = store.getAllFeatures();
+    assertTrue(features.isEmpty());
+  
+    SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
+            Float.NaN, null);
+    store.add(sf1);
+    features = store.getAllFeatures();
+    assertEquals(features.size(), 1);
+    assertTrue(features.contains(sf1));
+  
+    SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20,
+            Float.NaN, null);
+    store.add(sf2);
+    features = store.getAllFeatures();
+    assertEquals(features.size(), 2);
+    assertTrue(features.contains(sf2));
+  
+    /*
+     * add non-positional feature
+     */
+    SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
+            Float.NaN, null);
+    store.add(sf3);
+    features = store.getAllFeatures();
+    assertEquals(features.size(), 3);
+    assertTrue(features.contains(sf3));
+  
+    /*
+     * add contact feature
+     */
+    SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc",
+            10, 20, Float.NaN, null);
+    store.add(sf4);
+    features = store.getAllFeatures();
+    assertEquals(features.size(), 4);
+    assertTrue(features.contains(sf4));
+  
+    /*
+     * add another Pfam
+     */
+    SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
+            Float.NaN, null);
+    store.add(sf5);
+    features = store.getAllFeatures();
+    assertEquals(features.size(), 5);
+    assertTrue(features.contains(sf5));
+    features = store.getAllFeatures("Cath");
+    assertTrue(features.isEmpty());
+    features = store.getAllFeatures("Pfam", "Cath", "Metal");
+    assertEquals(features.size(), 3);
+    assertTrue(features.contains(sf1));
+    assertTrue(features.contains(sf3));
+    assertTrue(features.contains(sf5));
+  
+    /*
+     * delete first Pfam
+     */
+    assertTrue(store.delete(sf3));
+    features = store.getAllFeatures();
+    assertEquals(features.size(), 4);
+    assertFalse(features.contains(sf3));
+  
+    /*
+     * delete second Pfam
+     */
+    assertTrue(store.delete(sf5));
+    features = store.getAllFeatures();
+    assertEquals(features.size(), 3);
+    assertFalse(features.contains(sf3));
+  }
+
+  @Test(groups = "Functional")
+  public void testGetTotalFeatureLength()
+  {
+    SequenceFeaturesI store = new SequenceFeatures();
+    assertEquals(store.getTotalFeatureLength(), 0);
+
+    SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
+            Float.NaN, null);
+    assertTrue(store.add(sf1));
+    assertEquals(store.getTotalFeatureLength(), 11);
+
+    // re-add does nothing!
+    assertFalse(store.add(sf1));
+    assertEquals(store.getTotalFeatureLength(), 11);
+
+    /*
+     * add non-positional feature
+     */
+    SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
+            Float.NaN, null);
+    store.add(sf3);
+    assertEquals(store.getTotalFeatureLength(), 11);
+
+    /*
+     * add contact feature - counts 1 to feature length
+     */
+    SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc",
+            10, 20, Float.NaN, null);
+    store.add(sf4);
+    assertEquals(store.getTotalFeatureLength(), 12);
+
+    /*
+     * add another Pfam
+     */
+    SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
+            Float.NaN, null);
+    store.add(sf5);
+    assertEquals(store.getTotalFeatureLength(), 23);
+
+    /*
+     * delete features
+     */
+    assertTrue(store.delete(sf3)); // non-positional
+    assertEquals(store.getTotalFeatureLength(), 23); // no change
+
+    assertTrue(store.delete(sf5));
+    assertEquals(store.getTotalFeatureLength(), 12);
+
+    assertTrue(store.delete(sf4)); // contact
+    assertEquals(store.getTotalFeatureLength(), 11);
+
+    assertTrue(store.delete(sf1));
+    assertEquals(store.getTotalFeatureLength(), 0);
+  }
+
+  @Test
+  public void testGetMinimumScore_getMaximumScore()
+  {
+    SequenceFeatures sf = new SequenceFeatures();
+    SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 0, 0,
+            Float.NaN, "group"); // non-positional, no score
+    sf.add(sf1);
+    SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 10, 20,
+            Float.NaN, "group"); // positional, no score
+    sf.add(sf2);
+    SequenceFeature sf3 = new SequenceFeature("Metal", "desc", 10, 20, 1f,
+            "group");
+    sf.add(sf3);
+    SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 12, 16, 4f,
+            "group");
+    sf.add(sf4);
+    SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 0, 0, 11f,
+            "group");
+    sf.add(sf5);
+    SequenceFeature sf6 = new SequenceFeature("Cath", "desc", 0, 0, -7f,
+            "group");
+    sf.add(sf6);
+
+    assertEquals(sf.getMinimumScore("nosuchtype", true), Float.NaN);
+    assertEquals(sf.getMinimumScore("nosuchtype", false), Float.NaN);
+    assertEquals(sf.getMaximumScore("nosuchtype", true), Float.NaN);
+    assertEquals(sf.getMaximumScore("nosuchtype", false), Float.NaN);
+
+    // positional features min-max:
+    assertEquals(sf.getMinimumScore("Metal", true), 1f);
+    assertEquals(sf.getMaximumScore("Metal", true), 4f);
+    assertEquals(sf.getMinimumScore("Cath", true), Float.NaN);
+    assertEquals(sf.getMaximumScore("Cath", true), Float.NaN);
+
+    // non-positional features min-max:
+    assertEquals(sf.getMinimumScore("Cath", false), -7f);
+    assertEquals(sf.getMaximumScore("Cath", false), 11f);
+    assertEquals(sf.getMinimumScore("Metal", false), Float.NaN);
+    assertEquals(sf.getMaximumScore("Metal", false), Float.NaN);
+
+    // delete features; min-max should get recomputed
+    sf.delete(sf6);
+    assertEquals(sf.getMinimumScore("Cath", false), 11f);
+    assertEquals(sf.getMaximumScore("Cath", false), 11f);
+    sf.delete(sf4);
+    assertEquals(sf.getMinimumScore("Metal", true), 1f);
+    assertEquals(sf.getMaximumScore("Metal", true), 1f);
+    sf.delete(sf5);
+    assertEquals(sf.getMinimumScore("Cath", false), Float.NaN);
+    assertEquals(sf.getMaximumScore("Cath", false), Float.NaN);
+    sf.delete(sf3);
+    assertEquals(sf.getMinimumScore("Metal", true), Float.NaN);
+    assertEquals(sf.getMaximumScore("Metal", true), Float.NaN);
+    sf.delete(sf1);
+    sf.delete(sf2);
+    assertFalse(sf.hasFeatures());
+    assertEquals(sf.getMinimumScore("Cath", false), Float.NaN);
+    assertEquals(sf.getMaximumScore("Cath", false), Float.NaN);
+    assertEquals(sf.getMinimumScore("Metal", true), Float.NaN);
+    assertEquals(sf.getMaximumScore("Metal", true), Float.NaN);
+  }
 }