import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertTrue;
import jalview.datamodel.SequenceFeature;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import org.testng.annotations.Test;
+import junit.extensions.PA;
+
public class SequenceFeaturesTest
{
@Test(groups = "Functional")
+ public void testConstructor()
+ {
+ SequenceFeaturesI store = new SequenceFeatures();
+ assertFalse(store.hasFeatures());
+
+ store = new SequenceFeatures((List<SequenceFeature>) null);
+ assertFalse(store.hasFeatures());
+
+ List<SequenceFeature> features = new ArrayList<>();
+ store = new SequenceFeatures(features);
+ assertFalse(store.hasFeatures());
+
+ SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
+ Float.NaN, null);
+ features.add(sf1);
+ SequenceFeature sf2 = new SequenceFeature("Metal", "desc", 15, 18,
+ Float.NaN, null);
+ features.add(sf2); // nested
+ SequenceFeature sf3 = new SequenceFeature("Pfam", "desc2", 0, 0,
+ Float.NaN, null); // non-positional
+ features.add(sf3);
+ store = new SequenceFeatures(features);
+ assertTrue(store.hasFeatures());
+ assertEquals(2, store.getFeatureCount(true)); // positional
+ assertEquals(1, store.getFeatureCount(false)); // non-positional
+ assertFalse(store.add(sf1)); // already contained
+ assertFalse(store.add(sf2)); // already contained
+ assertFalse(store.add(sf3)); // already contained
+ }
+
+ @Test(groups = "Functional")
public void testGetPositionalFeatures()
{
SequenceFeaturesI store = new SequenceFeatures();
groups = sf.getFeatureGroups(false); // for non-positional
assertEquals(groups.size(), 1);
assertTrue(groups.contains("AGroup"));
+ groups = sf.getFeatureGroups(false, "AType");
+ assertEquals(groups.size(), 1);
+ assertTrue(groups.contains("AGroup"));
+ groups = sf.getFeatureGroups(true, "AnotherType");
+ assertTrue(groups.isEmpty());
/*
* add, then delete, more non-positional features of different types
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");
- assertTrue(features.isEmpty());
+ assertEquals(features.size(), 1);
+ assertTrue(features.contains(sf3));
+
features = store.getAllFeatures("Pfam", "Cath", "Metal");
assertEquals(features.size(), 3);
assertTrue(features.contains(sf1));
Float.NaN, null);
assertTrue(store.add(sf1));
assertEquals(store.getTotalFeatureLength(), 11);
+ assertEquals(store.getTotalFeatureLength("Metal"), 11);
+ assertEquals(store.getTotalFeatureLength("Plastic"), 0);
// re-add does nothing!
assertFalse(store.add(sf1));
* no type specified - get all types stored
* they are returned in keyset (alphabetical) order
*/
- Iterable<String> types = sf.varargToTypes();
- Iterator<String> iterator = types.iterator();
+ Map<String, FeatureStore> featureStores = (Map<String, FeatureStore>) PA
+ .getValue(sf, "featureStore");
+
+ Iterable<FeatureStore> types = sf.varargToTypes();
+ Iterator<FeatureStore> iterator = types.iterator();
assertTrue(iterator.hasNext());
- assertEquals(iterator.next(), "Cath");
+ assertSame(iterator.next(), featureStores.get("Cath"));
assertTrue(iterator.hasNext());
- assertEquals(iterator.next(), "Metal");
+ assertSame(iterator.next(), featureStores.get("Metal"));
assertFalse(iterator.hasNext());
/*
types = sf.varargToTypes(new String[] {});
iterator = types.iterator();
assertTrue(iterator.hasNext());
- assertEquals(iterator.next(), "Cath");
+ assertSame(iterator.next(), featureStores.get("Cath"));
assertTrue(iterator.hasNext());
- assertEquals(iterator.next(), "Metal");
+ assertSame(iterator.next(), featureStores.get("Metal"));
assertFalse(iterator.hasNext());
/*
types = sf.varargToTypes((String[]) null);
iterator = types.iterator();
assertTrue(iterator.hasNext());
- assertEquals(iterator.next(), "Cath");
+ assertSame(iterator.next(), featureStores.get("Cath"));
assertTrue(iterator.hasNext());
- assertEquals(iterator.next(), "Metal");
+ assertSame(iterator.next(), featureStores.get("Metal"));
assertFalse(iterator.hasNext());
/*
types = sf.varargToTypes("Metal");
iterator = types.iterator();
assertTrue(iterator.hasNext());
- assertEquals(iterator.next(), "Metal");
+ assertSame(iterator.next(), featureStores.get("Metal"));
assertFalse(iterator.hasNext());
/*
- * two types specified
+ * two types specified - get sorted alphabetically
*/
- types = sf.varargToTypes("Metal", "Helix");
+ types = sf.varargToTypes("Metal", "Cath");
iterator = types.iterator();
assertTrue(iterator.hasNext());
- assertEquals(iterator.next(), "Metal");
+ assertSame(iterator.next(), featureStores.get("Cath"));
assertTrue(iterator.hasNext());
- assertEquals(iterator.next(), "Helix");
+ assertSame(iterator.next(), featureStores.get("Metal"));
assertFalse(iterator.hasNext());
/*
- * null type included - should get removed
+ * null type included - should be ignored
*/
types = sf.varargToTypes("Metal", null, "Helix");
iterator = types.iterator();
assertTrue(iterator.hasNext());
- assertEquals(iterator.next(), "Metal");
- assertTrue(iterator.hasNext());
- assertEquals(iterator.next(), "Helix");
+ assertSame(iterator.next(), featureStores.get("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 transcriptFeature = new SequenceFeature("transcript", "desc", 10, 20,
+ Float.NaN, null);
+ store.add(transcriptFeature);
+
+ /*
+ * mRNA is a sub-type of transcript; added here 'as if' non-positional
+ * just to show that non-positional features are included in results
+ */
+ SequenceFeature mrnaFeature = new SequenceFeature("mRNA", "desc", 0, 0,
+ Float.NaN, null);
+ store.add(mrnaFeature);
+
+ SequenceFeature pfamFeature = new SequenceFeature("Pfam", "desc", 30, 40,
+ Float.NaN, null);
+ store.add(pfamFeature);
+
+ /*
+ * "transcript" matches both itself and the sub-term "mRNA"
+ */
+ features = store.getFeaturesByOntology("transcript");
+ assertEquals(features.size(), 2);
+ assertTrue(features.contains(transcriptFeature));
+ assertTrue(features.contains(mrnaFeature));
+
+ /*
+ * "mRNA" matches itself but not parent term "transcript"
+ */
+ features = store.getFeaturesByOntology("mRNA");
+ assertEquals(features.size(), 1);
+ assertTrue(features.contains(mrnaFeature));
+
+ /*
+ * "pfam" is not an SO term but is included as an exact match
+ */
+ features = store.getFeaturesByOntology("mRNA", "Pfam");
+ assertEquals(features.size(), 2);
+ assertTrue(features.contains(mrnaFeature));
+ assertTrue(features.contains(pfamFeature));
+
+ features = store.getFeaturesByOntology("sequence_variant");
+ assertTrue(features.isEmpty());
+ }
+
+ @Test(groups = "Functional")
+ public void testSortFeatures()
+ {
+ List<SequenceFeature> sfs = new ArrayList<>();
+ 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);
+ }
+
+ @Test(groups = "Functional")
+ public void testGetFeaturesForGroup()
+ {
+ SequenceFeaturesI store = new SequenceFeatures();
+
+ List<SequenceFeature> features = store.getFeaturesForGroup(true, null);
+ assertTrue(features.isEmpty());
+ assertTrue(store.getFeaturesForGroup(false, null).isEmpty());
+ assertTrue(store.getFeaturesForGroup(true, "Uniprot").isEmpty());
+ assertTrue(store.getFeaturesForGroup(false, "Uniprot").isEmpty());
+
+ SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
+ null);
+ SequenceFeature sf2 = new SequenceFeature("Pfam", "desc", 0, 0, 0f,
+ null);
+ SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
+ "Uniprot");
+ SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 0, 0, 0f,
+ "Rfam");
+ SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 5, 15, 0f,
+ null);
+ store.add(sf1);
+ store.add(sf2);
+ store.add(sf3);
+ store.add(sf4);
+ store.add(sf5);
+
+ // positional features for null group, any type
+ features = store.getFeaturesForGroup(true, null);
+ assertEquals(features.size(), 2);
+ assertTrue(features.contains(sf1));
+ assertTrue(features.contains(sf5));
+
+ // positional features for null group, specified type
+ features = store.getFeaturesForGroup(true, null, new String[] { "Pfam",
+ "Xfam" });
+ assertEquals(features.size(), 1);
+ assertTrue(features.contains(sf1));
+ features = store.getFeaturesForGroup(true, null, new String[] { "Pfam",
+ "Xfam", "Cath" });
+ assertEquals(features.size(), 2);
+ assertTrue(features.contains(sf1));
+ assertTrue(features.contains(sf5));
+
+ // positional features for non-null group, any type
+ features = store.getFeaturesForGroup(true, "Uniprot");
+ assertEquals(features.size(), 1);
+ assertTrue(features.contains(sf3));
+ assertTrue(store.getFeaturesForGroup(true, "Rfam").isEmpty());
+
+ // positional features for non-null group, specified type
+ features = store.getFeaturesForGroup(true, "Uniprot", "Pfam", "Xfam",
+ "Rfam");
+ assertEquals(features.size(), 1);
+ assertTrue(features.contains(sf3));
+ assertTrue(store.getFeaturesForGroup(true, "Uniprot", "Cath").isEmpty());
+
+ // non-positional features for null group, any type
+ features = store.getFeaturesForGroup(false, null);
+ assertEquals(features.size(), 1);
+ assertTrue(features.contains(sf2));
+
+ // non-positional features for null group, specified type
+ features = store.getFeaturesForGroup(false, null, "Pfam", "Xfam");
+ assertEquals(features.size(), 1);
+ assertTrue(features.contains(sf2));
+ assertTrue(store.getFeaturesForGroup(false, null, "Cath").isEmpty());
+
+ // non-positional features for non-null group, any type
+ features = store.getFeaturesForGroup(false, "Rfam");
+ assertEquals(features.size(), 1);
+ assertTrue(features.contains(sf4));
+ assertTrue(store.getFeaturesForGroup(false, "Uniprot").isEmpty());
+
+ // non-positional features for non-null group, specified type
+ features = store.getFeaturesForGroup(false, "Rfam", "Pfam", "Metal");
+ assertEquals(features.size(), 1);
+ assertTrue(features.contains(sf4));
+ assertTrue(store.getFeaturesForGroup(false, "Rfam", "Cath", "Pfam")
+ .isEmpty());
+ }
+
+ @Test(groups = "Functional")
+ public void testShiftFeatures()
+ {
+ SequenceFeatures store = new SequenceFeatures();
+ assertFalse(store.shiftFeatures(1));
+
+ SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
+ store.add(sf1);
+ // nested feature:
+ SequenceFeature sf2 = new SequenceFeature("Metal", "", 8, 14, 0f, null);
+ store.add(sf2);
+ // contact feature:
+ SequenceFeature sf3 = new SequenceFeature("Disulfide bond", "", 23, 32,
+ 0f, null);
+ store.add(sf3);
+ // non-positional feature:
+ SequenceFeature sf4 = new SequenceFeature("Pfam", "", 0, 0, 0f, null);
+ store.add(sf4);
+
+ /*
+ * shift features right by 5
+ */
+ assertTrue(store.shiftFeatures(5));
+
+ // non-positional features untouched:
+ List<SequenceFeature> nonPos = store.getNonPositionalFeatures();
+ assertEquals(nonPos.size(), 1);
+ assertTrue(nonPos.contains(sf4));
+
+ // positional features are replaced
+ List<SequenceFeature> pos = store.getPositionalFeatures();
+ assertEquals(pos.size(), 3);
+ assertFalse(pos.contains(sf1));
+ assertFalse(pos.contains(sf2));
+ assertFalse(pos.contains(sf3));
+ SequenceFeatures.sortFeatures(pos, true); // ascending start pos
+ assertEquals(pos.get(0).getBegin(), 7);
+ assertEquals(pos.get(0).getEnd(), 10);
+ assertEquals(pos.get(0).getType(), "Cath");
+ assertEquals(pos.get(1).getBegin(), 13);
+ assertEquals(pos.get(1).getEnd(), 19);
+ assertEquals(pos.get(1).getType(), "Metal");
+ assertEquals(pos.get(2).getBegin(), 28);
+ assertEquals(pos.get(2).getEnd(), 37);
+ assertEquals(pos.get(2).getType(), "Disulfide bond");
+
+ /*
+ * now shift left by 15
+ * feature at [7-10] should be removed
+ * feature at [13-19] should become [1-4]
+ */
+ assertTrue(store.shiftFeatures(-15));
+ pos = store.getPositionalFeatures();
+ assertEquals(pos.size(), 2);
+ SequenceFeatures.sortFeatures(pos, true);
+ assertEquals(pos.get(0).getBegin(), 1);
+ assertEquals(pos.get(0).getEnd(), 4);
+ assertEquals(pos.get(0).getType(), "Metal");
+ assertEquals(pos.get(1).getBegin(), 13);
+ assertEquals(pos.get(1).getEnd(), 22);
+ assertEquals(pos.get(1).getType(), "Disulfide bond");
+ }
+
+ @Test(groups = "Functional")
+ public void testIsOntologyTerm()
+ {
+ SequenceFeatures store = new SequenceFeatures();
+ assertTrue(store.isOntologyTerm("gobbledygook"));
+ assertTrue(store.isOntologyTerm("transcript", "transcript"));
+ assertTrue(store.isOntologyTerm("mRNA", "transcript"));
+ assertFalse(store.isOntologyTerm("transcript", "mRNA"));
+ assertTrue(store.isOntologyTerm("junk", "transcript", "junk"));
+ assertTrue(store.isOntologyTerm("junk", new String[] {}));
+ assertTrue(store.isOntologyTerm("junk", (String[]) null));
+ }
}