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