package jalview.datamodel.features; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; import jalview.datamodel.SequenceFeature; import java.util.List; import java.util.Set; import org.testng.annotations.Test; public class SequenceFeaturesTest { @Test(groups = "Functional") public void testGetPositionalFeatures() { SequenceFeatures store = new SequenceFeatures(); SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20, Float.NaN, null); store.add(sf1); // same range, different description SequenceFeature sf2 = new SequenceFeature("Metal", "desc2", 10, 20, Float.NaN, null); store.add(sf2); // discontiguous range SequenceFeature sf3 = new SequenceFeature("Metal", "desc", 30, 40, Float.NaN, null); store.add(sf3); // overlapping range SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 15, 35, Float.NaN, null); store.add(sf4); // enclosing range SequenceFeature sf5 = new SequenceFeature("Metal", "desc", 5, 50, Float.NaN, null); store.add(sf5); // non-positional feature SequenceFeature sf6 = new SequenceFeature("Metal", "desc", 0, 0, Float.NaN, null); store.add(sf6); // contact feature SequenceFeature sf7 = new SequenceFeature("Disulphide bond", "desc", 18, 45, Float.NaN, null); store.add(sf7); // different feature type SequenceFeature sf8 = new SequenceFeature("Pfam", "desc", 30, 40, Float.NaN, null); store.add(sf8); SequenceFeature sf9 = new SequenceFeature("Pfam", "desc", 15, 35, Float.NaN, null); store.add(sf9); /* * get all positional features */ List 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)); assertFalse(features.contains(sf6)); // non-positional assertTrue(features.contains(sf7)); assertTrue(features.contains(sf8)); assertTrue(features.contains(sf9)); /* * get features by type */ assertTrue(store.getPositionalFeatures((String) null).isEmpty()); assertTrue(store.getPositionalFeatures("Cath").isEmpty()); assertTrue(store.getPositionalFeatures("METAL").isEmpty()); 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)); assertFalse(features.contains(sf6)); features = store.getPositionalFeatures("Disulphide bond"); assertEquals(features.size(), 1); assertTrue(features.contains(sf7)); features = store.getPositionalFeatures("Pfam"); assertEquals(features.size(), 2); assertTrue(features.contains(sf8)); assertTrue(features.contains(sf9)); } @Test(groups = "Functional") public void testGetContactFeatures() { SequenceFeatures store = new SequenceFeatures(); // non-contact SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20, Float.NaN, null); store.add(sf1); // non-positional SequenceFeature sf2 = new SequenceFeature("Metal", "desc", 0, 0, Float.NaN, null); store.add(sf2); // contact feature SequenceFeature sf3 = new SequenceFeature("Disulphide bond", "desc", 18, 45, Float.NaN, null); store.add(sf3); // repeat for different feature type SequenceFeature sf4 = new SequenceFeature("Pfam", "desc", 10, 20, Float.NaN, null); store.add(sf4); SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 0, 0, Float.NaN, null); store.add(sf5); SequenceFeature sf6 = new SequenceFeature("Disulfide bond", "desc", 18, 45, Float.NaN, null); store.add(sf6); /* * get all contact features */ List features = store.getContactFeatures(); assertEquals(features.size(), 2); assertTrue(features.contains(sf3)); assertTrue(features.contains(sf6)); /* * get contact features by type */ assertTrue(store.getContactFeatures((String) null).isEmpty()); assertTrue(store.getContactFeatures("Cath").isEmpty()); assertTrue(store.getContactFeatures("Pfam").isEmpty()); assertTrue(store.getContactFeatures("DISULPHIDE BOND").isEmpty()); features = store.getContactFeatures("Disulphide bond"); assertEquals(features.size(), 1); assertTrue(features.contains(sf3)); features = store.getContactFeatures("Disulfide bond"); assertEquals(features.size(), 1); assertTrue(features.contains(sf6)); } @Test(groups = "Functional") public void testGetNonPositionalFeatures() { SequenceFeatures store = new SequenceFeatures(); // positional SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20, Float.NaN, null); store.add(sf1); // non-positional SequenceFeature sf2 = new SequenceFeature("Metal", "desc", 0, 0, Float.NaN, null); store.add(sf2); // contact feature SequenceFeature sf3 = new SequenceFeature("Disulphide bond", "desc", 18, 45, Float.NaN, null); store.add(sf3); // repeat for different feature type SequenceFeature sf4 = new SequenceFeature("Pfam", "desc", 10, 20, Float.NaN, null); store.add(sf4); SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 0, 0, Float.NaN, null); store.add(sf5); SequenceFeature sf6 = new SequenceFeature("Disulfide bond", "desc", 18, 45, Float.NaN, null); store.add(sf6); // one more non-positional, different description SequenceFeature sf7 = new SequenceFeature("Pfam", "desc2", 0, 0, Float.NaN, null); store.add(sf7); /* * get all non-positional features */ List features = store.getNonPositionalFeatures(); assertEquals(features.size(), 3); assertTrue(features.contains(sf2)); assertTrue(features.contains(sf5)); assertTrue(features.contains(sf7)); /* * get non-positional features by type */ assertTrue(store.getNonPositionalFeatures((String) null).isEmpty()); assertTrue(store.getNonPositionalFeatures("Cath").isEmpty()); assertTrue(store.getNonPositionalFeatures("PFAM").isEmpty()); features = store.getNonPositionalFeatures("Metal"); assertEquals(features.size(), 1); assertTrue(features.contains(sf2)); features = store.getNonPositionalFeatures("Pfam"); assertEquals(features.size(), 2); assertTrue(features.contains(sf5)); assertTrue(features.contains(sf7)); } /** * Helper method to add a feature of no particular type * * @param sf * @param type * @param from * @param to * @return */ SequenceFeature addFeature(SequenceFeatures sf, String type, int from, int to) { SequenceFeature sf1 = new SequenceFeature(type, "", from, to, Float.NaN, null); sf.add(sf1); return sf1; } @Test(groups = "Functional") public void testFindFeatures() { SequenceFeatures sf = new SequenceFeatures(); SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50); SequenceFeature sf2 = addFeature(sf, "Pfam", 1, 15); SequenceFeature sf3 = addFeature(sf, "Pfam", 20, 30); SequenceFeature sf4 = addFeature(sf, "Pfam", 40, 100); SequenceFeature sf5 = addFeature(sf, "Pfam", 60, 100); SequenceFeature sf6 = addFeature(sf, "Pfam", 70, 70); SequenceFeature sf7 = addFeature(sf, "Cath", 10, 50); SequenceFeature sf8 = addFeature(sf, "Cath", 1, 15); SequenceFeature sf9 = addFeature(sf, "Cath", 20, 30); SequenceFeature sf10 = addFeature(sf, "Cath", 40, 100); SequenceFeature sf11 = addFeature(sf, "Cath", 60, 100); SequenceFeature sf12 = addFeature(sf, "Cath", 70, 70); // null type is weird but possible: SequenceFeature sf13 = addFeature(sf, null, 5, 12); List overlaps = sf.findFeatures(200, 200, "Pfam"); assertTrue(overlaps.isEmpty()); overlaps = sf.findFeatures( 1, 9, "Pfam"); assertEquals(overlaps.size(), 1); assertTrue(overlaps.contains(sf2)); overlaps = sf.findFeatures( 5, 18, "Pfam"); assertEquals(overlaps.size(), 2); assertTrue(overlaps.contains(sf1)); assertTrue(overlaps.contains(sf2)); 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( 80, 90, "Pfam"); assertEquals(overlaps.size(), 2); assertTrue(overlaps.contains(sf4)); assertTrue(overlaps.contains(sf5)); 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(16, 69, "Cath"); assertEquals(overlaps.size(), 4); assertTrue(overlaps.contains(sf7)); assertFalse(overlaps.contains(sf8)); assertTrue(overlaps.contains(sf9)); assertTrue(overlaps.contains(sf10)); assertTrue(overlaps.contains(sf11)); assertFalse(overlaps.contains(sf12)); assertTrue(sf.findFeatures(0, 1000, "Metal").isEmpty()); overlaps = sf.findFeatures(7, 7, (String) null); assertEquals(overlaps.size(), 1); assertTrue(overlaps.contains(sf13)); } @Test(groups = "Functional") public void testDelete() { SequenceFeatures sf = new SequenceFeatures(); SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50); 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.getPositionalFeatures().isEmpty()); } @Test(groups = "Functional") public void testHasFeatures() { SequenceFeatures sf = new SequenceFeatures(); assertFalse(sf.hasFeatures()); SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50); assertTrue(sf.hasFeatures()); sf.delete(sf1); 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(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 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); 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(true); assertEquals(groups.size(), 2); assertTrue(groups.contains("PfamGroup")); assertTrue(groups.contains(null)); sf.delete(sf1); sf.delete(sf2); assertTrue(sf.getFeatureGroups(true).isEmpty()); SequenceFeature sf3 = new SequenceFeature("CDS", "", 10, 50, 0f, "Ensembl"); sf.add(sf3); SequenceFeature sf4 = new SequenceFeature("exon", "", 10, 50, 0f, "Ensembl"); sf.add(sf4); groups = sf.getFeatureGroups(true); assertEquals(groups.size(), 1); assertTrue(groups.contains("Ensembl")); /* * delete last Ensembl group feature from CDS features * but still have one in exon features */ sf.delete(sf3); 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 testGetFeatureTypesForGroups() { SequenceFeatures 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 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")); } }