1 package jalview.datamodel.features;
3 import static org.testng.Assert.assertEquals;
4 import static org.testng.Assert.assertFalse;
5 import static org.testng.Assert.assertTrue;
7 import jalview.datamodel.SequenceFeature;
11 import org.testng.annotations.Test;
13 public class FeatureStoreTest
16 @Test(groups = "Functional")
17 public void testFindFeatures_nonNested()
19 FeatureStore fs = new FeatureStore();
20 fs.addFeature(new SequenceFeature("", "", 10, 20, Float.NaN,
22 // same range different description
23 fs.addFeature(new SequenceFeature("", "desc", 10, 20, Float.NaN, null));
24 fs.addFeature(new SequenceFeature("", "", 15, 25, Float.NaN, null));
25 fs.addFeature(new SequenceFeature("", "", 20, 35, Float.NaN, null));
27 List<SequenceFeature> overlaps = fs.findOverlappingFeatures(1, 9);
28 assertTrue(overlaps.isEmpty());
30 overlaps = fs.findOverlappingFeatures(8, 10);
31 assertEquals(overlaps.size(), 2);
32 assertEquals(overlaps.get(0).getEnd(), 20);
33 assertEquals(overlaps.get(1).getEnd(), 20);
35 overlaps = fs.findOverlappingFeatures(12, 16);
36 assertEquals(overlaps.size(), 3);
37 assertEquals(overlaps.get(0).getEnd(), 20);
38 assertEquals(overlaps.get(1).getEnd(), 20);
39 assertEquals(overlaps.get(2).getEnd(), 25);
41 overlaps = fs.findOverlappingFeatures(33, 33);
42 assertEquals(overlaps.size(), 1);
43 assertEquals(overlaps.get(0).getEnd(), 35);
46 @Test(groups = "Functional")
47 public void testFindFeatures_nested()
49 FeatureStore fs = new FeatureStore();
50 SequenceFeature sf1 = addFeature(fs, 10, 50);
51 SequenceFeature sf2 = addFeature(fs, 10, 40);
52 SequenceFeature sf3 = addFeature(fs, 20, 30);
53 // fudge feature at same location but different group (so is added)
54 SequenceFeature sf4 = new SequenceFeature("", "", 20, 30, Float.NaN,
57 SequenceFeature sf5 = addFeature(fs, 35, 36);
59 List<SequenceFeature> overlaps = fs.findOverlappingFeatures(1, 9);
60 assertTrue(overlaps.isEmpty());
62 overlaps = fs.findOverlappingFeatures(10, 15);
63 assertEquals(overlaps.size(), 2);
64 assertTrue(overlaps.contains(sf1));
65 assertTrue(overlaps.contains(sf2));
67 overlaps = fs.findOverlappingFeatures(45, 60);
68 assertEquals(overlaps.size(), 1);
69 assertTrue(overlaps.contains(sf1));
71 overlaps = fs.findOverlappingFeatures(32, 38);
72 assertEquals(overlaps.size(), 3);
73 assertTrue(overlaps.contains(sf1));
74 assertTrue(overlaps.contains(sf2));
75 assertTrue(overlaps.contains(sf5));
77 overlaps = fs.findOverlappingFeatures(15, 25);
78 assertEquals(overlaps.size(), 4);
79 assertTrue(overlaps.contains(sf1));
80 assertTrue(overlaps.contains(sf2));
81 assertTrue(overlaps.contains(sf3));
82 assertTrue(overlaps.contains(sf4));
85 @Test(groups = "Functional")
86 public void testFindFeatures_mixed()
88 FeatureStore fs = new FeatureStore();
89 SequenceFeature sf1 = addFeature(fs, 10, 50);
90 SequenceFeature sf2 = addFeature(fs, 1, 15);
91 SequenceFeature sf3 = addFeature(fs, 20, 30);
92 SequenceFeature sf4 = addFeature(fs, 40, 100);
93 SequenceFeature sf5 = addFeature(fs, 60, 100);
94 SequenceFeature sf6 = addFeature(fs, 70, 70);
96 List<SequenceFeature> overlaps = fs.findOverlappingFeatures(200, 200);
97 assertTrue(overlaps.isEmpty());
99 overlaps = fs.findOverlappingFeatures(1, 9);
100 assertEquals(overlaps.size(), 1);
101 assertTrue(overlaps.contains(sf2));
103 overlaps = fs.findOverlappingFeatures(5, 18);
104 assertEquals(overlaps.size(), 2);
105 assertTrue(overlaps.contains(sf1));
106 assertTrue(overlaps.contains(sf2));
108 overlaps = fs.findOverlappingFeatures(30, 40);
109 assertEquals(overlaps.size(), 3);
110 assertTrue(overlaps.contains(sf1));
111 assertTrue(overlaps.contains(sf3));
112 assertTrue(overlaps.contains(sf4));
114 overlaps = fs.findOverlappingFeatures(80, 90);
115 assertEquals(overlaps.size(), 2);
116 assertTrue(overlaps.contains(sf4));
117 assertTrue(overlaps.contains(sf5));
119 overlaps = fs.findOverlappingFeatures(68, 70);
120 assertEquals(overlaps.size(), 3);
121 assertTrue(overlaps.contains(sf4));
122 assertTrue(overlaps.contains(sf5));
123 assertTrue(overlaps.contains(sf6));
127 * Helper method to add a feature of no particular type
134 SequenceFeature addFeature(FeatureStore fs, int from, int to)
136 SequenceFeature sf1 = new SequenceFeature("", "", from, to, Float.NaN,
142 @Test(groups = "Functional")
143 public void testFindFeatures_contactFeatures()
145 FeatureStore fs = new FeatureStore();
147 SequenceFeature sf = new SequenceFeature("disulphide bond", "bond", 10,
148 20, Float.NaN, null);
152 * neither contact point in range
154 List<SequenceFeature> overlaps = fs.findOverlappingFeatures(1, 9);
155 assertTrue(overlaps.isEmpty());
158 * neither contact point in range
160 overlaps = fs.findOverlappingFeatures(11, 19);
161 assertTrue(overlaps.isEmpty());
164 * first contact point in range
166 overlaps = fs.findOverlappingFeatures(5, 15);
167 assertEquals(overlaps.size(), 1);
168 assertTrue(overlaps.contains(sf));
171 * second contact point in range
173 overlaps = fs.findOverlappingFeatures(15, 25);
174 assertEquals(overlaps.size(), 1);
175 assertTrue(overlaps.contains(sf));
178 * both contact points in range
180 overlaps = fs.findOverlappingFeatures(5, 25);
181 assertEquals(overlaps.size(), 1);
182 assertTrue(overlaps.contains(sf));
186 * Tests for the method that returns false for an attempt to add a feature
187 * that would enclose, or be enclosed by, another feature
189 @Test(groups = "Functional")
190 public void testAddNonNestedFeature()
192 FeatureStore fs = new FeatureStore();
194 String type = "Domain";
195 SequenceFeature sf1 = new SequenceFeature(type, type, 10, 20,
197 assertTrue(fs.addNonNestedFeature(sf1));
199 // co-located feature is ok
200 SequenceFeature sf2 = new SequenceFeature(type, type, 10, 20,
202 assertTrue(fs.addNonNestedFeature(sf2));
204 // overlap left is ok
205 SequenceFeature sf3 = new SequenceFeature(type, type, 5, 15, Float.NaN,
207 assertTrue(fs.addNonNestedFeature(sf3));
209 // overlap right is ok
210 SequenceFeature sf4 = new SequenceFeature(type, type, 15, 25,
212 assertTrue(fs.addNonNestedFeature(sf4));
214 // add enclosing feature is not ok
215 SequenceFeature sf5 = new SequenceFeature(type, type, 10, 21,
217 assertFalse(fs.addNonNestedFeature(sf5));
218 SequenceFeature sf6 = new SequenceFeature(type, type, 4, 15, Float.NaN,
220 assertFalse(fs.addNonNestedFeature(sf6));
221 SequenceFeature sf7 = new SequenceFeature(type, type, 1, 50, Float.NaN,
223 assertFalse(fs.addNonNestedFeature(sf7));
225 // add enclosed feature is not ok
226 SequenceFeature sf8 = new SequenceFeature(type, type, 10, 19,
228 assertFalse(fs.addNonNestedFeature(sf8));
229 SequenceFeature sf9 = new SequenceFeature(type, type, 16, 25,
231 assertFalse(fs.addNonNestedFeature(sf9));
232 SequenceFeature sf10 = new SequenceFeature(type, type, 7, 7, Float.NaN,
234 assertFalse(fs.addNonNestedFeature(sf10));
237 @Test(groups = "Functional")
238 public void testGetFeatures()
240 FeatureStore store = new FeatureStore();
241 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
243 store.addFeature(sf1);
244 // same range, different description
245 SequenceFeature sf2 = new SequenceFeature("Metal", "desc2", 10, 20,
247 store.addFeature(sf2);
248 // discontiguous range
249 SequenceFeature sf3 = new SequenceFeature("Metal", "desc", 30, 40,
251 store.addFeature(sf3);
253 SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 15, 35,
255 store.addFeature(sf4);
257 SequenceFeature sf5 = new SequenceFeature("Metal", "desc", 5, 50,
259 store.addFeature(sf5);
260 // non-positional feature
261 SequenceFeature sf6 = new SequenceFeature("Metal", "desc", 0, 0,
263 store.addFeature(sf6);
265 SequenceFeature sf7 = new SequenceFeature("Disulphide bond", "desc",
266 18, 45, Float.NaN, null);
267 store.addFeature(sf7);
269 List<SequenceFeature> features = store.getFeatures();
270 assertEquals(features.size(), 7);
271 assertTrue(features.contains(sf1));
272 assertTrue(features.contains(sf2));
273 assertTrue(features.contains(sf3));
274 assertTrue(features.contains(sf4));
275 assertTrue(features.contains(sf5));
276 assertTrue(features.contains(sf6));
277 assertTrue(features.contains(sf7));
280 @Test(groups = "Functional")
281 public void testDelete()
283 FeatureStore store = new FeatureStore();
284 SequenceFeature sf1 = addFeature(store, 10, 20);
285 assertTrue(store.getFeatures().contains(sf1));
290 assertTrue(store.delete(sf1));
291 assertTrue(store.getFeatures().isEmpty());
294 * non-positional feature deletion
296 SequenceFeature sf2 = addFeature(store, 0, 0);
297 assertTrue(store.getFeatures().contains(sf2));
298 assertTrue(store.delete(sf2));
299 assertTrue(store.getFeatures().isEmpty());
302 * contact feature deletion
304 SequenceFeature sf3 = new SequenceFeature("", "Disulphide Bond", 11,
305 23, Float.NaN, null);
306 store.addFeature(sf3);
307 assertEquals(store.getFeatures().size(), 1);
308 assertTrue(store.getFeatures().contains(sf3));
309 assertTrue(store.delete(sf3));
310 assertTrue(store.getFeatures().isEmpty());
313 * nested feature deletion
315 SequenceFeature sf4 = addFeature(store, 20, 30);
316 SequenceFeature sf5 = addFeature(store, 22, 26); // to NCList
317 SequenceFeature sf6 = addFeature(store, 23, 24); // child of sf5
318 SequenceFeature sf7 = addFeature(store, 25, 25); // sibling of sf6
319 SequenceFeature sf8 = addFeature(store, 24, 24); // child of sf6
320 SequenceFeature sf9 = addFeature(store, 23, 23); // child of sf6
321 assertEquals(store.getFeatures().size(), 6);
323 // delete a node with children - they take its place
324 assertTrue(store.delete(sf6)); // sf8, sf9 should become children of sf5
325 assertEquals(store.getFeatures().size(), 5);
326 assertFalse(store.getFeatures().contains(sf6));
328 // delete a node with no children
329 assertTrue(store.delete(sf7));
330 assertEquals(store.getFeatures().size(), 4);
331 assertFalse(store.getFeatures().contains(sf7));
333 // delete root of NCList
334 assertTrue(store.delete(sf5));
335 assertEquals(store.getFeatures().size(), 3);
336 assertFalse(store.getFeatures().contains(sf5));
338 // continue the killing fields
339 assertTrue(store.delete(sf4));
340 assertEquals(store.getFeatures().size(), 2);
341 assertFalse(store.getFeatures().contains(sf4));
343 assertTrue(store.delete(sf9));
344 assertEquals(store.getFeatures().size(), 1);
345 assertFalse(store.getFeatures().contains(sf9));
347 assertTrue(store.delete(sf8));
348 assertTrue(store.getFeatures().isEmpty());
351 @Test(groups = "Functional")
352 public void testAddFeature()
354 FeatureStore fs = new FeatureStore();
356 SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20,
358 SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 20,
361 assertTrue(fs.addFeature(sf1));
364 * re-adding the same or an identical feature should fail
366 assertFalse(fs.addFeature(sf1));
367 assertFalse(fs.addFeature(sf2));
370 @Test(groups = "Functional")
371 public void testIsEmpty()
373 FeatureStore fs = new FeatureStore();
374 assertTrue(fs.isEmpty());
379 SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20,
382 assertFalse(fs.isEmpty());
384 assertTrue(fs.isEmpty());
387 * non-positional feature
389 sf1 = new SequenceFeature("Cath", "", 0, 0, Float.NaN, null);
391 assertFalse(fs.isEmpty());
393 assertTrue(fs.isEmpty());
398 sf1 = new SequenceFeature("Disulfide bond", "", 19, 49, Float.NaN, null);
400 assertFalse(fs.isEmpty());
402 assertTrue(fs.isEmpty());
405 * sf2, sf3 added as nested features
407 sf1 = new SequenceFeature("Cath", "", 19, 49, Float.NaN, null);
408 SequenceFeature sf2 = new SequenceFeature("Cath", "", 20, 40,
410 SequenceFeature sf3 = new SequenceFeature("Cath", "", 25, 35,
415 assertTrue(fs.delete(sf1));
416 // FeatureStore should now only contain features in the NCList
417 assertEquals(fs.nonNestedFeatures.size(), 0);
418 assertEquals(fs.nestedFeatures.size(), 2);
419 assertFalse(fs.isEmpty());
420 assertTrue(fs.delete(sf2));
421 assertFalse(fs.isEmpty());
422 assertTrue(fs.delete(sf3));
423 assertTrue(fs.isEmpty()); // all gone