/*
* 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.List;
import java.util.Set;
import org.testng.annotations.Test;
public class FeatureStoreTest
{
@Test(groups = "Functional")
public void testFindFeatures_nonNested()
{
FeatureStore fs = new FeatureStore();
fs.addFeature(new SequenceFeature("", "", 10, 20, Float.NaN, null));
// same range different description
fs.addFeature(new SequenceFeature("", "desc", 10, 20, Float.NaN, null));
fs.addFeature(new SequenceFeature("", "", 15, 25, Float.NaN, null));
fs.addFeature(new SequenceFeature("", "", 20, 35, Float.NaN, null));
List overlaps = fs.findOverlappingFeatures(1, 9);
assertTrue(overlaps.isEmpty());
overlaps = fs.findOverlappingFeatures(8, 10);
assertEquals(overlaps.size(), 2);
assertEquals(overlaps.get(0).getEnd(), 20);
assertEquals(overlaps.get(1).getEnd(), 20);
overlaps = fs.findOverlappingFeatures(12, 16);
assertEquals(overlaps.size(), 3);
assertEquals(overlaps.get(0).getEnd(), 20);
assertEquals(overlaps.get(1).getEnd(), 20);
assertEquals(overlaps.get(2).getEnd(), 25);
overlaps = fs.findOverlappingFeatures(33, 33);
assertEquals(overlaps.size(), 1);
assertEquals(overlaps.get(0).getEnd(), 35);
}
@Test(groups = "Functional")
public void testFindFeatures_nested()
{
FeatureStore fs = new FeatureStore();
SequenceFeature sf1 = addFeature(fs, 10, 50);
SequenceFeature sf2 = addFeature(fs, 10, 40);
SequenceFeature sf3 = addFeature(fs, 20, 30);
// fudge feature at same location but different group (so is added)
SequenceFeature sf4 = new SequenceFeature("", "", 20, 30, Float.NaN,
"different group");
fs.addFeature(sf4);
SequenceFeature sf5 = addFeature(fs, 35, 36);
List overlaps = fs.findOverlappingFeatures(1, 9);
assertTrue(overlaps.isEmpty());
overlaps = fs.findOverlappingFeatures(10, 15);
assertEquals(overlaps.size(), 2);
assertTrue(overlaps.contains(sf1));
assertTrue(overlaps.contains(sf2));
overlaps = fs.findOverlappingFeatures(45, 60);
assertEquals(overlaps.size(), 1);
assertTrue(overlaps.contains(sf1));
overlaps = fs.findOverlappingFeatures(32, 38);
assertEquals(overlaps.size(), 3);
assertTrue(overlaps.contains(sf1));
assertTrue(overlaps.contains(sf2));
assertTrue(overlaps.contains(sf5));
overlaps = fs.findOverlappingFeatures(15, 25);
assertEquals(overlaps.size(), 4);
assertTrue(overlaps.contains(sf1));
assertTrue(overlaps.contains(sf2));
assertTrue(overlaps.contains(sf3));
assertTrue(overlaps.contains(sf4));
}
@Test(groups = "Functional")
public void testFindFeatures_mixed()
{
FeatureStore fs = new FeatureStore();
SequenceFeature sf1 = addFeature(fs, 10, 50);
SequenceFeature sf2 = addFeature(fs, 1, 15);
SequenceFeature sf3 = addFeature(fs, 20, 30);
SequenceFeature sf4 = addFeature(fs, 40, 100);
SequenceFeature sf5 = addFeature(fs, 60, 100);
SequenceFeature sf6 = addFeature(fs, 70, 70);
List overlaps = fs.findOverlappingFeatures(200, 200);
assertTrue(overlaps.isEmpty());
overlaps = fs.findOverlappingFeatures(1, 9);
assertEquals(overlaps.size(), 1);
assertTrue(overlaps.contains(sf2));
overlaps = fs.findOverlappingFeatures(5, 18);
assertEquals(overlaps.size(), 2);
assertTrue(overlaps.contains(sf1));
assertTrue(overlaps.contains(sf2));
overlaps = fs.findOverlappingFeatures(30, 40);
assertEquals(overlaps.size(), 3);
assertTrue(overlaps.contains(sf1));
assertTrue(overlaps.contains(sf3));
assertTrue(overlaps.contains(sf4));
overlaps = fs.findOverlappingFeatures(80, 90);
assertEquals(overlaps.size(), 2);
assertTrue(overlaps.contains(sf4));
assertTrue(overlaps.contains(sf5));
overlaps = fs.findOverlappingFeatures(68, 70);
assertEquals(overlaps.size(), 3);
assertTrue(overlaps.contains(sf4));
assertTrue(overlaps.contains(sf5));
assertTrue(overlaps.contains(sf6));
}
/**
* Helper method to add a feature of no particular type
*
* @param fs
* @param from
* @param to
* @return
*/
SequenceFeature addFeature(FeatureStore fs, int from, int to)
{
SequenceFeature sf1 = new SequenceFeature("", "", from, to, Float.NaN,
null);
fs.addFeature(sf1);
return sf1;
}
@Test(groups = "Functional")
public void testFindFeatures_contactFeatures()
{
FeatureStore fs = new FeatureStore();
SequenceFeature sf = new SequenceFeature("disulphide bond", "bond", 10,
20, Float.NaN, null);
fs.addFeature(sf);
/*
* neither contact point in range
*/
List overlaps = fs.findOverlappingFeatures(1, 9);
assertTrue(overlaps.isEmpty());
/*
* neither contact point in range
*/
overlaps = fs.findOverlappingFeatures(11, 19);
assertTrue(overlaps.isEmpty());
/*
* first contact point in range
*/
overlaps = fs.findOverlappingFeatures(5, 15);
assertEquals(overlaps.size(), 1);
assertTrue(overlaps.contains(sf));
/*
* second contact point in range
*/
overlaps = fs.findOverlappingFeatures(15, 25);
assertEquals(overlaps.size(), 1);
assertTrue(overlaps.contains(sf));
/*
* both contact points in range
*/
overlaps = fs.findOverlappingFeatures(5, 25);
assertEquals(overlaps.size(), 1);
assertTrue(overlaps.contains(sf));
}
@Test(groups = "Functional")
public void testGetPositionalFeatures()
{
FeatureStore store = new FeatureStore();
SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
Float.NaN, null);
store.addFeature(sf1);
// same range, different description
SequenceFeature sf2 = new SequenceFeature("Metal", "desc2", 10, 20,
Float.NaN, null);
store.addFeature(sf2);
// discontiguous range
SequenceFeature sf3 = new SequenceFeature("Metal", "desc", 30, 40,
Float.NaN, null);
store.addFeature(sf3);
// overlapping range
SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 15, 35,
Float.NaN, null);
store.addFeature(sf4);
// enclosing range
SequenceFeature sf5 = new SequenceFeature("Metal", "desc", 5, 50,
Float.NaN, null);
store.addFeature(sf5);
// non-positional feature
SequenceFeature sf6 = new SequenceFeature("Metal", "desc", 0, 0,
Float.NaN, null);
store.addFeature(sf6);
// contact feature
SequenceFeature sf7 = new SequenceFeature("Disulphide bond", "desc", 18,
45, Float.NaN, null);
store.addFeature(sf7);
List features = store.getPositionalFeatures();
assertEquals(features.size(), 6);
assertTrue(features.contains(sf1));
assertTrue(features.contains(sf2));
assertTrue(features.contains(sf3));
assertTrue(features.contains(sf4));
assertTrue(features.contains(sf5));
assertFalse(features.contains(sf6));
assertTrue(features.contains(sf7));
features = store.getNonPositionalFeatures();
assertEquals(features.size(), 1);
assertTrue(features.contains(sf6));
}
@Test(groups = "Functional")
public void testDelete()
{
FeatureStore store = new FeatureStore();
SequenceFeature sf1 = addFeature(store, 10, 20);
assertTrue(store.getPositionalFeatures().contains(sf1));
/*
* simple deletion
*/
assertTrue(store.delete(sf1));
assertTrue(store.getPositionalFeatures().isEmpty());
/*
* non-positional feature deletion
*/
SequenceFeature sf2 = addFeature(store, 0, 0);
assertFalse(store.getPositionalFeatures().contains(sf2));
assertTrue(store.getNonPositionalFeatures().contains(sf2));
assertTrue(store.delete(sf2));
assertTrue(store.getNonPositionalFeatures().isEmpty());
/*
* contact feature deletion
*/
SequenceFeature sf3 = new SequenceFeature("", "Disulphide Bond", 11, 23,
Float.NaN, null);
store.addFeature(sf3);
assertEquals(store.getPositionalFeatures().size(), 1);
assertTrue(store.getPositionalFeatures().contains(sf3));
assertTrue(store.delete(sf3));
assertTrue(store.getPositionalFeatures().isEmpty());
/*
* nested feature deletion
*/
SequenceFeature sf4 = addFeature(store, 20, 30);
SequenceFeature sf5 = addFeature(store, 22, 26); // to NCList
SequenceFeature sf6 = addFeature(store, 23, 24); // child of sf5
SequenceFeature sf7 = addFeature(store, 25, 25); // sibling of sf6
SequenceFeature sf8 = addFeature(store, 24, 24); // child of sf6
SequenceFeature sf9 = addFeature(store, 23, 23); // child of sf6
assertEquals(store.getPositionalFeatures().size(), 6);
// delete a node with children - they take its place
assertTrue(store.delete(sf6)); // sf8, sf9 should become children of sf5
assertEquals(store.getPositionalFeatures().size(), 5);
assertFalse(store.getPositionalFeatures().contains(sf6));
// delete a node with no children
assertTrue(store.delete(sf7));
assertEquals(store.getPositionalFeatures().size(), 4);
assertFalse(store.getPositionalFeatures().contains(sf7));
// delete root of NCList
assertTrue(store.delete(sf5));
assertEquals(store.getPositionalFeatures().size(), 3);
assertFalse(store.getPositionalFeatures().contains(sf5));
// continue the killing fields
assertTrue(store.delete(sf4));
assertEquals(store.getPositionalFeatures().size(), 2);
assertFalse(store.getPositionalFeatures().contains(sf4));
assertTrue(store.delete(sf9));
assertEquals(store.getPositionalFeatures().size(), 1);
assertFalse(store.getPositionalFeatures().contains(sf9));
assertTrue(store.delete(sf8));
assertTrue(store.getPositionalFeatures().isEmpty());
}
@Test(groups = "Functional")
public void testAddFeature()
{
FeatureStore fs = new FeatureStore();
SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20, Float.NaN,
null);
SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 20, Float.NaN,
null);
assertTrue(fs.addFeature(sf1));
assertEquals(fs.getFeatureCount(true), 1); // positional
assertEquals(fs.getFeatureCount(false), 0); // non-positional
/*
* re-adding the same or an identical feature should fail
*/
assertFalse(fs.addFeature(sf1));
assertEquals(fs.getFeatureCount(true), 1);
assertFalse(fs.addFeature(sf2));
assertEquals(fs.getFeatureCount(true), 1);
/*
* add non-positional
*/
SequenceFeature sf3 = new SequenceFeature("Cath", "", 0, 0, Float.NaN,
null);
assertTrue(fs.addFeature(sf3));
assertEquals(fs.getFeatureCount(true), 1); // positional
assertEquals(fs.getFeatureCount(false), 1); // non-positional
SequenceFeature sf4 = new SequenceFeature("Cath", "", 0, 0, Float.NaN,
null);
assertFalse(fs.addFeature(sf4)); // already stored
assertEquals(fs.getFeatureCount(true), 1); // positional
assertEquals(fs.getFeatureCount(false), 1); // non-positional
/*
* add contact
*/
SequenceFeature sf5 = new SequenceFeature("Disulfide bond", "", 10, 20,
Float.NaN, null);
assertTrue(fs.addFeature(sf5));
assertEquals(fs.getFeatureCount(true), 2); // positional - add 1 for contact
assertEquals(fs.getFeatureCount(false), 1); // non-positional
SequenceFeature sf6 = new SequenceFeature("Disulfide bond", "", 10, 20,
Float.NaN, null);
assertFalse(fs.addFeature(sf6)); // already stored
assertEquals(fs.getFeatureCount(true), 2); // no change
assertEquals(fs.getFeatureCount(false), 1); // no change
}
@Test(groups = "Functional")
public void testIsEmpty()
{
FeatureStore fs = new FeatureStore();
assertTrue(fs.isEmpty());
assertEquals(fs.getFeatureCount(true), 0);
/*
* non-nested feature
*/
SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20, Float.NaN,
null);
fs.addFeature(sf1);
assertFalse(fs.isEmpty());
assertEquals(fs.getFeatureCount(true), 1);
fs.delete(sf1);
assertTrue(fs.isEmpty());
assertEquals(fs.getFeatureCount(true), 0);
/*
* non-positional feature
*/
sf1 = new SequenceFeature("Cath", "", 0, 0, Float.NaN, null);
fs.addFeature(sf1);
assertFalse(fs.isEmpty());
assertEquals(fs.getFeatureCount(false), 1); // non-positional
assertEquals(fs.getFeatureCount(true), 0); // positional
fs.delete(sf1);
assertTrue(fs.isEmpty());
assertEquals(fs.getFeatureCount(false), 0);
/*
* contact feature
*/
sf1 = new SequenceFeature("Disulfide bond", "", 19, 49, Float.NaN,
null);
fs.addFeature(sf1);
assertFalse(fs.isEmpty());
assertEquals(fs.getFeatureCount(true), 1);
fs.delete(sf1);
assertTrue(fs.isEmpty());
assertEquals(fs.getFeatureCount(true), 0);
/*
* sf2, sf3 added as nested features
*/
sf1 = new SequenceFeature("Cath", "", 19, 49, Float.NaN, null);
SequenceFeature sf2 = new SequenceFeature("Cath", "", 20, 40, Float.NaN,
null);
SequenceFeature sf3 = new SequenceFeature("Cath", "", 25, 35, Float.NaN,
null);
fs.addFeature(sf1);
fs.addFeature(sf2);
fs.addFeature(sf3);
assertEquals(fs.getFeatureCount(true), 3);
assertTrue(fs.delete(sf1));
assertEquals(fs.getFeatureCount(true), 2);
assertEquals(fs.features.size(), 2);
assertFalse(fs.isEmpty());
assertTrue(fs.delete(sf2));
assertEquals(fs.getFeatureCount(true), 1);
assertFalse(fs.isEmpty());
assertTrue(fs.delete(sf3));
assertEquals(fs.getFeatureCount(true), 0);
assertTrue(fs.isEmpty()); // all gone
}
@Test(groups = "Functional")
public void testGetFeatureGroups()
{
FeatureStore fs = new FeatureStore();
assertTrue(fs.getFeatureGroups(true).isEmpty());
assertTrue(fs.getFeatureGroups(false).isEmpty());
SequenceFeature sf1 = new SequenceFeature("Cath", "desc", 10, 20, 1f,
"group1");
fs.addFeature(sf1);
Set groups = fs.getFeatureGroups(true);
assertEquals(groups.size(), 1);
assertTrue(groups.contains("group1"));
/*
* add another feature of the same group, delete one, delete both
*/
SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 20, 30, 1f,
"group1");
fs.addFeature(sf2);
groups = fs.getFeatureGroups(true);
assertEquals(groups.size(), 1);
assertTrue(groups.contains("group1"));
fs.delete(sf2);
groups = fs.getFeatureGroups(true);
assertEquals(groups.size(), 1);
assertTrue(groups.contains("group1"));
fs.delete(sf1);
groups = fs.getFeatureGroups(true);
assertTrue(fs.getFeatureGroups(true).isEmpty());
SequenceFeature sf3 = new SequenceFeature("Cath", "desc", 20, 30, 1f,
"group2");
fs.addFeature(sf3);
SequenceFeature sf4 = new SequenceFeature("Cath", "desc", 20, 30, 1f,
"Group2");
fs.addFeature(sf4);
SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 20, 30, 1f,
null);
fs.addFeature(sf5);
groups = fs.getFeatureGroups(true);
assertEquals(groups.size(), 3);
assertTrue(groups.contains("group2"));
assertTrue(groups.contains("Group2")); // case sensitive
assertTrue(groups.contains(null)); // null allowed
assertTrue(fs.getFeatureGroups(false).isEmpty()); // non-positional
fs.delete(sf3);
groups = fs.getFeatureGroups(true);
assertEquals(groups.size(), 2);
assertFalse(groups.contains("group2"));
fs.delete(sf4);
groups = fs.getFeatureGroups(true);
assertEquals(groups.size(), 1);
assertFalse(groups.contains("Group2"));
fs.delete(sf5);
groups = fs.getFeatureGroups(true);
assertTrue(groups.isEmpty());
/*
* add non-positional feature
*/
SequenceFeature sf6 = new SequenceFeature("Cath", "desc", 0, 0, 1f,
"CathGroup");
fs.addFeature(sf6);
groups = fs.getFeatureGroups(false);
assertEquals(groups.size(), 1);
assertTrue(groups.contains("CathGroup"));
assertTrue(fs.delete(sf6));
assertTrue(fs.getFeatureGroups(false).isEmpty());
}
@Test(groups = "Functional")
public void testGetTotalFeatureLength()
{
FeatureStore fs = new FeatureStore();
assertEquals(fs.getTotalFeatureLength(), 0);
addFeature(fs, 10, 20); // 11
assertEquals(fs.getTotalFeatureLength(), 11);
addFeature(fs, 17, 37); // 21
SequenceFeature sf1 = addFeature(fs, 14, 74); // 61
assertEquals(fs.getTotalFeatureLength(), 93);
// non-positional features don't count
SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 0, 0, 1f,
"group1");
fs.addFeature(sf2);
assertEquals(fs.getTotalFeatureLength(), 93);
// contact features count 1
SequenceFeature sf3 = new SequenceFeature("disulphide bond", "desc", 15,
35, 1f, "group1");
fs.addFeature(sf3);
assertEquals(fs.getTotalFeatureLength(), 94);
assertTrue(fs.delete(sf1));
assertEquals(fs.getTotalFeatureLength(), 33);
assertFalse(fs.delete(sf1));
assertEquals(fs.getTotalFeatureLength(), 33);
assertTrue(fs.delete(sf2));
assertEquals(fs.getTotalFeatureLength(), 33);
assertTrue(fs.delete(sf3));
assertEquals(fs.getTotalFeatureLength(), 32);
}
@Test(groups = "Functional")
public void testGetFeatureLength()
{
/*
* positional feature
*/
SequenceFeature sf1 = new SequenceFeature("Cath", "desc", 10, 20, 1f,
"group1");
assertEquals(FeatureStore.getFeatureLength(sf1), 11);
/*
* non-positional feature
*/
SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 0, 0, 1f,
"CathGroup");
assertEquals(FeatureStore.getFeatureLength(sf2), 0);
/*
* contact feature counts 1
*/
SequenceFeature sf3 = new SequenceFeature("Disulphide Bond", "desc", 14,
28, 1f, "AGroup");
assertEquals(FeatureStore.getFeatureLength(sf3), 1);
}
@Test(groups = "Functional")
public void testMin()
{
assertEquals(FeatureStore.min(Float.NaN, Float.NaN), Float.NaN);
assertEquals(FeatureStore.min(Float.NaN, 2f), 2f);
assertEquals(FeatureStore.min(-2f, Float.NaN), -2f);
assertEquals(FeatureStore.min(2f, -3f), -3f);
}
@Test(groups = "Functional")
public void testMax()
{
assertEquals(FeatureStore.max(Float.NaN, Float.NaN), Float.NaN);
assertEquals(FeatureStore.max(Float.NaN, 2f), 2f);
assertEquals(FeatureStore.max(-2f, Float.NaN), -2f);
assertEquals(FeatureStore.max(2f, -3f), 2f);
}
@Test(groups = "Functional")
public void testGetMinimumScore_getMaximumScore()
{
FeatureStore fs = new FeatureStore();
assertEquals(fs.getMinimumScore(true), Float.NaN); // positional
assertEquals(fs.getMaximumScore(true), Float.NaN);
assertEquals(fs.getMinimumScore(false), Float.NaN); // non-positional
assertEquals(fs.getMaximumScore(false), Float.NaN);
// add features with no score
SequenceFeature sf1 = new SequenceFeature("type", "desc", 0, 0,
Float.NaN, "group");
fs.addFeature(sf1);
SequenceFeature sf2 = new SequenceFeature("type", "desc", 10, 20,
Float.NaN, "group");
fs.addFeature(sf2);
assertEquals(fs.getMinimumScore(true), Float.NaN);
assertEquals(fs.getMaximumScore(true), Float.NaN);
assertEquals(fs.getMinimumScore(false), Float.NaN);
assertEquals(fs.getMaximumScore(false), Float.NaN);
// add positional features with score
SequenceFeature sf3 = new SequenceFeature("type", "desc", 10, 20, 1f,
"group");
fs.addFeature(sf3);
SequenceFeature sf4 = new SequenceFeature("type", "desc", 12, 16, 4f,
"group");
fs.addFeature(sf4);
assertEquals(fs.getMinimumScore(true), 1f);
assertEquals(fs.getMaximumScore(true), 4f);
assertEquals(fs.getMinimumScore(false), Float.NaN);
assertEquals(fs.getMaximumScore(false), Float.NaN);
// add non-positional features with score
SequenceFeature sf5 = new SequenceFeature("type", "desc", 0, 0, 11f,
"group");
fs.addFeature(sf5);
SequenceFeature sf6 = new SequenceFeature("type", "desc", 0, 0, -7f,
"group");
fs.addFeature(sf6);
assertEquals(fs.getMinimumScore(true), 1f);
assertEquals(fs.getMaximumScore(true), 4f);
assertEquals(fs.getMinimumScore(false), -7f);
assertEquals(fs.getMaximumScore(false), 11f);
// delete one positional and one non-positional
// min-max should be recomputed
assertTrue(fs.delete(sf6));
assertTrue(fs.delete(sf3));
assertEquals(fs.getMinimumScore(true), 4f);
assertEquals(fs.getMaximumScore(true), 4f);
assertEquals(fs.getMinimumScore(false), 11f);
assertEquals(fs.getMaximumScore(false), 11f);
// delete remaining features with score
assertTrue(fs.delete(sf4));
assertTrue(fs.delete(sf5));
assertEquals(fs.getMinimumScore(true), Float.NaN);
assertEquals(fs.getMaximumScore(true), Float.NaN);
assertEquals(fs.getMinimumScore(false), Float.NaN);
assertEquals(fs.getMaximumScore(false), Float.NaN);
// delete all features
assertTrue(fs.delete(sf1));
assertTrue(fs.delete(sf2));
assertTrue(fs.isEmpty());
assertEquals(fs.getMinimumScore(true), Float.NaN);
assertEquals(fs.getMaximumScore(true), Float.NaN);
assertEquals(fs.getMinimumScore(false), Float.NaN);
assertEquals(fs.getMaximumScore(false), Float.NaN);
}
@Test(groups = "Functional")
public void testListContains()
{
assertFalse(FeatureStore.listContains(null, null));
List features = new ArrayList<>();
assertFalse(FeatureStore.listContains(features, null));
SequenceFeature sf1 = new SequenceFeature("type1", "desc1", 20, 30, 3f,
"group1");
assertFalse(FeatureStore.listContains(null, sf1));
assertFalse(FeatureStore.listContains(features, sf1));
features.add(sf1);
SequenceFeature sf2 = new SequenceFeature("type1", "desc1", 20, 30, 3f,
"group1");
SequenceFeature sf3 = new SequenceFeature("type1", "desc1", 20, 40, 3f,
"group1");
// sf2.equals(sf1) so contains should return true
assertTrue(FeatureStore.listContains(features, sf2));
assertFalse(FeatureStore.listContains(features, sf3));
}
@Test(groups = "Functional")
public void testGetFeaturesForGroup()
{
FeatureStore fs = new FeatureStore();
/*
* with no features
*/
assertTrue(fs.getFeaturesForGroup(true, null).isEmpty());
assertTrue(fs.getFeaturesForGroup(false, null).isEmpty());
assertTrue(fs.getFeaturesForGroup(true, "uniprot").isEmpty());
assertTrue(fs.getFeaturesForGroup(false, "uniprot").isEmpty());
/*
* sf1: positional feature in the null group
*/
SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
null);
fs.addFeature(sf1);
assertTrue(fs.getFeaturesForGroup(true, "uniprot").isEmpty());
assertTrue(fs.getFeaturesForGroup(false, "uniprot").isEmpty());
assertTrue(fs.getFeaturesForGroup(false, null).isEmpty());
List features = fs.getFeaturesForGroup(true, null);
assertEquals(features.size(), 1);
assertTrue(features.contains(sf1));
/*
* sf2: non-positional feature in the null group
* sf3: positional feature in a non-null group
* sf4: non-positional feature in a non-null group
*/
SequenceFeature sf2 = new SequenceFeature("Pfam", "desc", 0, 0, 0f,
null);
SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
"Uniprot");
SequenceFeature sf4 = new SequenceFeature("Pfam", "desc", 0, 0, 0f,
"Rfam");
fs.addFeature(sf2);
fs.addFeature(sf3);
fs.addFeature(sf4);
features = fs.getFeaturesForGroup(true, null);
assertEquals(features.size(), 1);
assertTrue(features.contains(sf1));
features = fs.getFeaturesForGroup(false, null);
assertEquals(features.size(), 1);
assertTrue(features.contains(sf2));
features = fs.getFeaturesForGroup(true, "Uniprot");
assertEquals(features.size(), 1);
assertTrue(features.contains(sf3));
features = fs.getFeaturesForGroup(false, "Rfam");
assertEquals(features.size(), 1);
assertTrue(features.contains(sf4));
}
@Test(groups = "Functional")
public void testShiftFeatures()
{
FeatureStore fs = new FeatureStore();
assertFalse(fs.shiftFeatures(0, 1)); // nothing to do
SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
fs.addFeature(sf1);
// nested feature:
SequenceFeature sf2 = new SequenceFeature("Cath", "", 8, 14, 0f, null);
fs.addFeature(sf2);
// contact feature:
SequenceFeature sf3 = new SequenceFeature("Disulfide bond", "", 23, 32,
0f, null);
fs.addFeature(sf3);
// non-positional feature:
SequenceFeature sf4 = new SequenceFeature("Cath", "", 0, 0, 0f, null);
fs.addFeature(sf4);
/*
* shift all features right by 5
*/
assertTrue(fs.shiftFeatures(0, 5));
// non-positional features untouched:
List nonPos = fs.getNonPositionalFeatures();
assertEquals(nonPos.size(), 1);
assertTrue(nonPos.contains(sf4));
// positional features are replaced
List pos = fs.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(1).getBegin(), 13);
assertEquals(pos.get(1).getEnd(), 19);
assertEquals(pos.get(2).getBegin(), 28);
assertEquals(pos.get(2).getEnd(), 37);
/*
* now shift left by 15
* feature at [7-10] should be removed
* feature at [13-19] should become [1-4]
*/
assertTrue(fs.shiftFeatures(0, -15));
pos = fs.getPositionalFeatures();
assertEquals(pos.size(), 2);
SequenceFeatures.sortFeatures(pos, true);
assertEquals(pos.get(0).getBegin(), 1);
assertEquals(pos.get(0).getEnd(), 4);
assertEquals(pos.get(1).getBegin(), 13);
assertEquals(pos.get(1).getEnd(), 22);
/*
* shift right by 4 from position 2 onwards
* feature at [1-4] unchanged, feature at [13-22] shifts
*/
assertTrue(fs.shiftFeatures(2, 4));
pos = fs.getPositionalFeatures();
assertEquals(pos.size(), 2);
SequenceFeatures.sortFeatures(pos, true);
assertEquals(pos.get(0).getBegin(), 1);
assertEquals(pos.get(0).getEnd(), 4);
assertEquals(pos.get(1).getBegin(), 17);
assertEquals(pos.get(1).getEnd(), 26);
/*
* shift right by 4 from position 18 onwards
* should be no change
*/
SequenceFeature f1 = pos.get(0);
SequenceFeature f2 = pos.get(1);
assertFalse(fs.shiftFeatures(18, 4)); // no update
pos = fs.getPositionalFeatures();
assertEquals(pos.size(), 2);
SequenceFeatures.sortFeatures(pos, true);
assertSame(pos.get(0), f1);
assertSame(pos.get(1), f2);
}
@Test(groups = "Functional")
public void testDelete_readd()
{
/*
* add a feature and a nested feature
*/
FeatureStore store = new FeatureStore();
SequenceFeature sf1 = addFeature(store, 10, 20);
// sf2 is nested in sf1 so will be stored in nestedFeatures
SequenceFeature sf2 = addFeature(store, 12, 14);
List features = store.getPositionalFeatures();
assertEquals(features.size(), 2);
assertTrue(features.contains(sf1));
assertTrue(features.contains(sf2));
assertTrue(store.features.contains(sf1));
assertTrue(store.features.contains(sf2));
/*
* delete the first feature
*/
assertTrue(store.delete(sf1));
features = store.getPositionalFeatures();
assertFalse(features.contains(sf1));
assertTrue(features.contains(sf2));
/*
* re-add the 'nested' feature; is it now duplicated?
*/
store.addFeature(sf2);
features = store.getPositionalFeatures();
assertEquals(features.size(), 1);
assertTrue(features.contains(sf2));
}
@Test(groups = "Functional")
public void testContains()
{
FeatureStore fs = new FeatureStore();
SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20, Float.NaN,
"group1");
SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 20, Float.NaN,
"group2");
SequenceFeature sf3 = new SequenceFeature("Cath", "", 0, 0, Float.NaN,
"group1");
SequenceFeature sf4 = new SequenceFeature("Cath", "", 0, 0, 0f,
"group1");
SequenceFeature sf5 = new SequenceFeature("Disulphide Bond", "", 5, 15,
Float.NaN, "group1");
SequenceFeature sf6 = new SequenceFeature("Disulphide Bond", "", 5, 15,
Float.NaN, "group2");
fs.addFeature(sf1);
fs.addFeature(sf3);
fs.addFeature(sf5);
assertTrue(fs.contains(sf1)); // positional feature
assertTrue(fs.contains(new SequenceFeature(sf1))); // identical feature
assertFalse(fs.contains(sf2)); // different group
assertTrue(fs.contains(sf3)); // non-positional
assertTrue(fs.contains(new SequenceFeature(sf3)));
assertFalse(fs.contains(sf4)); // different score
assertTrue(fs.contains(sf5)); // contact feature
assertTrue(fs.contains(new SequenceFeature(sf5)));
assertFalse(fs.contains(sf6)); // different group
/*
* add a nested feature
*/
SequenceFeature sf7 = new SequenceFeature("Cath", "", 12, 16, Float.NaN,
"group1");
fs.addFeature(sf7);
assertTrue(fs.contains(sf7));
assertTrue(fs.contains(new SequenceFeature(sf7)));
/*
* delete the outer (enclosing, non-nested) feature
*/
fs.delete(sf1);
assertFalse(fs.contains(sf1));
assertTrue(fs.contains(sf7));
}
}