JAL-2480 cache min-max score values per sequence and feature type
[jalview.git] / test / jalview / datamodel / features / SequenceFeaturesTest.java
index c096b1b..eaf20b0 100644 (file)
@@ -14,9 +14,9 @@ import org.testng.annotations.Test;
 public class SequenceFeaturesTest
 {
   @Test(groups = "Functional")
-  public void testGetFeatures()
+  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);
@@ -53,16 +53,16 @@ public class SequenceFeaturesTest
     store.add(sf9);
 
     /*
-     * get all features
+     * get all positional features
      */
-    List<SequenceFeature> features = store.getFeatures();
-    assertEquals(features.size(), 9);
+    List<SequenceFeature> features = store.getPositionalFeatures();
+    assertEquals(features.size(), 8);
     assertTrue(features.contains(sf1));
     assertTrue(features.contains(sf2));
     assertTrue(features.contains(sf3));
     assertTrue(features.contains(sf4));
     assertTrue(features.contains(sf5));
-    assertTrue(features.contains(sf6));
+    assertFalse(features.contains(sf6)); // non-positional
     assertTrue(features.contains(sf7));
     assertTrue(features.contains(sf8));
     assertTrue(features.contains(sf9));
@@ -70,24 +70,24 @@ public class SequenceFeaturesTest
     /*
      * get features by type
      */
-    assertTrue(store.getFeatures(null).isEmpty());
-    assertTrue(store.getFeatures("Cath").isEmpty());
-    assertTrue(store.getFeatures("METAL").isEmpty());
+    assertTrue(store.getPositionalFeatures((String) null).isEmpty());
+    assertTrue(store.getPositionalFeatures("Cath").isEmpty());
+    assertTrue(store.getPositionalFeatures("METAL").isEmpty());
 
-    features = store.getFeatures("Metal");
-    assertEquals(features.size(), 6);
+    features = store.getPositionalFeatures("Metal");
+    assertEquals(features.size(), 5);
     assertTrue(features.contains(sf1));
     assertTrue(features.contains(sf2));
     assertTrue(features.contains(sf3));
     assertTrue(features.contains(sf4));
     assertTrue(features.contains(sf5));
-    assertTrue(features.contains(sf6));
+    assertFalse(features.contains(sf6));
 
-    features = store.getFeatures("Disulphide bond");
+    features = store.getPositionalFeatures("Disulphide bond");
     assertEquals(features.size(), 1);
     assertTrue(features.contains(sf7));
 
-    features = store.getFeatures("Pfam");
+    features = store.getPositionalFeatures("Pfam");
     assertEquals(features.size(), 2);
     assertTrue(features.contains(sf8));
     assertTrue(features.contains(sf9));
@@ -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,21 +288,21 @@ 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.getFeatures().contains(sf1));
+    assertTrue(sf.getPositionalFeatures().contains(sf1));
 
     assertFalse(sf.delete(null));
     SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 15, 0f, null);
     assertFalse(sf.delete(sf2)); // not added, can't delete it
     assertTrue(sf.delete(sf1));
-    assertTrue(sf.getFeatures().isEmpty());
+    assertTrue(sf.getPositionalFeatures().isEmpty());
   }
 
   @Test(groups = "Functional")
   public void testHasFeatures()
   {
-    SequenceFeatures sf = new SequenceFeatures();
+    SequenceFeaturesI sf = new SequenceFeatures();
     assertFalse(sf.hasFeatures());
 
     SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
@@ -312,30 +312,75 @@ public class SequenceFeaturesTest
     assertFalse(sf.hasFeatures());
   }
 
+  /**
+   * Tests for the method that gets feature groups for positional or
+   * non-positional features
+   */
   @Test(groups = "Functional")
   public void testGetFeatureGroups()
   {
-    SequenceFeatures sf = new SequenceFeatures();
-    assertTrue(sf.getFeatureGroups().isEmpty());
+    SequenceFeaturesI sf = new SequenceFeatures();
+    assertTrue(sf.getFeatureGroups(true).isEmpty());
+    assertTrue(sf.getFeatureGroups(false).isEmpty());
+
+    /*
+     * add a non-positional feature (begin/end = 0/0)
+     */
+    SequenceFeature sfx = new SequenceFeature("AType", "Desc", 0, 0, 0f,
+            "AGroup");
+    sf.add(sfx);
+    Set<String> groups = sf.getFeatureGroups(true); // for positional
+    assertTrue(groups.isEmpty());
+    groups = sf.getFeatureGroups(false); // for non-positional
+    assertEquals(groups.size(), 1);
+    assertTrue(groups.contains("AGroup"));
 
+    /*
+     * add, then delete, more non-positional features of different types
+     */
+    SequenceFeature sfy = new SequenceFeature("AnotherType", "Desc", 0, 0,
+            0f,
+            "AnotherGroup");
+    sf.add(sfy);
+    SequenceFeature sfz = new SequenceFeature("AThirdType", "Desc", 0, 0,
+            0f,
+            null);
+    sf.add(sfz);
+    groups = sf.getFeatureGroups(false);
+    assertEquals(groups.size(), 3);
+    assertTrue(groups.contains("AGroup"));
+    assertTrue(groups.contains("AnotherGroup"));
+    assertTrue(groups.contains(null)); // null is a possible group
+    sf.delete(sfz);
+    sf.delete(sfy);
+    groups = sf.getFeatureGroups(false);
+    assertEquals(groups.size(), 1);
+    assertTrue(groups.contains("AGroup"));
+
+    /*
+     * add positional features
+     */
     SequenceFeature sf1 = new SequenceFeature("Pfam", "Desc", 10, 50, 0f,
             "PfamGroup");
     sf.add(sf1);
-    Set<String> groups = sf.getFeatureGroups();
+    groups = sf.getFeatureGroups(true);
     assertEquals(groups.size(), 1);
     assertTrue(groups.contains("PfamGroup"));
+    groups = sf.getFeatureGroups(false); // non-positional unchanged
+    assertEquals(groups.size(), 1);
+    assertTrue(groups.contains("AGroup"));
 
     SequenceFeature sf2 = new SequenceFeature("Cath", "Desc", 10, 50, 0f,
             null);
     sf.add(sf2);
-    groups = sf.getFeatureGroups();
+    groups = sf.getFeatureGroups(true);
     assertEquals(groups.size(), 2);
     assertTrue(groups.contains("PfamGroup"));
     assertTrue(groups.contains(null));
 
     sf.delete(sf1);
     sf.delete(sf2);
-    assertTrue(sf.getFeatureGroups().isEmpty());
+    assertTrue(sf.getFeatureGroups(true).isEmpty());
 
     SequenceFeature sf3 = new SequenceFeature("CDS", "", 10, 50, 0f,
             "Ensembl");
@@ -343,7 +388,7 @@ public class SequenceFeaturesTest
     SequenceFeature sf4 = new SequenceFeature("exon", "", 10, 50, 0f,
             "Ensembl");
     sf.add(sf4);
-    groups = sf.getFeatureGroups();
+    groups = sf.getFeatureGroups(true);
     assertEquals(groups.size(), 1);
     assertTrue(groups.contains("Ensembl"));
 
@@ -352,16 +397,23 @@ public class SequenceFeaturesTest
      * but still have one in exon features
      */
     sf.delete(sf3);
-    groups = sf.getFeatureGroups();
+    groups = sf.getFeatureGroups(true);
     assertEquals(groups.size(), 1);
     assertTrue(groups.contains("Ensembl"));
+
+    /*
+     * delete the last non-positional feature
+     */
+    sf.delete(sfx);
+    groups = sf.getFeatureGroups(false);
+    assertTrue(groups.isEmpty());
   }
 
   @Test(groups = "Functional")
-  public void testGetFeatureTypesForGroup()
+  public void testGetFeatureTypesForGroups()
   {
-    SequenceFeatures sf = new SequenceFeatures();
-    assertTrue(sf.getFeatureTypesForGroup(null).isEmpty());
+    SequenceFeaturesI sf = new SequenceFeatures();
+    assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
   
     /*
      * add feature with group = "Uniprot", type = "helix"
@@ -370,10 +422,10 @@ public class SequenceFeaturesTest
     SequenceFeature sf1 = new SequenceFeature("helix", "Desc", 10, 50, 0f,
             groupUniprot);
     sf.add(sf1);
-    Set<String> groups = sf.getFeatureTypesForGroup(groupUniprot);
+    Set<String> groups = sf.getFeatureTypesForGroups(true, groupUniprot);
     assertEquals(groups.size(), 1);
     assertTrue(groups.contains("helix"));
-    assertTrue(sf.getFeatureTypesForGroup(null).isEmpty());
+    assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
   
     /*
      * add feature with group = "Uniprot", type = "strand"
@@ -381,7 +433,7 @@ public class SequenceFeaturesTest
     SequenceFeature sf2 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
             groupUniprot);
     sf.add(sf2);
-    groups = sf.getFeatureTypesForGroup(groupUniprot);
+    groups = sf.getFeatureTypesForGroups(true, groupUniprot);
     assertEquals(groups.size(), 2);
     assertTrue(groups.contains("helix"));
     assertTrue(groups.contains("strand"));
@@ -390,7 +442,7 @@ public class SequenceFeaturesTest
      * delete the "strand" Uniprot feature - still have "helix"
      */
     sf.delete(sf2);
-    groups = sf.getFeatureTypesForGroup(groupUniprot);
+    groups = sf.getFeatureTypesForGroups(true, groupUniprot);
     assertEquals(groups.size(), 1);
     assertTrue(groups.contains("helix"));
 
@@ -398,7 +450,7 @@ public class SequenceFeaturesTest
      * delete the "helix" Uniprot feature - none left
      */
     sf.delete(sf1);
-    assertTrue(sf.getFeatureTypesForGroup(groupUniprot).isEmpty());
+    assertTrue(sf.getFeatureTypesForGroups(true, groupUniprot).isEmpty());
 
     /*
      * add some null group features
@@ -409,9 +461,373 @@ public class SequenceFeaturesTest
     SequenceFeature sf4 = new SequenceFeature("turn", "Desc", 10, 50, 0f,
             null);
     sf.add(sf4);
-    groups = sf.getFeatureTypesForGroup(null);
+    groups = sf.getFeatureTypesForGroups(true, (String) null);
     assertEquals(groups.size(), 2);
     assertTrue(groups.contains("strand"));
     assertTrue(groups.contains("turn"));
+
+    /*
+     * add strand/Cath  and turn/Scop and query for one or both groups
+     * (find feature types for groups selected in Feature Settings)
+     */
+    SequenceFeature sf5 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
+            "Cath");
+    sf.add(sf5);
+    SequenceFeature sf6 = new SequenceFeature("turn", "Desc", 10, 50, 0f,
+            "Scop");
+    sf.add(sf6);
+    groups = sf.getFeatureTypesForGroups(true, "Cath");
+    assertEquals(groups.size(), 1);
+    assertTrue(groups.contains("strand"));
+    groups = sf.getFeatureTypesForGroups(true, "Scop");
+    assertEquals(groups.size(), 1);
+    assertTrue(groups.contains("turn"));
+    groups = sf.getFeatureTypesForGroups(true, "Cath", "Scop");
+    assertEquals(groups.size(), 2);
+    assertTrue(groups.contains("turn"));
+    assertTrue(groups.contains("strand"));
+    // alternative vararg syntax
+    groups = sf.getFeatureTypesForGroups(true, new String[] { "Cath",
+        "Scop" });
+    assertEquals(groups.size(), 2);
+    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);
   }
 }