X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=test%2Fjalview%2Fdatamodel%2Ffeatures%2FSequenceFeaturesTest.java;h=7dde97b6006b5db39bf4b91115963de7efa3f37c;hb=e9a1c2c372f4bbf6cf658de3dba73ef326b20c20;hp=31703cd945a86a39e0f7d7854e9a8a544c13484c;hpb=661f8bc80f969f31d7aeceb9af7d01374c8e1f35;p=jalview.git diff --git a/test/jalview/datamodel/features/SequenceFeaturesTest.java b/test/jalview/datamodel/features/SequenceFeaturesTest.java index 31703cd..7dde97b 100644 --- a/test/jalview/datamodel/features/SequenceFeaturesTest.java +++ b/test/jalview/datamodel/features/SequenceFeaturesTest.java @@ -1,19 +1,75 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ package jalview.datamodel.features; 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 jalview.datamodel.SequenceFeature; +import junit.extensions.PA; + public class SequenceFeaturesTest { @Test(groups = "Functional") + public void testConstructor() + { + SequenceFeaturesI store = new SequenceFeatures(); + assertFalse(store.hasFeatures()); + + store = new SequenceFeatures((List) null); + assertFalse(store.hasFeatures()); + + List 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(); @@ -41,8 +97,8 @@ public class SequenceFeaturesTest Float.NaN, null); store.add(sf6); // contact feature - SequenceFeature sf7 = new SequenceFeature("Disulphide bond", "desc", - 18, 45, Float.NaN, null); + 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, @@ -106,8 +162,8 @@ public class SequenceFeaturesTest Float.NaN, null); store.add(sf2); // contact feature - SequenceFeature sf3 = new SequenceFeature("Disulphide bond", "desc", - 18, 45, Float.NaN, null); + 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, @@ -119,7 +175,7 @@ public class SequenceFeaturesTest SequenceFeature sf6 = new SequenceFeature("Disulfide bond", "desc", 18, 45, Float.NaN, null); store.add(sf6); - + /* * get all contact features */ @@ -127,7 +183,7 @@ public class SequenceFeaturesTest assertEquals(features.size(), 2); assertTrue(features.contains(sf3)); assertTrue(features.contains(sf6)); - + /* * get contact features by type */ @@ -135,11 +191,11 @@ public class SequenceFeaturesTest 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)); @@ -158,8 +214,8 @@ public class SequenceFeaturesTest Float.NaN, null); store.add(sf2); // contact feature - SequenceFeature sf3 = new SequenceFeature("Disulphide bond", "desc", - 18, 45, Float.NaN, null); + 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, @@ -175,7 +231,7 @@ public class SequenceFeaturesTest SequenceFeature sf7 = new SequenceFeature("Pfam", "desc2", 0, 0, Float.NaN, null); store.add(sf7); - + /* * get all non-positional features */ @@ -184,18 +240,18 @@ public class SequenceFeaturesTest 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)); @@ -214,8 +270,7 @@ public class SequenceFeaturesTest SequenceFeature addFeature(SequenceFeaturesI sf, String type, int from, int to) { - SequenceFeature sf1 = new SequenceFeature(type, "", from, to, - Float.NaN, + SequenceFeature sf1 = new SequenceFeature(type, "", from, to, Float.NaN, null); sf.add(sf1); return sf1; @@ -237,33 +292,31 @@ public class SequenceFeaturesTest 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"); + + overlaps = sf.findFeatures(1, 9, "Pfam"); assertEquals(overlaps.size(), 1); assertTrue(overlaps.contains(sf2)); - - overlaps = sf.findFeatures( 5, 18, "Pfam"); + + 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"); + + overlaps = sf.findFeatures(80, 90, "Pfam"); assertEquals(overlaps.size(), 2); assertTrue(overlaps.contains(sf4)); assertTrue(overlaps.contains(sf5)); - - overlaps = sf.findFeatures( 68, 70, "Pfam"); + + overlaps = sf.findFeatures(68, 70, "Pfam"); assertEquals(overlaps.size(), 3); assertTrue(overlaps.contains(sf4)); assertTrue(overlaps.contains(sf5)); @@ -281,8 +334,7 @@ public class SequenceFeaturesTest assertTrue(sf.findFeatures(0, 1000, "Metal").isEmpty()); overlaps = sf.findFeatures(7, 7, (String) null); - assertEquals(overlaps.size(), 1); - assertTrue(overlaps.contains(sf13)); + assertTrue(overlaps.isEmpty()); } @Test(groups = "Functional") @@ -334,17 +386,20 @@ public class SequenceFeaturesTest 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 */ SequenceFeature sfy = new SequenceFeature("AnotherType", "Desc", 0, 0, - 0f, - "AnotherGroup"); + 0f, "AnotherGroup"); sf.add(sfy); SequenceFeature sfz = new SequenceFeature("AThirdType", "Desc", 0, 0, - 0f, - null); + 0f, null); sf.add(sfz); groups = sf.getFeatureGroups(false); assertEquals(groups.size(), 3); @@ -414,7 +469,7 @@ public class SequenceFeaturesTest { SequenceFeaturesI sf = new SequenceFeatures(); assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty()); - + /* * add feature with group = "Uniprot", type = "helix" */ @@ -426,7 +481,7 @@ public class SequenceFeaturesTest assertEquals(groups.size(), 1); assertTrue(groups.contains("helix")); assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty()); - + /* * add feature with group = "Uniprot", type = "strand" */ @@ -487,8 +542,9 @@ public class SequenceFeaturesTest assertTrue(groups.contains("turn")); assertTrue(groups.contains("strand")); // alternative vararg syntax - groups = sf.getFeatureTypesForGroups(true, new String[] { "Cath", - "Scop" }); + groups = sf.getFeatureTypesForGroups(true, + new String[] + { "Cath", "Scop" }); assertEquals(groups.size(), 2); assertTrue(groups.contains("turn")); assertTrue(groups.contains("strand")); @@ -508,13 +564,13 @@ public class SequenceFeaturesTest assertEquals(types.size(), 1); assertTrue(types.contains("Metal")); - // null type is possible... + // null type is rejected... SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20, Float.NaN, null); - store.add(sf2); + assertFalse(store.add(sf2)); types = store.getFeatureTypes(); - assertEquals(types.size(), 2); - assertTrue(types.contains(null)); + assertEquals(types.size(), 1); + assertFalse(types.contains(null)); assertTrue(types.contains("Metal")); /* @@ -524,17 +580,17 @@ public class SequenceFeaturesTest Float.NaN, null); store.add(sf3); types = store.getFeatureTypes(); - assertEquals(types.size(), 3); + assertEquals(types.size(), 2); assertTrue(types.contains("Pfam")); /* * add contact feature */ - SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc", - 10, 20, Float.NaN, null); + SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc", 10, + 20, Float.NaN, null); store.add(sf4); types = store.getFeatureTypes(); - assertEquals(types.size(), 4); + assertEquals(types.size(), 3); assertTrue(types.contains("Disulphide Bond")); /* @@ -544,14 +600,14 @@ public class SequenceFeaturesTest Float.NaN, null); store.add(sf5); types = store.getFeatureTypes(); - assertEquals(types.size(), 4); // unchanged + assertEquals(types.size(), 3); // unchanged /* * delete first Pfam - still have one */ assertTrue(store.delete(sf3)); types = store.getFeatureTypes(); - assertEquals(types.size(), 4); + assertEquals(types.size(), 3); assertTrue(types.contains("Pfam")); /* @@ -559,7 +615,7 @@ public class SequenceFeaturesTest */ assertTrue(store.delete(sf5)); types = store.getFeatureTypes(); - assertEquals(types.size(), 3); + assertEquals(types.size(), 2); assertFalse(types.contains("Pfam")); } @@ -569,7 +625,7 @@ public class SequenceFeaturesTest SequenceFeaturesI store = new SequenceFeatures(); assertEquals(store.getFeatureCount(true), 0); assertEquals(store.getFeatureCount(false), 0); - + /* * add positional */ @@ -580,62 +636,62 @@ public class SequenceFeaturesTest assertEquals(store.getFeatureCount(false), 0); /* - * another positional + * null feature type is rejected */ SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20, Float.NaN, null); - store.add(sf2); - assertEquals(store.getFeatureCount(true), 2); + 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), 2); + 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); + SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc", 10, + 20, Float.NaN, null); store.add(sf4); - assertEquals(store.getFeatureCount(true), 3); + assertEquals(store.getFeatureCount(true), 2); assertEquals(store.getFeatureCount(false), 1); - + /* - * add another Pfam + * 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), 4); - assertEquals(store.getFeatureCount(false), 1); - assertEquals(store.getFeatureCount(true, "Pfam"), 1); - assertEquals(store.getFeatureCount(false, "Pfam"), 1); + 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), 1); + assertEquals(store.getFeatureCount(true, (String) null), 0); // search with no type specified - assertEquals(store.getFeatureCount(true, (String[]) null), 4); + 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), 3); + assertEquals(store.getFeatureCount(true, "Metal", "Pfam", null), 2); /* * delete first Pfam (non-positional) */ assertTrue(store.delete(sf3)); - assertEquals(store.getFeatureCount(true), 4); + assertEquals(store.getFeatureCount(true), 3); assertEquals(store.getFeatureCount(false), 0); - + /* * delete second Pfam (positional) */ assertTrue(store.delete(sf5)); - assertEquals(store.getFeatureCount(true), 3); + assertEquals(store.getFeatureCount(true), 2); assertEquals(store.getFeatureCount(false), 0); } @@ -645,21 +701,21 @@ public class SequenceFeaturesTest SequenceFeaturesI store = new SequenceFeatures(); List 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, + + 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 */ @@ -669,17 +725,17 @@ public class SequenceFeaturesTest 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); + 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 */ @@ -689,14 +745,20 @@ public class SequenceFeaturesTest 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)); assertTrue(features.contains(sf3)); assertTrue(features.contains(sf5)); - + /* * delete first Pfam */ @@ -704,7 +766,7 @@ public class SequenceFeaturesTest features = store.getAllFeatures(); assertEquals(features.size(), 4); assertFalse(features.contains(sf3)); - + /* * delete second Pfam */ @@ -724,6 +786,8 @@ public class SequenceFeaturesTest 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)); @@ -740,8 +804,8 @@ public class SequenceFeaturesTest /* * add contact feature - counts 1 to feature length */ - SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc", - 10, 20, Float.NaN, null); + SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc", 10, + 20, Float.NaN, null); store.add(sf4); assertEquals(store.getTotalFeatureLength(), 12); @@ -768,4 +832,481 @@ public class SequenceFeaturesTest 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 + */ + Map featureStores = (Map) PA + .getValue(sf, "featureStore"); + + Iterable types = sf.varargToTypes(); + Iterator iterator = types.iterator(); + assertTrue(iterator.hasNext()); + assertSame(iterator.next(), featureStores.get("Cath")); + assertTrue(iterator.hasNext()); + assertSame(iterator.next(), featureStores.get("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()); + assertSame(iterator.next(), featureStores.get("Cath")); + assertTrue(iterator.hasNext()); + assertSame(iterator.next(), featureStores.get("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()); + assertSame(iterator.next(), featureStores.get("Cath")); + assertTrue(iterator.hasNext()); + assertSame(iterator.next(), featureStores.get("Metal")); + assertFalse(iterator.hasNext()); + + /* + * one type specified + */ + types = sf.varargToTypes("Metal"); + iterator = types.iterator(); + assertTrue(iterator.hasNext()); + assertSame(iterator.next(), featureStores.get("Metal")); + assertFalse(iterator.hasNext()); + + /* + * two types specified - order is preserved + */ + types = sf.varargToTypes("Metal", "Cath"); + iterator = types.iterator(); + assertTrue(iterator.hasNext()); + assertSame(iterator.next(), featureStores.get("Metal")); + assertTrue(iterator.hasNext()); + assertSame(iterator.next(), featureStores.get("Cath")); + assertFalse(iterator.hasNext()); + + /* + * null type included - should be ignored + */ + types = sf.varargToTypes("Metal", null, "Helix"); + iterator = types.iterator(); + assertTrue(iterator.hasNext()); + 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 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 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 sfs = new ArrayList<>(); + SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 30, 60, + 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); + SequenceFeature sf4 = new SequenceFeature("Xfam", "desc", 30, 80, + Float.NaN, null); + sfs.add(sf4); + SequenceFeature sf5 = new SequenceFeature("Xfam", "desc", 30, 90, + Float.NaN, null); + sfs.add(sf5); + + /* + * sort by end position descending, order unchanged if matched + */ + SequenceFeatures.sortFeatures(sfs, false); + assertSame(sfs.get(0), sf5); // end 90 + assertSame(sfs.get(1), sf4); // end 80 + assertSame(sfs.get(2), sf1); // end 60, start 50 + assertSame(sfs.get(3), sf3); // end 60, start 30 + assertSame(sfs.get(4), sf2); // end 50 + + /* + * resort {5, 4, 1, 3, 2} by start position ascending, end descending + */ + SequenceFeatures.sortFeatures(sfs, true); + assertSame(sfs.get(0), sf5); // start 30, end 90 + assertSame(sfs.get(1), sf4); // start 30, end 80 + assertSame(sfs.get(2), sf1); // start 30, end 60 + assertSame(sfs.get(3), sf2); // start 40 + assertSame(sfs.get(4), sf3); // start 50 + } + + @Test(groups = "Functional") + public void testGetFeaturesForGroup() + { + SequenceFeaturesI store = new SequenceFeatures(); + + List 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(0, 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(0, 5)); + + // non-positional features untouched: + List nonPos = store.getNonPositionalFeatures(); + assertEquals(nonPos.size(), 1); + assertTrue(nonPos.contains(sf4)); + + // positional features are replaced + List 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(0, -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"); + + /* + * shift right by 4 from column 2 + * feature at [1-4] should be unchanged + * feature at [13-22] should become [17-26] + */ + assertTrue(store.shiftFeatures(2, 4)); + 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(), 17); + assertEquals(pos.get(1).getEnd(), 26); + assertEquals(pos.get(1).getType(), "Disulfide bond"); + + /* + * shift right from column 18 + * should be no updates + */ + SequenceFeature f1 = pos.get(0); + SequenceFeature f2 = pos.get(1); + assertFalse(store.shiftFeatures(18, 6)); + pos = store.getPositionalFeatures(); + assertEquals(pos.size(), 2); + SequenceFeatures.sortFeatures(pos, true); + assertSame(pos.get(0), f1); + assertSame(pos.get(1), f2); + } + + @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)); + } + + @Test(groups = "Functional") + public void testDeleteAll() + { + SequenceFeaturesI store = new SequenceFeatures(); + assertFalse(store.hasFeatures()); + store.deleteAll(); + assertFalse(store.hasFeatures()); + store.add(new SequenceFeature("Cath", "Desc", 12, 20, 0f, "Group")); + store.add(new SequenceFeature("Pfam", "Desc", 6, 12, 2f, "Group2")); + assertTrue(store.hasFeatures()); + store.deleteAll(); + assertFalse(store.hasFeatures()); + } }