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;
12 import org.testng.annotations.Test;
14 public class FeatureStoreTest
17 @Test(groups = "Functional")
18 public void testFindFeatures_nonNested()
20 FeatureStore fs = new FeatureStore();
21 fs.addFeature(new SequenceFeature("", "", 10, 20, Float.NaN,
23 // same range different description
24 fs.addFeature(new SequenceFeature("", "desc", 10, 20, Float.NaN, null));
25 fs.addFeature(new SequenceFeature("", "", 15, 25, Float.NaN, null));
26 fs.addFeature(new SequenceFeature("", "", 20, 35, Float.NaN, null));
28 List<SequenceFeature> overlaps = fs.findOverlappingFeatures(1, 9);
29 assertTrue(overlaps.isEmpty());
31 overlaps = fs.findOverlappingFeatures(8, 10);
32 assertEquals(overlaps.size(), 2);
33 assertEquals(overlaps.get(0).getEnd(), 20);
34 assertEquals(overlaps.get(1).getEnd(), 20);
36 overlaps = fs.findOverlappingFeatures(12, 16);
37 assertEquals(overlaps.size(), 3);
38 assertEquals(overlaps.get(0).getEnd(), 20);
39 assertEquals(overlaps.get(1).getEnd(), 20);
40 assertEquals(overlaps.get(2).getEnd(), 25);
42 overlaps = fs.findOverlappingFeatures(33, 33);
43 assertEquals(overlaps.size(), 1);
44 assertEquals(overlaps.get(0).getEnd(), 35);
47 @Test(groups = "Functional")
48 public void testFindFeatures_nested()
50 FeatureStore fs = new FeatureStore();
51 SequenceFeature sf1 = addFeature(fs, 10, 50);
52 SequenceFeature sf2 = addFeature(fs, 10, 40);
53 SequenceFeature sf3 = addFeature(fs, 20, 30);
54 // fudge feature at same location but different group (so is added)
55 SequenceFeature sf4 = new SequenceFeature("", "", 20, 30, Float.NaN,
58 SequenceFeature sf5 = addFeature(fs, 35, 36);
60 List<SequenceFeature> overlaps = fs.findOverlappingFeatures(1, 9);
61 assertTrue(overlaps.isEmpty());
63 overlaps = fs.findOverlappingFeatures(10, 15);
64 assertEquals(overlaps.size(), 2);
65 assertTrue(overlaps.contains(sf1));
66 assertTrue(overlaps.contains(sf2));
68 overlaps = fs.findOverlappingFeatures(45, 60);
69 assertEquals(overlaps.size(), 1);
70 assertTrue(overlaps.contains(sf1));
72 overlaps = fs.findOverlappingFeatures(32, 38);
73 assertEquals(overlaps.size(), 3);
74 assertTrue(overlaps.contains(sf1));
75 assertTrue(overlaps.contains(sf2));
76 assertTrue(overlaps.contains(sf5));
78 overlaps = fs.findOverlappingFeatures(15, 25);
79 assertEquals(overlaps.size(), 4);
80 assertTrue(overlaps.contains(sf1));
81 assertTrue(overlaps.contains(sf2));
82 assertTrue(overlaps.contains(sf3));
83 assertTrue(overlaps.contains(sf4));
86 @Test(groups = "Functional")
87 public void testFindFeatures_mixed()
89 FeatureStore fs = new FeatureStore();
90 SequenceFeature sf1 = addFeature(fs, 10, 50);
91 SequenceFeature sf2 = addFeature(fs, 1, 15);
92 SequenceFeature sf3 = addFeature(fs, 20, 30);
93 SequenceFeature sf4 = addFeature(fs, 40, 100);
94 SequenceFeature sf5 = addFeature(fs, 60, 100);
95 SequenceFeature sf6 = addFeature(fs, 70, 70);
97 List<SequenceFeature> overlaps = fs.findOverlappingFeatures(200, 200);
98 assertTrue(overlaps.isEmpty());
100 overlaps = fs.findOverlappingFeatures(1, 9);
101 assertEquals(overlaps.size(), 1);
102 assertTrue(overlaps.contains(sf2));
104 overlaps = fs.findOverlappingFeatures(5, 18);
105 assertEquals(overlaps.size(), 2);
106 assertTrue(overlaps.contains(sf1));
107 assertTrue(overlaps.contains(sf2));
109 overlaps = fs.findOverlappingFeatures(30, 40);
110 assertEquals(overlaps.size(), 3);
111 assertTrue(overlaps.contains(sf1));
112 assertTrue(overlaps.contains(sf3));
113 assertTrue(overlaps.contains(sf4));
115 overlaps = fs.findOverlappingFeatures(80, 90);
116 assertEquals(overlaps.size(), 2);
117 assertTrue(overlaps.contains(sf4));
118 assertTrue(overlaps.contains(sf5));
120 overlaps = fs.findOverlappingFeatures(68, 70);
121 assertEquals(overlaps.size(), 3);
122 assertTrue(overlaps.contains(sf4));
123 assertTrue(overlaps.contains(sf5));
124 assertTrue(overlaps.contains(sf6));
128 * Helper method to add a feature of no particular type
135 SequenceFeature addFeature(FeatureStore fs, int from, int to)
137 SequenceFeature sf1 = new SequenceFeature("", "", from, to, Float.NaN,
143 @Test(groups = "Functional")
144 public void testFindFeatures_contactFeatures()
146 FeatureStore fs = new FeatureStore();
148 SequenceFeature sf = new SequenceFeature("disulphide bond", "bond", 10,
149 20, Float.NaN, null);
153 * neither contact point in range
155 List<SequenceFeature> overlaps = fs.findOverlappingFeatures(1, 9);
156 assertTrue(overlaps.isEmpty());
159 * neither contact point in range
161 overlaps = fs.findOverlappingFeatures(11, 19);
162 assertTrue(overlaps.isEmpty());
165 * first contact point in range
167 overlaps = fs.findOverlappingFeatures(5, 15);
168 assertEquals(overlaps.size(), 1);
169 assertTrue(overlaps.contains(sf));
172 * second contact point in range
174 overlaps = fs.findOverlappingFeatures(15, 25);
175 assertEquals(overlaps.size(), 1);
176 assertTrue(overlaps.contains(sf));
179 * both contact points in range
181 overlaps = fs.findOverlappingFeatures(5, 25);
182 assertEquals(overlaps.size(), 1);
183 assertTrue(overlaps.contains(sf));
187 * Tests for the method that returns false for an attempt to add a feature
188 * that would enclose, or be enclosed by, another feature
190 @Test(groups = "Functional")
191 public void testAddNonNestedFeature()
193 FeatureStore fs = new FeatureStore();
195 String type = "Domain";
196 SequenceFeature sf1 = new SequenceFeature(type, type, 10, 20,
198 assertTrue(fs.addNonNestedFeature(sf1));
200 // co-located feature is ok
201 SequenceFeature sf2 = new SequenceFeature(type, type, 10, 20,
203 assertTrue(fs.addNonNestedFeature(sf2));
205 // overlap left is ok
206 SequenceFeature sf3 = new SequenceFeature(type, type, 5, 15, Float.NaN,
208 assertTrue(fs.addNonNestedFeature(sf3));
210 // overlap right is ok
211 SequenceFeature sf4 = new SequenceFeature(type, type, 15, 25,
213 assertTrue(fs.addNonNestedFeature(sf4));
215 // add enclosing feature is not ok
216 SequenceFeature sf5 = new SequenceFeature(type, type, 10, 21,
218 assertFalse(fs.addNonNestedFeature(sf5));
219 SequenceFeature sf6 = new SequenceFeature(type, type, 4, 15, Float.NaN,
221 assertFalse(fs.addNonNestedFeature(sf6));
222 SequenceFeature sf7 = new SequenceFeature(type, type, 1, 50, Float.NaN,
224 assertFalse(fs.addNonNestedFeature(sf7));
226 // add enclosed feature is not ok
227 SequenceFeature sf8 = new SequenceFeature(type, type, 10, 19,
229 assertFalse(fs.addNonNestedFeature(sf8));
230 SequenceFeature sf9 = new SequenceFeature(type, type, 16, 25,
232 assertFalse(fs.addNonNestedFeature(sf9));
233 SequenceFeature sf10 = new SequenceFeature(type, type, 7, 7, Float.NaN,
235 assertFalse(fs.addNonNestedFeature(sf10));
238 @Test(groups = "Functional")
239 public void testGetFeatures()
241 FeatureStore store = new FeatureStore();
242 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
244 store.addFeature(sf1);
245 // same range, different description
246 SequenceFeature sf2 = new SequenceFeature("Metal", "desc2", 10, 20,
248 store.addFeature(sf2);
249 // discontiguous range
250 SequenceFeature sf3 = new SequenceFeature("Metal", "desc", 30, 40,
252 store.addFeature(sf3);
254 SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 15, 35,
256 store.addFeature(sf4);
258 SequenceFeature sf5 = new SequenceFeature("Metal", "desc", 5, 50,
260 store.addFeature(sf5);
261 // non-positional feature
262 SequenceFeature sf6 = new SequenceFeature("Metal", "desc", 0, 0,
264 store.addFeature(sf6);
266 SequenceFeature sf7 = new SequenceFeature("Disulphide bond", "desc",
267 18, 45, Float.NaN, null);
268 store.addFeature(sf7);
270 List<SequenceFeature> features = store.getFeatures();
271 assertEquals(features.size(), 7);
272 assertTrue(features.contains(sf1));
273 assertTrue(features.contains(sf2));
274 assertTrue(features.contains(sf3));
275 assertTrue(features.contains(sf4));
276 assertTrue(features.contains(sf5));
277 assertTrue(features.contains(sf6));
278 assertTrue(features.contains(sf7));
281 @Test(groups = "Functional")
282 public void testDelete()
284 FeatureStore store = new FeatureStore();
285 SequenceFeature sf1 = addFeature(store, 10, 20);
286 assertTrue(store.getFeatures().contains(sf1));
291 assertTrue(store.delete(sf1));
292 assertTrue(store.getFeatures().isEmpty());
295 * non-positional feature deletion
297 SequenceFeature sf2 = addFeature(store, 0, 0);
298 assertTrue(store.getFeatures().contains(sf2));
299 assertTrue(store.delete(sf2));
300 assertTrue(store.getFeatures().isEmpty());
303 * contact feature deletion
305 SequenceFeature sf3 = new SequenceFeature("", "Disulphide Bond", 11,
306 23, Float.NaN, null);
307 store.addFeature(sf3);
308 assertEquals(store.getFeatures().size(), 1);
309 assertTrue(store.getFeatures().contains(sf3));
310 assertTrue(store.delete(sf3));
311 assertTrue(store.getFeatures().isEmpty());
314 * nested feature deletion
316 SequenceFeature sf4 = addFeature(store, 20, 30);
317 SequenceFeature sf5 = addFeature(store, 22, 26); // to NCList
318 SequenceFeature sf6 = addFeature(store, 23, 24); // child of sf5
319 SequenceFeature sf7 = addFeature(store, 25, 25); // sibling of sf6
320 SequenceFeature sf8 = addFeature(store, 24, 24); // child of sf6
321 SequenceFeature sf9 = addFeature(store, 23, 23); // child of sf6
322 assertEquals(store.getFeatures().size(), 6);
324 // delete a node with children - they take its place
325 assertTrue(store.delete(sf6)); // sf8, sf9 should become children of sf5
326 assertEquals(store.getFeatures().size(), 5);
327 assertFalse(store.getFeatures().contains(sf6));
329 // delete a node with no children
330 assertTrue(store.delete(sf7));
331 assertEquals(store.getFeatures().size(), 4);
332 assertFalse(store.getFeatures().contains(sf7));
334 // delete root of NCList
335 assertTrue(store.delete(sf5));
336 assertEquals(store.getFeatures().size(), 3);
337 assertFalse(store.getFeatures().contains(sf5));
339 // continue the killing fields
340 assertTrue(store.delete(sf4));
341 assertEquals(store.getFeatures().size(), 2);
342 assertFalse(store.getFeatures().contains(sf4));
344 assertTrue(store.delete(sf9));
345 assertEquals(store.getFeatures().size(), 1);
346 assertFalse(store.getFeatures().contains(sf9));
348 assertTrue(store.delete(sf8));
349 assertTrue(store.getFeatures().isEmpty());
352 @Test(groups = "Functional")
353 public void testAddFeature()
355 FeatureStore fs = new FeatureStore();
357 SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20,
359 SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 20,
362 assertTrue(fs.addFeature(sf1));
365 * re-adding the same or an identical feature should fail
367 assertFalse(fs.addFeature(sf1));
368 assertFalse(fs.addFeature(sf2));
371 @Test(groups = "Functional")
372 public void testIsEmpty()
374 FeatureStore fs = new FeatureStore();
375 assertTrue(fs.isEmpty());
380 SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20,
383 assertFalse(fs.isEmpty());
385 assertTrue(fs.isEmpty());
388 * non-positional feature
390 sf1 = new SequenceFeature("Cath", "", 0, 0, Float.NaN, null);
392 assertFalse(fs.isEmpty());
394 assertTrue(fs.isEmpty());
399 sf1 = new SequenceFeature("Disulfide bond", "", 19, 49, Float.NaN, null);
401 assertFalse(fs.isEmpty());
403 assertTrue(fs.isEmpty());
406 * sf2, sf3 added as nested features
408 sf1 = new SequenceFeature("Cath", "", 19, 49, Float.NaN, null);
409 SequenceFeature sf2 = new SequenceFeature("Cath", "", 20, 40,
411 SequenceFeature sf3 = new SequenceFeature("Cath", "", 25, 35,
416 assertTrue(fs.delete(sf1));
417 // FeatureStore should now only contain features in the NCList
418 assertEquals(fs.nonNestedFeatures.size(), 0);
419 assertEquals(fs.nestedFeatures.size(), 2);
420 assertFalse(fs.isEmpty());
421 assertTrue(fs.delete(sf2));
422 assertFalse(fs.isEmpty());
423 assertTrue(fs.delete(sf3));
424 assertTrue(fs.isEmpty()); // all gone
427 @Test(groups = "Functional")
428 public void testGetFeatureGroups()
430 FeatureStore fs = new FeatureStore();
431 assertTrue(fs.getFeatureGroups().isEmpty());
433 SequenceFeature sf1 = new SequenceFeature("Cath", "desc", 10, 20, 1f, "group1");
435 Set<String> groups = fs.getFeatureGroups();
436 assertEquals(groups.size(), 1);
437 assertTrue(groups.contains("group1"));
440 * add another feature of the same group, delete one, delete both
442 SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 20, 30, 1f, "group1");
444 groups = fs.getFeatureGroups();
445 assertEquals(groups.size(), 1);
446 assertTrue(groups.contains("group1"));
448 groups = fs.getFeatureGroups();
449 assertEquals(groups.size(), 1);
450 assertTrue(groups.contains("group1"));
452 groups = fs.getFeatureGroups();
453 assertTrue(fs.getFeatureGroups().isEmpty());
455 SequenceFeature sf3 = new SequenceFeature("Cath", "desc", 20, 30, 1f, "group2");
457 SequenceFeature sf4 = new SequenceFeature("Cath", "desc", 20, 30, 1f, "Group2");
459 SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 20, 30, 1f, null);
461 groups = fs.getFeatureGroups();
462 assertEquals(groups.size(), 3);
463 assertTrue(groups.contains("group2"));
464 assertTrue(groups.contains("Group2")); // case sensitive
465 assertTrue(groups.contains(null)); // null allowed
468 groups = fs.getFeatureGroups();
469 assertEquals(groups.size(), 2);
470 assertFalse(groups.contains("group2"));
472 groups = fs.getFeatureGroups();
473 assertEquals(groups.size(), 1);
474 assertFalse(groups.contains("Group2"));
476 groups = fs.getFeatureGroups();
477 assertTrue(groups.isEmpty());