JAL-3383 JAL-3397 JAL-3253-applet IntervalStore options
[jalview.git] / test / jalview / datamodel / features / FeatureStoreNoNCTest.java
1 package jalview.datamodel.features;
2
3 import static org.testng.Assert.assertEquals;
4 import static org.testng.Assert.assertFalse;
5 import static org.testng.Assert.assertSame;
6 import static org.testng.Assert.assertTrue;
7
8 import jalview.datamodel.SequenceFeature;
9
10 import java.util.ArrayList;
11 import java.util.List;
12 import java.util.Set;
13
14 import org.testng.annotations.Test;
15
16 public class FeatureStoreNoNCTest
17 {
18
19   private FeatureStoreI newFeatureStore()
20   {
21     return new FeatureStoreImpl(false);
22   }
23
24   @Test(groups = "Functional")
25   public void testFindFeatures_nonNested()
26   {
27     FeatureStoreI fs = newFeatureStore();
28     fs.addFeature(new SequenceFeature("", "", 10, 20, Float.NaN,
29             null));
30     // same range different description
31     fs.addFeature(new SequenceFeature("", "desc", 10, 20, Float.NaN, null));
32     fs.addFeature(new SequenceFeature("", "", 15, 25, Float.NaN, null));
33     fs.addFeature(new SequenceFeature("", "", 20, 35, Float.NaN, null));
34
35     List<SequenceFeature> overlaps = fs.findOverlappingFeatures(1, 9);
36     assertTrue(overlaps.isEmpty());
37
38     overlaps = fs.findOverlappingFeatures(8, 10);
39     assertEquals(overlaps.size(), 2);
40     assertEquals(overlaps.get(0).getEnd(), 20);
41     assertEquals(overlaps.get(1).getEnd(), 20);
42
43     overlaps = fs.findOverlappingFeatures(12, 16);
44     assertEquals(overlaps.size(), 3);
45     assertEquals(overlaps.get(0).getEnd(), 20);
46     assertEquals(overlaps.get(1).getEnd(), 20);
47     assertEquals(overlaps.get(2).getEnd(), 25);
48
49     overlaps = fs.findOverlappingFeatures(33, 33);
50     assertEquals(overlaps.size(), 1);
51     assertEquals(overlaps.get(0).getEnd(), 35);
52   }
53
54   @Test(groups = "Functional")
55   public void testFindFeatures_nested()
56   {
57     FeatureStoreI fs = newFeatureStore();
58     SequenceFeature sf1 = addFeature(fs, 10, 50);
59     SequenceFeature sf2 = addFeature(fs, 10, 40);
60     SequenceFeature sf3 = addFeature(fs, 20, 30);
61     // fudge feature at same location but different group (so is added)
62     SequenceFeature sf4 = new SequenceFeature("", "", 20, 30, Float.NaN,
63             "different group");
64     fs.addFeature(sf4);
65     SequenceFeature sf5 = addFeature(fs, 35, 36);
66
67     List<SequenceFeature> overlaps = fs.findOverlappingFeatures(1, 9);
68     assertTrue(overlaps.isEmpty());
69
70     overlaps = fs.findOverlappingFeatures(10, 15);
71     assertEquals(overlaps.size(), 2);
72     assertTrue(overlaps.contains(sf1));
73     assertTrue(overlaps.contains(sf2));
74
75     overlaps = fs.findOverlappingFeatures(45, 60);
76     assertEquals(overlaps.size(), 1);
77     assertTrue(overlaps.contains(sf1));
78
79     overlaps = fs.findOverlappingFeatures(32, 38);
80     assertEquals(overlaps.size(), 3);
81     assertTrue(overlaps.contains(sf1));
82     assertTrue(overlaps.contains(sf2));
83     assertTrue(overlaps.contains(sf5));
84
85     overlaps = fs.findOverlappingFeatures(15, 25);
86     assertEquals(overlaps.size(), 4);
87     assertTrue(overlaps.contains(sf1));
88     assertTrue(overlaps.contains(sf2));
89     assertTrue(overlaps.contains(sf3));
90     assertTrue(overlaps.contains(sf4));
91   }
92
93   @Test(groups = "Functional")
94   public void testFindFeatures_mixed()
95   {
96     FeatureStoreI fs = newFeatureStore();
97     SequenceFeature sf1 = addFeature(fs, 10, 50);
98     SequenceFeature sf2 = addFeature(fs, 1, 15);
99     SequenceFeature sf3 = addFeature(fs, 20, 30);
100     SequenceFeature sf4 = addFeature(fs, 40, 100);
101     SequenceFeature sf5 = addFeature(fs, 60, 100);
102     SequenceFeature sf6 = addFeature(fs, 70, 70);
103
104     List<SequenceFeature> overlaps = fs.findOverlappingFeatures(200, 200);
105     assertTrue(overlaps.isEmpty());
106
107     overlaps = fs.findOverlappingFeatures(1, 9);
108     assertEquals(overlaps.size(), 1);
109     assertTrue(overlaps.contains(sf2));
110
111     overlaps = fs.findOverlappingFeatures(5, 18);
112     assertEquals(overlaps.size(), 2);
113     assertTrue(overlaps.contains(sf1));
114     assertTrue(overlaps.contains(sf2));
115
116     overlaps = fs.findOverlappingFeatures(30, 40);
117     assertEquals(overlaps.size(), 3);
118     assertTrue(overlaps.contains(sf1));
119     assertTrue(overlaps.contains(sf3));
120     assertTrue(overlaps.contains(sf4));
121
122     overlaps = fs.findOverlappingFeatures(80, 90);
123     assertEquals(overlaps.size(), 2);
124     assertTrue(overlaps.contains(sf4));
125     assertTrue(overlaps.contains(sf5));
126
127     overlaps = fs.findOverlappingFeatures(68, 70);
128     assertEquals(overlaps.size(), 3);
129     assertTrue(overlaps.contains(sf4));
130     assertTrue(overlaps.contains(sf5));
131     assertTrue(overlaps.contains(sf6));
132   }
133
134   /**
135    * Helper method to add a feature of no particular type
136    * 
137    * @param fs
138    * @param from
139    * @param to
140    * @return
141    */
142   SequenceFeature addFeature(FeatureStoreI fs, int from, int to)
143   {
144     SequenceFeature sf1 = new SequenceFeature("", "", from, to, Float.NaN,
145             null);
146     fs.addFeature(sf1);
147     return sf1;
148   }
149
150   @Test(groups = "Functional")
151   public void testFindFeatures_contactFeatures()
152   {
153     FeatureStoreI fs = newFeatureStore();
154
155     SequenceFeature sf = new SequenceFeature("disulphide bond", "bond", 10,
156             20, Float.NaN, null);
157     fs.addFeature(sf);
158
159     /*
160      * neither contact point in range
161      */
162     List<SequenceFeature> overlaps = fs.findOverlappingFeatures(1, 9);
163     assertTrue(overlaps.isEmpty());
164
165     /*
166      * neither contact point in range
167      */
168     overlaps = fs.findOverlappingFeatures(11, 19);
169     assertTrue(overlaps.isEmpty());
170
171     /*
172      * first contact point in range
173      */
174     overlaps = fs.findOverlappingFeatures(5, 15);
175     assertEquals(overlaps.size(), 1);
176     assertTrue(overlaps.contains(sf));
177
178     /*
179      * second contact point in range
180      */
181     overlaps = fs.findOverlappingFeatures(15, 25);
182     assertEquals(overlaps.size(), 1);
183     assertTrue(overlaps.contains(sf));
184
185     /*
186      * both contact points in range
187      */
188     overlaps = fs.findOverlappingFeatures(5, 25);
189     assertEquals(overlaps.size(), 1);
190     assertTrue(overlaps.contains(sf));
191   }
192
193   @Test(groups = "Functional")
194   public void testGetPositionalFeatures()
195   {
196     FeatureStoreI store = newFeatureStore();
197     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
198             Float.NaN, null);
199     store.addFeature(sf1);
200     // same range, different description
201     SequenceFeature sf2 = new SequenceFeature("Metal", "desc2", 10, 20,
202             Float.NaN, null);
203     store.addFeature(sf2);
204     // discontiguous range
205     SequenceFeature sf3 = new SequenceFeature("Metal", "desc", 30, 40,
206             Float.NaN, null);
207     store.addFeature(sf3);
208     // overlapping range
209     SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 15, 35,
210             Float.NaN, null);
211     store.addFeature(sf4);
212     // enclosing range
213     SequenceFeature sf5 = new SequenceFeature("Metal", "desc", 5, 50,
214             Float.NaN, null);
215     store.addFeature(sf5);
216     // non-positional feature
217     SequenceFeature sf6 = new SequenceFeature("Metal", "desc", 0, 0,
218             Float.NaN, null);
219     store.addFeature(sf6);
220     // contact feature
221     SequenceFeature sf7 = new SequenceFeature("Disulphide bond", "desc",
222             18, 45, Float.NaN, null);
223     store.addFeature(sf7);
224
225     List<SequenceFeature> features = store.getPositionalFeatures();
226     assertEquals(features.size(), 6);
227     assertTrue(features.contains(sf1));
228     assertTrue(features.contains(sf2));
229     assertTrue(features.contains(sf3));
230     assertTrue(features.contains(sf4));
231     assertTrue(features.contains(sf5));
232     assertFalse(features.contains(sf6));
233     assertTrue(features.contains(sf7));
234
235     features = store.getNonPositionalFeatures();
236     assertEquals(features.size(), 1);
237     assertTrue(features.contains(sf6));
238   }
239
240   @Test(groups = "Functional")
241   public void testDelete()
242   {
243     FeatureStoreI store = newFeatureStore();
244     SequenceFeature sf1 = addFeature(store, 10, 20);
245     assertTrue(store.getPositionalFeatures().contains(sf1));
246
247     /*
248      * simple deletion
249      */
250     assertTrue(store.delete(sf1));
251     assertTrue(store.getPositionalFeatures().isEmpty());
252
253     /*
254      * non-positional feature deletion
255      */
256     SequenceFeature sf2 = addFeature(store, 0, 0);
257     assertFalse(store.getPositionalFeatures().contains(sf2));
258     assertTrue(store.getNonPositionalFeatures().contains(sf2));
259     assertTrue(store.delete(sf2));
260     assertTrue(store.getNonPositionalFeatures().isEmpty());
261
262     /*
263      * contact feature deletion
264      */
265     SequenceFeature sf3 = new SequenceFeature("", "Disulphide Bond", 11,
266             23, Float.NaN, null);
267     store.addFeature(sf3);
268     assertEquals(store.getPositionalFeatures().size(), 1);
269     assertTrue(store.getPositionalFeatures().contains(sf3));
270     assertTrue(store.delete(sf3));
271     assertTrue(store.getPositionalFeatures().isEmpty());
272
273     /*
274      * nested feature deletion
275      */
276     SequenceFeature sf4 = addFeature(store, 20, 30);
277     SequenceFeature sf5 = addFeature(store, 22, 26); // to NCList
278     SequenceFeature sf6 = addFeature(store, 23, 24); // child of sf5
279     SequenceFeature sf7 = addFeature(store, 25, 25); // sibling of sf6
280     SequenceFeature sf8 = addFeature(store, 24, 24); // child of sf6
281     SequenceFeature sf9 = addFeature(store, 23, 23); // child of sf6
282
283     // SequenceFeature sf4 = addFeature(store, 20, 30);
284     //// SequenceFeature sf5 = addFeature(store, 22, 26);
285     ////// SequenceFeature sf6 = addFeature(store, 23, 24); // child of sf5
286     //////// SequenceFeature sf9 = addFeature(store, 23, 23); // child of sf6
287     //////// SequenceFeature sf8 = addFeature(store, 24, 24); // child of sf6
288     ////// SequenceFeature sf7 = addFeature(store, 25, 25); // child of sf5
289     //
290     assertEquals(store.getPositionalFeatures().size(), 6);
291
292     // delete a node with children - they take its place
293     assertTrue(store.delete(sf6)); // sf8, sf9 should become children of sf5
294     assertEquals(store.getPositionalFeatures().size(), 5);
295     assertFalse(store.getPositionalFeatures().contains(sf6));
296
297     // delete a node with no children
298     assertTrue(store.delete(sf7));
299     assertEquals(store.getPositionalFeatures().size(), 4);
300     assertFalse(store.getPositionalFeatures().contains(sf7));
301
302     // delete root of NCList
303     assertTrue(store.delete(sf5));
304     assertEquals(store.getPositionalFeatures().size(), 3);
305     assertFalse(store.getPositionalFeatures().contains(sf5));
306
307     // continue the killing fields
308     assertTrue(store.delete(sf4));
309     assertEquals(store.getPositionalFeatures().size(), 2);
310     assertFalse(store.getPositionalFeatures().contains(sf4));
311
312     assertTrue(store.delete(sf9));
313     assertEquals(store.getPositionalFeatures().size(), 1);
314     assertFalse(store.getPositionalFeatures().contains(sf9));
315
316     assertTrue(store.delete(sf8));
317     assertTrue(store.getPositionalFeatures().isEmpty());
318   }
319
320   @Test(groups = "Functional")
321   public void testAddFeature()
322   {
323     FeatureStoreI fs = newFeatureStore();
324
325     SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20,
326             Float.NaN, null);
327     SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 20,
328             Float.NaN, null);
329
330     assertTrue(fs.addFeature(sf1));
331     assertEquals(fs.getFeatureCount(true), 1); // positional
332     assertEquals(fs.getFeatureCount(false), 0); // non-positional
333
334     /*
335      * re-adding the same or an identical feature should fail
336      */
337     assertFalse(fs.addFeature(sf1));
338     assertEquals(fs.getFeatureCount(true), 1);
339     assertFalse(fs.addFeature(sf2));
340     assertEquals(fs.getFeatureCount(true), 1);
341
342     /*
343      * add non-positional
344      */
345     SequenceFeature sf3 = new SequenceFeature("Cath", "", 0, 0, Float.NaN,
346             null);
347     assertTrue(fs.addFeature(sf3));
348     assertEquals(fs.getFeatureCount(true), 1); // positional
349     assertEquals(fs.getFeatureCount(false), 1); // non-positional
350     SequenceFeature sf4 = new SequenceFeature("Cath", "", 0, 0, Float.NaN,
351             null);
352     assertFalse(fs.addFeature(sf4)); // already stored
353     assertEquals(fs.getFeatureCount(true), 1); // positional
354     assertEquals(fs.getFeatureCount(false), 1); // non-positional
355
356     /*
357      * add contact
358      */
359     SequenceFeature sf5 = new SequenceFeature("Disulfide bond", "", 10, 20,
360             Float.NaN, null);
361     assertTrue(fs.addFeature(sf5));
362     assertEquals(fs.getFeatureCount(true), 2); // positional - add 1 for contact
363     assertEquals(fs.getFeatureCount(false), 1); // non-positional
364     SequenceFeature sf6 = new SequenceFeature("Disulfide bond", "", 10, 20,
365             Float.NaN, null);
366     assertFalse(fs.addFeature(sf6)); // already stored
367     assertEquals(fs.getFeatureCount(true), 2); // no change
368     assertEquals(fs.getFeatureCount(false), 1); // no change
369   }
370
371   @Test(groups = "Functional")
372   public void testIsEmpty()
373   {
374     FeatureStoreI fs = newFeatureStore();
375     assertTrue(fs.isEmpty());
376     assertEquals(fs.getFeatureCount(true), 0);
377
378     /*
379      * non-nested feature
380      */
381     SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20,
382             Float.NaN, null);
383     fs.addFeature(sf1);
384     assertFalse(fs.isEmpty());
385     assertEquals(fs.getFeatureCount(true), 1);
386     fs.delete(sf1);
387     assertTrue(fs.isEmpty());
388     assertEquals(fs.getFeatureCount(true), 0);
389
390     /*
391      * non-positional feature
392      */
393     sf1 = new SequenceFeature("Cath", "", 0, 0, Float.NaN, null);
394     fs.addFeature(sf1);
395     assertFalse(fs.isEmpty());
396     assertEquals(fs.getFeatureCount(false), 1); // non-positional
397     assertEquals(fs.getFeatureCount(true), 0); // positional
398     fs.delete(sf1);
399     assertTrue(fs.isEmpty());
400     assertEquals(fs.getFeatureCount(false), 0);
401
402     /*
403      * contact feature
404      */
405     sf1 = new SequenceFeature("Disulfide bond", "", 19, 49, Float.NaN, null);
406     fs.addFeature(sf1);
407     assertFalse(fs.isEmpty());
408     assertEquals(fs.getFeatureCount(true), 1);
409     fs.delete(sf1);
410     assertTrue(fs.isEmpty());
411     assertEquals(fs.getFeatureCount(true), 0);
412
413     /*
414      * sf2, sf3 added as nested features
415      */
416     sf1 = new SequenceFeature("Cath", "", 19, 49, Float.NaN, null);
417     SequenceFeature sf2 = new SequenceFeature("Cath", "", 20, 40,
418             Float.NaN, null);
419     SequenceFeature sf3 = new SequenceFeature("Cath", "", 25, 35,
420             Float.NaN, null);
421     fs.addFeature(sf1);
422     fs.addFeature(sf2);
423     fs.addFeature(sf3);
424     assertEquals(fs.getFeatureCount(true), 3);
425     assertTrue(fs.delete(sf1));
426     assertEquals(fs.getFeatureCount(true), 2);
427     assertEquals(fs.getFeatures().size(), 2);
428     assertFalse(fs.isEmpty());
429     assertTrue(fs.delete(sf2));
430     assertEquals(fs.getFeatureCount(true), 1);
431     assertFalse(fs.isEmpty());
432     assertTrue(fs.delete(sf3));
433     assertEquals(fs.getFeatureCount(true), 0);
434     assertTrue(fs.isEmpty()); // all gone
435   }
436
437   @Test(groups = "Functional")
438   public void testGetFeatureGroups()
439   {
440     FeatureStoreI fs = newFeatureStore();
441     assertTrue(fs.getFeatureGroups(true).isEmpty());
442     assertTrue(fs.getFeatureGroups(false).isEmpty());
443
444     SequenceFeature sf1 = new SequenceFeature("Cath", "desc", 10, 20, 1f, "group1");
445     fs.addFeature(sf1);
446     Set<String> groups = fs.getFeatureGroups(true);
447     assertEquals(groups.size(), 1);
448     assertTrue(groups.contains("group1"));
449
450     /*
451      * add another feature of the same group, delete one, delete both
452      */
453     SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 20, 30, 1f, "group1");
454     fs.addFeature(sf2);
455     groups = fs.getFeatureGroups(true);
456     assertEquals(groups.size(), 1);
457     assertTrue(groups.contains("group1"));
458     fs.delete(sf2);
459     groups = fs.getFeatureGroups(true);
460     assertEquals(groups.size(), 1);
461     assertTrue(groups.contains("group1"));
462     fs.delete(sf1);
463     groups = fs.getFeatureGroups(true);
464     assertTrue(fs.getFeatureGroups(true).isEmpty());
465
466     SequenceFeature sf3 = new SequenceFeature("Cath", "desc", 20, 30, 1f, "group2");
467     fs.addFeature(sf3);
468     SequenceFeature sf4 = new SequenceFeature("Cath", "desc", 20, 30, 1f, "Group2");
469     fs.addFeature(sf4);
470     SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 20, 30, 1f, null);
471     fs.addFeature(sf5);
472     groups = fs.getFeatureGroups(true);
473     assertEquals(groups.size(), 3);
474     assertTrue(groups.contains("group2"));
475     assertTrue(groups.contains("Group2")); // case sensitive
476     assertTrue(groups.contains(null)); // null allowed
477     assertTrue(fs.getFeatureGroups(false).isEmpty()); // non-positional
478
479     fs.delete(sf3);
480     groups = fs.getFeatureGroups(true);
481     assertEquals(groups.size(), 2);
482     assertFalse(groups.contains("group2"));
483     fs.delete(sf4);
484     groups = fs.getFeatureGroups(true);
485     assertEquals(groups.size(), 1);
486     assertFalse(groups.contains("Group2"));
487     fs.delete(sf5);
488     groups = fs.getFeatureGroups(true);
489     assertTrue(groups.isEmpty());
490
491     /*
492      * add non-positional feature
493      */
494     SequenceFeature sf6 = new SequenceFeature("Cath", "desc", 0, 0, 1f,
495             "CathGroup");
496     fs.addFeature(sf6);
497     groups = fs.getFeatureGroups(false);
498     assertEquals(groups.size(), 1);
499     assertTrue(groups.contains("CathGroup"));
500     assertTrue(fs.delete(sf6));
501     assertTrue(fs.getFeatureGroups(false).isEmpty());
502   }
503
504   @Test(groups = "Functional")
505   public void testGetTotalFeatureLength()
506   {
507     FeatureStoreI fs = newFeatureStore();
508     assertEquals(fs.getTotalFeatureLength(), 0);
509
510     addFeature(fs, 10, 20); // 11
511     assertEquals(fs.getTotalFeatureLength(), 11);
512     addFeature(fs, 17, 37); // 21
513     SequenceFeature sf1 = addFeature(fs, 14, 74); // 61
514     assertEquals(fs.getTotalFeatureLength(), 93);
515
516     // non-positional features don't count
517     SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 0, 0, 1f,
518             "group1");
519     fs.addFeature(sf2);
520     assertEquals(fs.getTotalFeatureLength(), 93);
521
522     // contact features count 1
523     SequenceFeature sf3 = new SequenceFeature("disulphide bond", "desc",
524             15, 35, 1f, "group1");
525     fs.addFeature(sf3);
526     assertEquals(fs.getTotalFeatureLength(), 94);
527
528     assertTrue(fs.delete(sf1));
529     assertEquals(fs.getTotalFeatureLength(), 33);
530     assertFalse(fs.delete(sf1));
531     assertEquals(fs.getTotalFeatureLength(), 33);
532     assertTrue(fs.delete(sf2));
533     assertEquals(fs.getTotalFeatureLength(), 33);
534     assertTrue(fs.delete(sf3));
535     assertEquals(fs.getTotalFeatureLength(), 32);
536   }
537
538   @Test(groups = "Functional")
539   public void testGetFeatureLength()
540   {
541     /*
542      * positional feature
543      */
544     SequenceFeature sf1 = new SequenceFeature("Cath", "desc", 10, 20, 1f, "group1");
545     assertEquals(FeatureStore.getFeatureLength(sf1), 11);
546   
547     /*
548      * non-positional feature
549      */
550     SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 0, 0, 1f,
551             "CathGroup");
552     assertEquals(FeatureStore.getFeatureLength(sf2), 0);
553
554     /*
555      * contact feature counts 1
556      */
557     SequenceFeature sf3 = new SequenceFeature("Disulphide Bond", "desc",
558             14, 28, 1f, "AGroup");
559     assertEquals(FeatureStore.getFeatureLength(sf3), 1);
560   }
561
562   @Test(groups = "Functional")
563   public void testMin()
564   {
565     assertEquals(FeatureStore.min(Float.NaN, Float.NaN), Float.NaN);
566     assertEquals(FeatureStore.min(Float.NaN, 2f), 2f);
567     assertEquals(FeatureStore.min(-2f, Float.NaN), -2f);
568     assertEquals(FeatureStore.min(2f, -3f), -3f);
569   }
570
571   @Test(groups = "Functional")
572   public void testMax()
573   {
574     assertEquals(FeatureStore.max(Float.NaN, Float.NaN), Float.NaN);
575     assertEquals(FeatureStore.max(Float.NaN, 2f), 2f);
576     assertEquals(FeatureStore.max(-2f, Float.NaN), -2f);
577     assertEquals(FeatureStore.max(2f, -3f), 2f);
578   }
579
580   @Test(groups = "Functional")
581   public void testGetMinimumScore_getMaximumScore()
582   {
583     FeatureStoreI fs = newFeatureStore();
584     assertEquals(fs.getMinimumScore(true), Float.NaN); // positional
585     assertEquals(fs.getMaximumScore(true), Float.NaN);
586     assertEquals(fs.getMinimumScore(false), Float.NaN); // non-positional
587     assertEquals(fs.getMaximumScore(false), Float.NaN);
588
589     // add features with no score
590     SequenceFeature sf1 = new SequenceFeature("type", "desc", 0, 0,
591             Float.NaN, "group");
592     fs.addFeature(sf1);
593     SequenceFeature sf2 = new SequenceFeature("type", "desc", 10, 20,
594             Float.NaN, "group");
595     fs.addFeature(sf2);
596     assertEquals(fs.getMinimumScore(true), Float.NaN);
597     assertEquals(fs.getMaximumScore(true), Float.NaN);
598     assertEquals(fs.getMinimumScore(false), Float.NaN);
599     assertEquals(fs.getMaximumScore(false), Float.NaN);
600
601     // add positional features with score
602     SequenceFeature sf3 = new SequenceFeature("type", "desc", 10, 20, 1f,
603             "group");
604     fs.addFeature(sf3);
605     SequenceFeature sf4 = new SequenceFeature("type", "desc", 12, 16, 4f,
606             "group");
607     fs.addFeature(sf4);
608     assertEquals(fs.getMinimumScore(true), 1f);
609     assertEquals(fs.getMaximumScore(true), 4f);
610     assertEquals(fs.getMinimumScore(false), Float.NaN);
611     assertEquals(fs.getMaximumScore(false), Float.NaN);
612
613     // add non-positional features with score
614     SequenceFeature sf5 = new SequenceFeature("type", "desc", 0, 0, 11f,
615             "group");
616     fs.addFeature(sf5);
617     SequenceFeature sf6 = new SequenceFeature("type", "desc", 0, 0, -7f,
618             "group");
619     fs.addFeature(sf6);
620     assertEquals(fs.getMinimumScore(true), 1f);
621     assertEquals(fs.getMaximumScore(true), 4f);
622     assertEquals(fs.getMinimumScore(false), -7f);
623     assertEquals(fs.getMaximumScore(false), 11f);
624
625     // delete one positional and one non-positional
626     // min-max should be recomputed
627     assertTrue(fs.delete(sf6));
628     assertTrue(fs.delete(sf3));
629     assertEquals(fs.getMinimumScore(true), 4f);
630     assertEquals(fs.getMaximumScore(true), 4f);
631     assertEquals(fs.getMinimumScore(false), 11f);
632     assertEquals(fs.getMaximumScore(false), 11f);
633
634     // delete remaining features with score
635     assertTrue(fs.delete(sf4));
636     assertTrue(fs.delete(sf5));
637     assertEquals(fs.getMinimumScore(true), Float.NaN);
638     assertEquals(fs.getMaximumScore(true), Float.NaN);
639     assertEquals(fs.getMinimumScore(false), Float.NaN);
640     assertEquals(fs.getMaximumScore(false), Float.NaN);
641
642     // delete all features
643     assertTrue(fs.delete(sf1));
644     assertTrue(fs.delete(sf2));
645     assertTrue(fs.isEmpty());
646     assertEquals(fs.getMinimumScore(true), Float.NaN);
647     assertEquals(fs.getMaximumScore(true), Float.NaN);
648     assertEquals(fs.getMinimumScore(false), Float.NaN);
649     assertEquals(fs.getMaximumScore(false), Float.NaN);
650   }
651
652   @Test(groups = "Functional")
653   public void testListContains()
654   {
655     FeatureStoreI featureStore = newFeatureStore();
656     assertFalse(featureStore.listContains(null, null));
657     List<SequenceFeature> features = new ArrayList<>();
658     assertFalse(featureStore.listContains(features, null));
659
660     SequenceFeature sf1 = new SequenceFeature("type1", "desc1", 20, 30, 3f,
661             "group1");
662     assertFalse(featureStore.listContains(null, sf1));
663     assertFalse(featureStore.listContains(features, sf1));
664
665     features.add(sf1);
666     SequenceFeature sf2 = new SequenceFeature("type1", "desc1", 20, 30, 3f,
667             "group1");
668     SequenceFeature sf3 = new SequenceFeature("type1", "desc1", 20, 40, 3f,
669             "group1");
670
671     // sf2.equals(sf1) so contains should return true
672     assertTrue(featureStore.listContains(features, sf2));
673     assertFalse(featureStore.listContains(features, sf3));
674   }
675
676   @Test(groups = "Functional")
677   public void testGetFeaturesForGroup()
678   {
679     FeatureStoreI fs = newFeatureStore();
680
681     /*
682      * with no features
683      */
684     assertTrue(fs.getFeaturesForGroup(true, null).isEmpty());
685     assertTrue(fs.getFeaturesForGroup(false, null).isEmpty());
686     assertTrue(fs.getFeaturesForGroup(true, "uniprot").isEmpty());
687     assertTrue(fs.getFeaturesForGroup(false, "uniprot").isEmpty());
688
689     /*
690      * sf1: positional feature in the null group
691      */
692     SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
693             null);
694     fs.addFeature(sf1);
695     assertTrue(fs.getFeaturesForGroup(true, "uniprot").isEmpty());
696     assertTrue(fs.getFeaturesForGroup(false, "uniprot").isEmpty());
697     assertTrue(fs.getFeaturesForGroup(false, null).isEmpty());
698     List<SequenceFeature> features = fs.getFeaturesForGroup(true, null);
699     assertEquals(features.size(), 1);
700     assertTrue(features.contains(sf1));
701
702     /*
703      * sf2: non-positional feature in the null group
704      * sf3: positional feature in a non-null group
705      * sf4: non-positional feature in a non-null group
706      */
707     SequenceFeature sf2 = new SequenceFeature("Pfam", "desc", 0, 0, 0f,
708             null);
709     SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
710             "Uniprot");
711     SequenceFeature sf4 = new SequenceFeature("Pfam", "desc", 0, 0, 0f,
712             "Rfam");
713     fs.addFeature(sf2);
714     fs.addFeature(sf3);
715     fs.addFeature(sf4);
716
717     features = fs.getFeaturesForGroup(true, null);
718     assertEquals(features.size(), 1);
719     assertTrue(features.contains(sf1));
720
721     features = fs.getFeaturesForGroup(false, null);
722     assertEquals(features.size(), 1);
723     assertTrue(features.contains(sf2));
724
725     features = fs.getFeaturesForGroup(true, "Uniprot");
726     assertEquals(features.size(), 1);
727     assertTrue(features.contains(sf3));
728
729     features = fs.getFeaturesForGroup(false, "Rfam");
730     assertEquals(features.size(), 1);
731     assertTrue(features.contains(sf4));
732   }
733
734   @Test(groups = "Functional")
735   public void testShiftFeatures()
736   {
737     FeatureStoreI fs = newFeatureStore();
738     assertFalse(fs.shiftFeatures(0, 1)); // nothing to do
739
740     SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
741     fs.addFeature(sf1);
742     // nested feature:
743     SequenceFeature sf2 = new SequenceFeature("Cath", "", 8, 14, 0f, null);
744     fs.addFeature(sf2);
745     // contact feature:
746     SequenceFeature sf3 = new SequenceFeature("Disulfide bond", "", 23, 32,
747             0f, null);
748     fs.addFeature(sf3);
749     // non-positional feature:
750     SequenceFeature sf4 = new SequenceFeature("Cath", "", 0, 0, 0f, null);
751     fs.addFeature(sf4);
752
753     /*
754      * shift all features right by 5
755      */
756     assertTrue(fs.shiftFeatures(0, 5));
757
758     // non-positional features untouched:
759     List<SequenceFeature> nonPos = fs.getNonPositionalFeatures();
760     assertEquals(nonPos.size(), 1);
761     assertTrue(nonPos.contains(sf4));
762
763     // positional features are replaced
764     List<SequenceFeature> pos = fs.getPositionalFeatures();
765     assertEquals(pos.size(), 3);
766     assertFalse(pos.contains(sf1));
767     assertFalse(pos.contains(sf2));
768     assertFalse(pos.contains(sf3));
769     SequenceFeatures.sortFeatures(pos, true); // ascending start pos
770     assertEquals(pos.get(0).getBegin(), 7);
771     assertEquals(pos.get(0).getEnd(), 10);
772     assertEquals(pos.get(1).getBegin(), 13);
773     assertEquals(pos.get(1).getEnd(), 19);
774     assertEquals(pos.get(2).getBegin(), 28);
775     assertEquals(pos.get(2).getEnd(), 37);
776
777     /*
778      * now shift left by 15
779      * feature at [7-10] should be removed
780      * feature at [13-19] should become [1-4] 
781      */
782     assertTrue(fs.shiftFeatures(0, -15));
783     pos = fs.getPositionalFeatures();
784     assertEquals(pos.size(), 2);
785     SequenceFeatures.sortFeatures(pos, true);
786     assertEquals(pos.get(0).getBegin(), 1);
787     assertEquals(pos.get(0).getEnd(), 4);
788     assertEquals(pos.get(1).getBegin(), 13);
789     assertEquals(pos.get(1).getEnd(), 22);
790
791     /*
792      * shift right by 4 from position 2 onwards
793      * feature at [1-4] unchanged, feature at [13-22] shifts
794      */
795     assertTrue(fs.shiftFeatures(2, 4));
796     pos = fs.getPositionalFeatures();
797     assertEquals(pos.size(), 2);
798     SequenceFeatures.sortFeatures(pos, true);
799     assertEquals(pos.get(0).getBegin(), 1);
800     assertEquals(pos.get(0).getEnd(), 4);
801     assertEquals(pos.get(1).getBegin(), 17);
802     assertEquals(pos.get(1).getEnd(), 26);
803
804     /*
805      * shift right by 4 from position 18 onwards
806      * should be no change
807      */
808     SequenceFeature f1 = pos.get(0);
809     SequenceFeature f2 = pos.get(1);
810     assertFalse(fs.shiftFeatures(18, 4)); // no update
811     pos = fs.getPositionalFeatures();
812     assertEquals(pos.size(), 2);
813     SequenceFeatures.sortFeatures(pos, true);
814     assertSame(pos.get(0), f1);
815     assertSame(pos.get(1), f2);
816   }
817
818   @Test(groups = "Functional")
819   public void testDelete_readd()
820   {
821     /*
822      * add a feature and a nested feature
823      */
824     FeatureStoreI store = newFeatureStore();
825     SequenceFeature sf1 = addFeature(store, 10, 20);
826     // sf2 is nested in sf1 so will be stored in nestedFeatures
827     SequenceFeature sf2 = addFeature(store, 12, 14);
828     List<SequenceFeature> features = store.getPositionalFeatures();
829     assertEquals(features.size(), 2);
830     assertTrue(features.contains(sf1));
831     assertTrue(features.contains(sf2));
832     assertTrue(store.getFeatures().contains(sf1));
833     assertTrue(store.getFeatures().contains(sf2));
834   
835     /*
836      * delete the first feature
837      */
838     assertTrue(store.delete(sf1));
839     features = store.getPositionalFeatures();
840     assertFalse(features.contains(sf1));
841     assertTrue(features.contains(sf2));
842
843     /*
844      * re-add the 'nested' feature; is it now duplicated?
845      */
846     store.addFeature(sf2);
847     features = store.getPositionalFeatures();
848     assertEquals(features.size(), 1);
849     assertTrue(features.contains(sf2));
850   }
851
852   @Test(groups = "Functional")
853   public void testContains()
854   {
855     FeatureStoreI fs = newFeatureStore();
856     SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20,
857             Float.NaN, "group1");
858     SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 20,
859             Float.NaN, "group2");
860     SequenceFeature sf3 = new SequenceFeature("Cath", "", 0, 0, Float.NaN,
861             "group1");
862     SequenceFeature sf4 = new SequenceFeature("Cath", "", 0, 0, 0f,
863             "group1");
864     SequenceFeature sf5 = new SequenceFeature("Disulphide Bond", "", 5, 15,
865             Float.NaN, "group1");
866     SequenceFeature sf6 = new SequenceFeature("Disulphide Bond", "", 5, 15,
867             Float.NaN, "group2");
868
869     fs.addFeature(sf1);
870     fs.addFeature(sf3);
871     fs.addFeature(sf5);
872     assertTrue(fs.contains(sf1)); // positional feature
873     assertTrue(fs.contains(new SequenceFeature(sf1))); // identical feature
874     assertFalse(fs.contains(sf2)); // different group
875     assertTrue(fs.contains(sf3)); // non-positional
876     assertTrue(fs.contains(new SequenceFeature(sf3)));
877     assertFalse(fs.contains(sf4)); // different score
878     assertTrue(fs.contains(sf5)); // contact feature
879     assertTrue(fs.contains(new SequenceFeature(sf5)));
880     assertFalse(fs.contains(sf6)); // different group
881
882     /*
883      * add a nested feature
884      */
885     SequenceFeature sf7 = new SequenceFeature("Cath", "", 12, 16,
886             Float.NaN, "group1");
887     fs.addFeature(sf7);
888     assertTrue(fs.contains(sf7));
889     assertTrue(fs.contains(new SequenceFeature(sf7)));
890
891     /*
892      * delete the outer (enclosing, non-nested) feature
893      */
894     fs.delete(sf1);
895     assertFalse(fs.contains(sf1));
896     assertTrue(fs.contains(sf7));
897   }
898 }