+
+ /*
+ * delete the last non-positional feature
+ */
+ sf.delete(sfx);
+ groups = sf.getFeatureGroups(false);
+ assertTrue(groups.isEmpty());
+ }
+
+ @Test(groups = "Functional")
+ public void testGetFeatureTypesForGroups()
+ {
+ SequenceFeaturesI sf = new SequenceFeatures();
+ assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
+
+ /*
+ * add feature with group = "Uniprot", type = "helix"
+ */
+ String groupUniprot = "Uniprot";
+ SequenceFeature sf1 = new SequenceFeature("helix", "Desc", 10, 50, 0f,
+ groupUniprot);
+ sf.add(sf1);
+ Set<String> groups = sf.getFeatureTypesForGroups(true, groupUniprot);
+ assertEquals(groups.size(), 1);
+ assertTrue(groups.contains("helix"));
+ assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
+
+ /*
+ * add feature with group = "Uniprot", type = "strand"
+ */
+ SequenceFeature sf2 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
+ groupUniprot);
+ sf.add(sf2);
+ groups = sf.getFeatureTypesForGroups(true, groupUniprot);
+ assertEquals(groups.size(), 2);
+ assertTrue(groups.contains("helix"));
+ assertTrue(groups.contains("strand"));
+
+ /*
+ * delete the "strand" Uniprot feature - still have "helix"
+ */
+ sf.delete(sf2);
+ groups = sf.getFeatureTypesForGroups(true, groupUniprot);
+ assertEquals(groups.size(), 1);
+ assertTrue(groups.contains("helix"));
+
+ /*
+ * delete the "helix" Uniprot feature - none left
+ */
+ sf.delete(sf1);
+ assertTrue(sf.getFeatureTypesForGroups(true, groupUniprot).isEmpty());
+
+ /*
+ * add some null group features
+ */
+ SequenceFeature sf3 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
+ null);
+ sf.add(sf3);
+ SequenceFeature sf4 = new SequenceFeature("turn", "Desc", 10, 50, 0f,
+ null);
+ sf.add(sf4);
+ 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 rejected...
+ SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20,
+ Float.NaN, null);
+ assertFalse(store.add(sf2));
+ types = store.getFeatureTypes();
+ assertEquals(types.size(), 1);
+ assertFalse(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(), 2);
+ 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(), 3);
+ 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(), 3); // unchanged
+
+ /*
+ * delete first Pfam - still have one
+ */
+ assertTrue(store.delete(sf3));
+ types = store.getFeatureTypes();
+ assertEquals(types.size(), 3);
+ assertTrue(types.contains("Pfam"));
+
+ /*
+ * delete second Pfam - no longer have one
+ */
+ assertTrue(store.delete(sf5));
+ types = store.getFeatureTypes();
+ assertEquals(types.size(), 2);
+ 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);
+
+ /*
+ * null feature type is rejected
+ */
+ SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20,
+ Float.NaN, null);
+ assertFalse(store.add(sf2));
+ assertEquals(store.getFeatureCount(true), 1);
+ 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), 1);
+ 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), 2);
+ assertEquals(store.getFeatureCount(false), 1);
+
+ /*
+ * add another Pfam but this time as a positional feature
+ */
+ SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
+ Float.NaN, null);
+ store.add(sf5);
+ assertEquals(store.getFeatureCount(true), 3); // sf1, sf4, sf5
+ assertEquals(store.getFeatureCount(false), 1); // sf3
+ assertEquals(store.getFeatureCount(true, "Pfam"), 1); // positional
+ assertEquals(store.getFeatureCount(false, "Pfam"), 1); // non-positional
+ // search for type==null
+ assertEquals(store.getFeatureCount(true, (String) null), 0);
+ // search with no type specified
+ assertEquals(store.getFeatureCount(true, (String[]) null), 3);
+ assertEquals(store.getFeatureCount(true, "Metal", "Cath"), 1);
+ assertEquals(store.getFeatureCount(true, "Disulphide Bond"), 1);
+ assertEquals(store.getFeatureCount(true, "Metal", "Pfam", null), 2);
+
+ /*
+ * delete first Pfam (non-positional)
+ */
+ assertTrue(store.delete(sf3));
+ assertEquals(store.getFeatureCount(true), 3);
+ assertEquals(store.getFeatureCount(false), 0);
+
+ /*
+ * delete second Pfam (positional)
+ */
+ assertTrue(store.delete(sf5));
+ assertEquals(store.getFeatureCount(true), 2);
+ 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("Metallic", "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));
+
+ /*
+ * select by type does not apply to non-positional features
+ */
+ features = store.getAllFeatures("Cath");
+ assertEquals(features.size(), 1);
+ assertTrue(features.contains(sf3));
+
+ 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(groups = "Functional")
+ 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);
+ }
+
+ @Test(groups = "Functional")
+ public void testVarargsToTypes()
+ {
+ SequenceFeatures sf = new SequenceFeatures();
+ sf.add(new SequenceFeature("Metal", "desc", 0, 0, Float.NaN, "group"));
+ sf.add(new SequenceFeature("Cath", "desc", 10, 20, Float.NaN, "group"));
+
+ /*
+ * no type specified - get all types stored
+ * they are returned in keyset (alphabetical) order
+ */
+ Iterable<String> types = sf.varargToTypes();
+ Iterator<String> iterator = types.iterator();
+ assertTrue(iterator.hasNext());
+ assertEquals(iterator.next(), "Cath");
+ assertTrue(iterator.hasNext());
+ assertEquals(iterator.next(), "Metal");
+ assertFalse(iterator.hasNext());
+
+ /*
+ * empty array is the same as no vararg parameter supplied
+ * so treated as all stored types
+ */
+ types = sf.varargToTypes(new String[] {});
+ iterator = types.iterator();
+ assertTrue(iterator.hasNext());
+ assertEquals(iterator.next(), "Cath");
+ assertTrue(iterator.hasNext());
+ assertEquals(iterator.next(), "Metal");
+ assertFalse(iterator.hasNext());
+
+ /*
+ * null type specified; this is passed as vararg
+ * String[1] {null}
+ */
+ types = sf.varargToTypes((String) null);
+ assertFalse(types.iterator().hasNext());
+
+ /*
+ * null types array specified; this is passed as vararg null
+ */
+ types = sf.varargToTypes((String[]) null);
+ iterator = types.iterator();
+ assertTrue(iterator.hasNext());
+ assertEquals(iterator.next(), "Cath");
+ assertTrue(iterator.hasNext());
+ assertEquals(iterator.next(), "Metal");
+ assertFalse(iterator.hasNext());
+
+ /*
+ * one type specified
+ */
+ types = sf.varargToTypes("Metal");
+ iterator = types.iterator();
+ assertTrue(iterator.hasNext());
+ assertEquals(iterator.next(), "Metal");
+ assertFalse(iterator.hasNext());
+
+ /*
+ * two types specified - get sorted alphabetically
+ */
+ types = sf.varargToTypes("Metal", "Helix");
+ iterator = types.iterator();
+ assertTrue(iterator.hasNext());
+ assertEquals(iterator.next(), "Helix");
+ assertTrue(iterator.hasNext());
+ assertEquals(iterator.next(), "Metal");
+ assertFalse(iterator.hasNext());
+
+ /*
+ * null type included - should get removed
+ */
+ types = sf.varargToTypes("Metal", null, "Helix");
+ iterator = types.iterator();
+ assertTrue(iterator.hasNext());
+ assertEquals(iterator.next(), "Helix");
+ assertTrue(iterator.hasNext());
+ assertEquals(iterator.next(), "Metal");
+ assertFalse(iterator.hasNext());
+ }
+
+ @Test(groups = "Functional")
+ public void testGetFeatureTypes_byOntology()
+ {
+ SequenceFeaturesI store = new SequenceFeatures();
+
+ SequenceFeature sf1 = new SequenceFeature("transcript", "desc", 10, 20,
+ Float.NaN, null);
+ store.add(sf1);
+ // mRNA isA mature_transcript isA transcript
+ SequenceFeature sf2 = new SequenceFeature("mRNA", "desc", 10, 20,
+ Float.NaN, null);
+ store.add(sf2);
+ // just to prove non-positional feature types are included
+ SequenceFeature sf3 = new SequenceFeature("mRNA", "desc", 0, 0,
+ Float.NaN, null);
+ store.add(sf3);
+ SequenceFeature sf4 = new SequenceFeature("CDS", "desc", 0, 0,
+ Float.NaN, null);
+ store.add(sf4);
+
+ Set<String> types = store.getFeatureTypes("transcript");
+ assertEquals(types.size(), 2);
+ assertTrue(types.contains("transcript"));
+ assertTrue(types.contains("mRNA"));
+
+ // matches include arguments whether SO terms or not
+ types = store.getFeatureTypes("transcript", "CDS");
+ assertEquals(types.size(), 3);
+ assertTrue(types.contains("transcript"));
+ assertTrue(types.contains("mRNA"));
+ assertTrue(types.contains("CDS"));
+
+ types = store.getFeatureTypes("exon");
+ assertTrue(types.isEmpty());
+ }
+
+ @Test(groups = "Functional")
+ public void testGetFeaturesByOntology()
+ {
+ SequenceFeaturesI store = new SequenceFeatures();
+ List<SequenceFeature> features = store.getFeaturesByOntology();
+ assertTrue(features.isEmpty());
+ assertTrue(store.getFeaturesByOntology(new String[] {}).isEmpty());
+ assertTrue(store.getFeaturesByOntology((String[]) null).isEmpty());
+
+ SequenceFeature sf1 = new SequenceFeature("transcript", "desc", 10, 20,
+ Float.NaN, null);
+ store.add(sf1);
+
+ // mRNA isA transcript; added here 'as if' non-positional
+ // just to show that non-positional features are included in results
+ SequenceFeature sf2 = new SequenceFeature("mRNA", "desc", 0, 0,
+ Float.NaN, null);
+ store.add(sf2);
+
+ SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 30, 40,
+ Float.NaN, null);
+ store.add(sf3);
+
+ features = store.getFeaturesByOntology("transcript");
+ assertEquals(features.size(), 2);
+ assertTrue(features.contains(sf1));
+ assertTrue(features.contains(sf2));
+
+ features = store.getFeaturesByOntology("mRNA");
+ assertEquals(features.size(), 1);
+ assertTrue(features.contains(sf2));
+
+ features = store.getFeaturesByOntology("mRNA", "Pfam");
+ assertEquals(features.size(), 2);
+ assertTrue(features.contains(sf2));
+ assertTrue(features.contains(sf3));
+ }
+
+ @Test(groups = "Functional")
+ public void testSortFeatures()
+ {
+ List<SequenceFeature> sfs = new ArrayList<SequenceFeature>();
+ SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 30, 80,
+ Float.NaN, null);
+ sfs.add(sf1);
+ SequenceFeature sf2 = new SequenceFeature("Rfam", "desc", 40, 50,
+ Float.NaN, null);
+ sfs.add(sf2);
+ SequenceFeature sf3 = new SequenceFeature("Rfam", "desc", 50, 60,
+ Float.NaN, null);
+ sfs.add(sf3);
+
+ // sort by end position descending
+ SequenceFeatures.sortFeatures(sfs, false);
+ assertSame(sfs.get(0), sf1);
+ assertSame(sfs.get(1), sf3);
+ assertSame(sfs.get(2), sf2);
+
+ // sort by start position ascending
+ SequenceFeatures.sortFeatures(sfs, true);
+ assertSame(sfs.get(0), sf1);
+ assertSame(sfs.get(1), sf2);
+ assertSame(sfs.get(2), sf3);