b51075e8af9c96db0e5df3c081c5b17405467fad
[jalview.git] / test / jalview / datamodel / features / SequenceFeaturesTest.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 java.util.ArrayList;
9 import java.util.Iterator;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Set;
13
14 import org.testng.annotations.Test;
15
16 import jalview.datamodel.SequenceFeature;
17 import junit.extensions.PA;
18
19 public class SequenceFeaturesTest
20 {
21   @Test(groups = "Functional")
22   public void testConstructor()
23   {
24     SequenceFeaturesI store = new SequenceFeatures();
25     assertFalse(store.hasFeatures());
26
27     store = new SequenceFeatures((List<SequenceFeature>) null);
28     assertFalse(store.hasFeatures());
29
30     List<SequenceFeature> features = new ArrayList<>();
31     store = new SequenceFeatures(features);
32     assertFalse(store.hasFeatures());
33
34     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
35             Float.NaN, null);
36     features.add(sf1);
37     SequenceFeature sf2 = new SequenceFeature("Metal", "desc", 15, 18,
38             Float.NaN, null);
39     features.add(sf2); // nested
40     SequenceFeature sf3 = new SequenceFeature("Pfam", "desc2", 0, 0,
41             Float.NaN, null); // non-positional
42     features.add(sf3);
43     store = new SequenceFeatures(features);
44     assertTrue(store.hasFeatures());
45     assertEquals(2, store.getFeatureCount(true)); // positional
46     assertEquals(1, store.getFeatureCount(false)); // non-positional
47     assertFalse(store.add(sf1)); // already contained
48     assertFalse(store.add(sf2)); // already contained
49     assertFalse(store.add(sf3)); // already contained
50   }
51
52   @Test(groups = "Functional")
53   public void testGetPositionalFeatures()
54   {
55     SequenceFeaturesI store = new SequenceFeatures();
56     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
57             Float.NaN, null);
58     store.add(sf1);
59     // same range, different description
60     SequenceFeature sf2 = new SequenceFeature("Metal", "desc2", 10, 20,
61             Float.NaN, null);
62     store.add(sf2);
63     // discontiguous range
64     SequenceFeature sf3 = new SequenceFeature("Metal", "desc", 30, 40,
65             Float.NaN, null);
66     store.add(sf3);
67     // overlapping range
68     SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 15, 35,
69             Float.NaN, null);
70     store.add(sf4);
71     // enclosing range
72     SequenceFeature sf5 = new SequenceFeature("Metal", "desc", 5, 50,
73             Float.NaN, null);
74     store.add(sf5);
75     // non-positional feature
76     SequenceFeature sf6 = new SequenceFeature("Metal", "desc", 0, 0,
77             Float.NaN, null);
78     store.add(sf6);
79     // contact feature
80     SequenceFeature sf7 = new SequenceFeature("Disulphide bond", "desc", 18,
81             45, Float.NaN, null);
82     store.add(sf7);
83     // different feature type
84     SequenceFeature sf8 = new SequenceFeature("Pfam", "desc", 30, 40,
85             Float.NaN, null);
86     store.add(sf8);
87     SequenceFeature sf9 = new SequenceFeature("Pfam", "desc", 15, 35,
88             Float.NaN, null);
89     store.add(sf9);
90
91     /*
92      * get all positional features
93      */
94     List<SequenceFeature> features = store.getPositionalFeatures();
95     assertEquals(features.size(), 8);
96     assertTrue(features.contains(sf1));
97     assertTrue(features.contains(sf2));
98     assertTrue(features.contains(sf3));
99     assertTrue(features.contains(sf4));
100     assertTrue(features.contains(sf5));
101     assertFalse(features.contains(sf6)); // non-positional
102     assertTrue(features.contains(sf7));
103     assertTrue(features.contains(sf8));
104     assertTrue(features.contains(sf9));
105
106     /*
107      * get features by type
108      */
109     assertTrue(store.getPositionalFeatures((String) null).isEmpty());
110     assertTrue(store.getPositionalFeatures("Cath").isEmpty());
111     assertTrue(store.getPositionalFeatures("METAL").isEmpty());
112
113     features = store.getPositionalFeatures("Metal");
114     assertEquals(features.size(), 5);
115     assertTrue(features.contains(sf1));
116     assertTrue(features.contains(sf2));
117     assertTrue(features.contains(sf3));
118     assertTrue(features.contains(sf4));
119     assertTrue(features.contains(sf5));
120     assertFalse(features.contains(sf6));
121
122     features = store.getPositionalFeatures("Disulphide bond");
123     assertEquals(features.size(), 1);
124     assertTrue(features.contains(sf7));
125
126     features = store.getPositionalFeatures("Pfam");
127     assertEquals(features.size(), 2);
128     assertTrue(features.contains(sf8));
129     assertTrue(features.contains(sf9));
130   }
131
132   @Test(groups = "Functional")
133   public void testGetContactFeatures()
134   {
135     SequenceFeaturesI store = new SequenceFeatures();
136     // non-contact
137     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
138             Float.NaN, null);
139     store.add(sf1);
140     // non-positional
141     SequenceFeature sf2 = new SequenceFeature("Metal", "desc", 0, 0,
142             Float.NaN, null);
143     store.add(sf2);
144     // contact feature
145     SequenceFeature sf3 = new SequenceFeature("Disulphide bond", "desc", 18,
146             45, Float.NaN, null);
147     store.add(sf3);
148     // repeat for different feature type
149     SequenceFeature sf4 = new SequenceFeature("Pfam", "desc", 10, 20,
150             Float.NaN, null);
151     store.add(sf4);
152     SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 0, 0,
153             Float.NaN, null);
154     store.add(sf5);
155     SequenceFeature sf6 = new SequenceFeature("Disulfide bond", "desc", 18,
156             45, Float.NaN, null);
157     store.add(sf6);
158
159     /*
160      * get all contact features
161      */
162     List<SequenceFeature> features = store.getContactFeatures();
163     assertEquals(features.size(), 2);
164     assertTrue(features.contains(sf3));
165     assertTrue(features.contains(sf6));
166
167     /*
168      * get contact features by type
169      */
170     assertTrue(store.getContactFeatures((String) null).isEmpty());
171     assertTrue(store.getContactFeatures("Cath").isEmpty());
172     assertTrue(store.getContactFeatures("Pfam").isEmpty());
173     assertTrue(store.getContactFeatures("DISULPHIDE BOND").isEmpty());
174
175     features = store.getContactFeatures("Disulphide bond");
176     assertEquals(features.size(), 1);
177     assertTrue(features.contains(sf3));
178
179     features = store.getContactFeatures("Disulfide bond");
180     assertEquals(features.size(), 1);
181     assertTrue(features.contains(sf6));
182   }
183
184   @Test(groups = "Functional")
185   public void testGetNonPositionalFeatures()
186   {
187     SequenceFeaturesI store = new SequenceFeatures();
188     // positional
189     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
190             Float.NaN, null);
191     store.add(sf1);
192     // non-positional
193     SequenceFeature sf2 = new SequenceFeature("Metal", "desc", 0, 0,
194             Float.NaN, null);
195     store.add(sf2);
196     // contact feature
197     SequenceFeature sf3 = new SequenceFeature("Disulphide bond", "desc", 18,
198             45, Float.NaN, null);
199     store.add(sf3);
200     // repeat for different feature type
201     SequenceFeature sf4 = new SequenceFeature("Pfam", "desc", 10, 20,
202             Float.NaN, null);
203     store.add(sf4);
204     SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 0, 0,
205             Float.NaN, null);
206     store.add(sf5);
207     SequenceFeature sf6 = new SequenceFeature("Disulfide bond", "desc", 18,
208             45, Float.NaN, null);
209     store.add(sf6);
210     // one more non-positional, different description
211     SequenceFeature sf7 = new SequenceFeature("Pfam", "desc2", 0, 0,
212             Float.NaN, null);
213     store.add(sf7);
214
215     /*
216      * get all non-positional features
217      */
218     List<SequenceFeature> features = store.getNonPositionalFeatures();
219     assertEquals(features.size(), 3);
220     assertTrue(features.contains(sf2));
221     assertTrue(features.contains(sf5));
222     assertTrue(features.contains(sf7));
223
224     /*
225      * get non-positional features by type
226      */
227     assertTrue(store.getNonPositionalFeatures((String) null).isEmpty());
228     assertTrue(store.getNonPositionalFeatures("Cath").isEmpty());
229     assertTrue(store.getNonPositionalFeatures("PFAM").isEmpty());
230
231     features = store.getNonPositionalFeatures("Metal");
232     assertEquals(features.size(), 1);
233     assertTrue(features.contains(sf2));
234
235     features = store.getNonPositionalFeatures("Pfam");
236     assertEquals(features.size(), 2);
237     assertTrue(features.contains(sf5));
238     assertTrue(features.contains(sf7));
239   }
240
241   /**
242    * Helper method to add a feature of no particular type
243    * 
244    * @param sf
245    * @param type
246    * @param from
247    * @param to
248    * @return
249    */
250   SequenceFeature addFeature(SequenceFeaturesI sf, String type, int from,
251           int to)
252   {
253     SequenceFeature sf1 = new SequenceFeature(type, "", from, to, Float.NaN,
254             null);
255     sf.add(sf1);
256     return sf1;
257   }
258
259   @Test(groups = "Functional")
260   public void testFindFeatures()
261   {
262     SequenceFeaturesI sf = new SequenceFeatures();
263     SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
264     SequenceFeature sf2 = addFeature(sf, "Pfam", 1, 15);
265     SequenceFeature sf3 = addFeature(sf, "Pfam", 20, 30);
266     SequenceFeature sf4 = addFeature(sf, "Pfam", 40, 100);
267     SequenceFeature sf5 = addFeature(sf, "Pfam", 60, 100);
268     SequenceFeature sf6 = addFeature(sf, "Pfam", 70, 70);
269     SequenceFeature sf7 = addFeature(sf, "Cath", 10, 50);
270     SequenceFeature sf8 = addFeature(sf, "Cath", 1, 15);
271     SequenceFeature sf9 = addFeature(sf, "Cath", 20, 30);
272     SequenceFeature sf10 = addFeature(sf, "Cath", 40, 100);
273     SequenceFeature sf11 = addFeature(sf, "Cath", 60, 100);
274     SequenceFeature sf12 = addFeature(sf, "Cath", 70, 70);
275
276     List<SequenceFeature> overlaps = sf.findFeatures(200, 200, "Pfam");
277     assertTrue(overlaps.isEmpty());
278
279     overlaps = sf.findFeatures(1, 9, "Pfam");
280     assertEquals(overlaps.size(), 1);
281     assertTrue(overlaps.contains(sf2));
282
283     overlaps = sf.findFeatures(5, 18, "Pfam");
284     assertEquals(overlaps.size(), 2);
285     assertTrue(overlaps.contains(sf1));
286     assertTrue(overlaps.contains(sf2));
287
288     overlaps = sf.findFeatures(30, 40, "Pfam");
289     assertEquals(overlaps.size(), 3);
290     assertTrue(overlaps.contains(sf1));
291     assertTrue(overlaps.contains(sf3));
292     assertTrue(overlaps.contains(sf4));
293
294     overlaps = sf.findFeatures(80, 90, "Pfam");
295     assertEquals(overlaps.size(), 2);
296     assertTrue(overlaps.contains(sf4));
297     assertTrue(overlaps.contains(sf5));
298
299     overlaps = sf.findFeatures(68, 70, "Pfam");
300     assertEquals(overlaps.size(), 3);
301     assertTrue(overlaps.contains(sf4));
302     assertTrue(overlaps.contains(sf5));
303     assertTrue(overlaps.contains(sf6));
304
305     overlaps = sf.findFeatures(16, 69, "Cath");
306     assertEquals(overlaps.size(), 4);
307     assertTrue(overlaps.contains(sf7));
308     assertFalse(overlaps.contains(sf8));
309     assertTrue(overlaps.contains(sf9));
310     assertTrue(overlaps.contains(sf10));
311     assertTrue(overlaps.contains(sf11));
312     assertFalse(overlaps.contains(sf12));
313
314     assertTrue(sf.findFeatures(0, 1000, "Metal").isEmpty());
315
316     overlaps = sf.findFeatures(7, 7, (String) null);
317     assertTrue(overlaps.isEmpty());
318   }
319
320   @Test(groups = "Functional")
321   public void testDelete()
322   {
323     SequenceFeaturesI sf = new SequenceFeatures();
324     SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
325     assertTrue(sf.getPositionalFeatures().contains(sf1));
326
327     assertFalse(sf.delete(null));
328     SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 15, 0f, null);
329     assertFalse(sf.delete(sf2)); // not added, can't delete it
330     assertTrue(sf.delete(sf1));
331     assertTrue(sf.getPositionalFeatures().isEmpty());
332   }
333
334   @Test(groups = "Functional")
335   public void testHasFeatures()
336   {
337     SequenceFeaturesI sf = new SequenceFeatures();
338     assertFalse(sf.hasFeatures());
339
340     SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
341     assertTrue(sf.hasFeatures());
342
343     sf.delete(sf1);
344     assertFalse(sf.hasFeatures());
345   }
346
347   /**
348    * Tests for the method that gets feature groups for positional or
349    * non-positional features
350    */
351   @Test(groups = "Functional")
352   public void testGetFeatureGroups()
353   {
354     SequenceFeaturesI sf = new SequenceFeatures();
355     assertTrue(sf.getFeatureGroups(true).isEmpty());
356     assertTrue(sf.getFeatureGroups(false).isEmpty());
357
358     /*
359      * add a non-positional feature (begin/end = 0/0)
360      */
361     SequenceFeature sfx = new SequenceFeature("AType", "Desc", 0, 0, 0f,
362             "AGroup");
363     sf.add(sfx);
364     Set<String> groups = sf.getFeatureGroups(true); // for positional
365     assertTrue(groups.isEmpty());
366     groups = sf.getFeatureGroups(false); // for non-positional
367     assertEquals(groups.size(), 1);
368     assertTrue(groups.contains("AGroup"));
369     groups = sf.getFeatureGroups(false, "AType");
370     assertEquals(groups.size(), 1);
371     assertTrue(groups.contains("AGroup"));
372     groups = sf.getFeatureGroups(true, "AnotherType");
373     assertTrue(groups.isEmpty());
374
375     /*
376      * add, then delete, more non-positional features of different types
377      */
378     SequenceFeature sfy = new SequenceFeature("AnotherType", "Desc", 0, 0,
379             0f, "AnotherGroup");
380     sf.add(sfy);
381     SequenceFeature sfz = new SequenceFeature("AThirdType", "Desc", 0, 0,
382             0f, null);
383     sf.add(sfz);
384     groups = sf.getFeatureGroups(false);
385     assertEquals(groups.size(), 3);
386     assertTrue(groups.contains("AGroup"));
387     assertTrue(groups.contains("AnotherGroup"));
388     assertTrue(groups.contains(null)); // null is a possible group
389     sf.delete(sfz);
390     sf.delete(sfy);
391     groups = sf.getFeatureGroups(false);
392     assertEquals(groups.size(), 1);
393     assertTrue(groups.contains("AGroup"));
394
395     /*
396      * add positional features
397      */
398     SequenceFeature sf1 = new SequenceFeature("Pfam", "Desc", 10, 50, 0f,
399             "PfamGroup");
400     sf.add(sf1);
401     groups = sf.getFeatureGroups(true);
402     assertEquals(groups.size(), 1);
403     assertTrue(groups.contains("PfamGroup"));
404     groups = sf.getFeatureGroups(false); // non-positional unchanged
405     assertEquals(groups.size(), 1);
406     assertTrue(groups.contains("AGroup"));
407
408     SequenceFeature sf2 = new SequenceFeature("Cath", "Desc", 10, 50, 0f,
409             null);
410     sf.add(sf2);
411     groups = sf.getFeatureGroups(true);
412     assertEquals(groups.size(), 2);
413     assertTrue(groups.contains("PfamGroup"));
414     assertTrue(groups.contains(null));
415
416     sf.delete(sf1);
417     sf.delete(sf2);
418     assertTrue(sf.getFeatureGroups(true).isEmpty());
419
420     SequenceFeature sf3 = new SequenceFeature("CDS", "", 10, 50, 0f,
421             "Ensembl");
422     sf.add(sf3);
423     SequenceFeature sf4 = new SequenceFeature("exon", "", 10, 50, 0f,
424             "Ensembl");
425     sf.add(sf4);
426     groups = sf.getFeatureGroups(true);
427     assertEquals(groups.size(), 1);
428     assertTrue(groups.contains("Ensembl"));
429
430     /*
431      * delete last Ensembl group feature from CDS features
432      * but still have one in exon features
433      */
434     sf.delete(sf3);
435     groups = sf.getFeatureGroups(true);
436     assertEquals(groups.size(), 1);
437     assertTrue(groups.contains("Ensembl"));
438
439     /*
440      * delete the last non-positional feature
441      */
442     sf.delete(sfx);
443     groups = sf.getFeatureGroups(false);
444     assertTrue(groups.isEmpty());
445   }
446
447   @Test(groups = "Functional")
448   public void testGetFeatureTypesForGroups()
449   {
450     SequenceFeaturesI sf = new SequenceFeatures();
451     assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
452
453     /*
454      * add feature with group = "Uniprot", type = "helix"
455      */
456     String groupUniprot = "Uniprot";
457     SequenceFeature sf1 = new SequenceFeature("helix", "Desc", 10, 50, 0f,
458             groupUniprot);
459     sf.add(sf1);
460     Set<String> groups = sf.getFeatureTypesForGroups(true, groupUniprot);
461     assertEquals(groups.size(), 1);
462     assertTrue(groups.contains("helix"));
463     assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
464
465     /*
466      * add feature with group = "Uniprot", type = "strand"
467      */
468     SequenceFeature sf2 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
469             groupUniprot);
470     sf.add(sf2);
471     groups = sf.getFeatureTypesForGroups(true, groupUniprot);
472     assertEquals(groups.size(), 2);
473     assertTrue(groups.contains("helix"));
474     assertTrue(groups.contains("strand"));
475
476     /*
477      * delete the "strand" Uniprot feature - still have "helix"
478      */
479     sf.delete(sf2);
480     groups = sf.getFeatureTypesForGroups(true, groupUniprot);
481     assertEquals(groups.size(), 1);
482     assertTrue(groups.contains("helix"));
483
484     /*
485      * delete the "helix" Uniprot feature - none left
486      */
487     sf.delete(sf1);
488     assertTrue(sf.getFeatureTypesForGroups(true, groupUniprot).isEmpty());
489
490     /*
491      * add some null group features
492      */
493     SequenceFeature sf3 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
494             null);
495     sf.add(sf3);
496     SequenceFeature sf4 = new SequenceFeature("turn", "Desc", 10, 50, 0f,
497             null);
498     sf.add(sf4);
499     groups = sf.getFeatureTypesForGroups(true, (String) null);
500     assertEquals(groups.size(), 2);
501     assertTrue(groups.contains("strand"));
502     assertTrue(groups.contains("turn"));
503
504     /*
505      * add strand/Cath  and turn/Scop and query for one or both groups
506      * (find feature types for groups selected in Feature Settings)
507      */
508     SequenceFeature sf5 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
509             "Cath");
510     sf.add(sf5);
511     SequenceFeature sf6 = new SequenceFeature("turn", "Desc", 10, 50, 0f,
512             "Scop");
513     sf.add(sf6);
514     groups = sf.getFeatureTypesForGroups(true, "Cath");
515     assertEquals(groups.size(), 1);
516     assertTrue(groups.contains("strand"));
517     groups = sf.getFeatureTypesForGroups(true, "Scop");
518     assertEquals(groups.size(), 1);
519     assertTrue(groups.contains("turn"));
520     groups = sf.getFeatureTypesForGroups(true, "Cath", "Scop");
521     assertEquals(groups.size(), 2);
522     assertTrue(groups.contains("turn"));
523     assertTrue(groups.contains("strand"));
524     // alternative vararg syntax
525     groups = sf.getFeatureTypesForGroups(true,
526             new String[]
527             { "Cath", "Scop" });
528     assertEquals(groups.size(), 2);
529     assertTrue(groups.contains("turn"));
530     assertTrue(groups.contains("strand"));
531   }
532
533   @Test(groups = "Functional")
534   public void testGetFeatureTypes()
535   {
536     SequenceFeaturesI store = new SequenceFeatures();
537     Set<String> types = store.getFeatureTypes();
538     assertTrue(types.isEmpty());
539
540     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
541             Float.NaN, null);
542     store.add(sf1);
543     types = store.getFeatureTypes();
544     assertEquals(types.size(), 1);
545     assertTrue(types.contains("Metal"));
546
547     // null type is rejected...
548     SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20,
549             Float.NaN, null);
550     assertFalse(store.add(sf2));
551     types = store.getFeatureTypes();
552     assertEquals(types.size(), 1);
553     assertFalse(types.contains(null));
554     assertTrue(types.contains("Metal"));
555
556     /*
557      * add non-positional feature
558      */
559     SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
560             Float.NaN, null);
561     store.add(sf3);
562     types = store.getFeatureTypes();
563     assertEquals(types.size(), 2);
564     assertTrue(types.contains("Pfam"));
565
566     /*
567      * add contact feature
568      */
569     SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc", 10,
570             20, Float.NaN, null);
571     store.add(sf4);
572     types = store.getFeatureTypes();
573     assertEquals(types.size(), 3);
574     assertTrue(types.contains("Disulphide Bond"));
575
576     /*
577      * add another Pfam
578      */
579     SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
580             Float.NaN, null);
581     store.add(sf5);
582     types = store.getFeatureTypes();
583     assertEquals(types.size(), 3); // unchanged
584
585     /*
586      * delete first Pfam - still have one
587      */
588     assertTrue(store.delete(sf3));
589     types = store.getFeatureTypes();
590     assertEquals(types.size(), 3);
591     assertTrue(types.contains("Pfam"));
592
593     /*
594      * delete second Pfam - no longer have one
595      */
596     assertTrue(store.delete(sf5));
597     types = store.getFeatureTypes();
598     assertEquals(types.size(), 2);
599     assertFalse(types.contains("Pfam"));
600   }
601
602   @Test(groups = "Functional")
603   public void testGetFeatureCount()
604   {
605     SequenceFeaturesI store = new SequenceFeatures();
606     assertEquals(store.getFeatureCount(true), 0);
607     assertEquals(store.getFeatureCount(false), 0);
608
609     /*
610      * add positional
611      */
612     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
613             Float.NaN, null);
614     store.add(sf1);
615     assertEquals(store.getFeatureCount(true), 1);
616     assertEquals(store.getFeatureCount(false), 0);
617
618     /*
619      * null feature type is rejected
620      */
621     SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20,
622             Float.NaN, null);
623     assertFalse(store.add(sf2));
624     assertEquals(store.getFeatureCount(true), 1);
625     assertEquals(store.getFeatureCount(false), 0);
626
627     /*
628      * add non-positional feature
629      */
630     SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
631             Float.NaN, null);
632     store.add(sf3);
633     assertEquals(store.getFeatureCount(true), 1);
634     assertEquals(store.getFeatureCount(false), 1);
635
636     /*
637      * add contact feature (counts as 1)
638      */
639     SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc", 10,
640             20, Float.NaN, null);
641     store.add(sf4);
642     assertEquals(store.getFeatureCount(true), 2);
643     assertEquals(store.getFeatureCount(false), 1);
644
645     /*
646      * add another Pfam but this time as a positional feature
647      */
648     SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
649             Float.NaN, null);
650     store.add(sf5);
651     assertEquals(store.getFeatureCount(true), 3); // sf1, sf4, sf5
652     assertEquals(store.getFeatureCount(false), 1); // sf3
653     assertEquals(store.getFeatureCount(true, "Pfam"), 1); // positional
654     assertEquals(store.getFeatureCount(false, "Pfam"), 1); // non-positional
655     // search for type==null
656     assertEquals(store.getFeatureCount(true, (String) null), 0);
657     // search with no type specified
658     assertEquals(store.getFeatureCount(true, (String[]) null), 3);
659     assertEquals(store.getFeatureCount(true, "Metal", "Cath"), 1);
660     assertEquals(store.getFeatureCount(true, "Disulphide Bond"), 1);
661     assertEquals(store.getFeatureCount(true, "Metal", "Pfam", null), 2);
662
663     /*
664      * delete first Pfam (non-positional)
665      */
666     assertTrue(store.delete(sf3));
667     assertEquals(store.getFeatureCount(true), 3);
668     assertEquals(store.getFeatureCount(false), 0);
669
670     /*
671      * delete second Pfam (positional)
672      */
673     assertTrue(store.delete(sf5));
674     assertEquals(store.getFeatureCount(true), 2);
675     assertEquals(store.getFeatureCount(false), 0);
676   }
677
678   @Test(groups = "Functional")
679   public void testGetAllFeatures()
680   {
681     SequenceFeaturesI store = new SequenceFeatures();
682     List<SequenceFeature> features = store.getAllFeatures();
683     assertTrue(features.isEmpty());
684
685     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
686             Float.NaN, null);
687     store.add(sf1);
688     features = store.getAllFeatures();
689     assertEquals(features.size(), 1);
690     assertTrue(features.contains(sf1));
691
692     SequenceFeature sf2 = new SequenceFeature("Metallic", "desc", 10, 20,
693             Float.NaN, null);
694     store.add(sf2);
695     features = store.getAllFeatures();
696     assertEquals(features.size(), 2);
697     assertTrue(features.contains(sf2));
698
699     /*
700      * add non-positional feature
701      */
702     SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
703             Float.NaN, null);
704     store.add(sf3);
705     features = store.getAllFeatures();
706     assertEquals(features.size(), 3);
707     assertTrue(features.contains(sf3));
708
709     /*
710      * add contact feature
711      */
712     SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc", 10,
713             20, Float.NaN, null);
714     store.add(sf4);
715     features = store.getAllFeatures();
716     assertEquals(features.size(), 4);
717     assertTrue(features.contains(sf4));
718
719     /*
720      * add another Pfam
721      */
722     SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
723             Float.NaN, null);
724     store.add(sf5);
725     features = store.getAllFeatures();
726     assertEquals(features.size(), 5);
727     assertTrue(features.contains(sf5));
728
729     /*
730      * select by type does not apply to non-positional features
731      */
732     features = store.getAllFeatures("Cath");
733     assertEquals(features.size(), 1);
734     assertTrue(features.contains(sf3));
735
736     features = store.getAllFeatures("Pfam", "Cath", "Metal");
737     assertEquals(features.size(), 3);
738     assertTrue(features.contains(sf1));
739     assertTrue(features.contains(sf3));
740     assertTrue(features.contains(sf5));
741
742     /*
743      * delete first Pfam
744      */
745     assertTrue(store.delete(sf3));
746     features = store.getAllFeatures();
747     assertEquals(features.size(), 4);
748     assertFalse(features.contains(sf3));
749
750     /*
751      * delete second Pfam
752      */
753     assertTrue(store.delete(sf5));
754     features = store.getAllFeatures();
755     assertEquals(features.size(), 3);
756     assertFalse(features.contains(sf3));
757   }
758
759   @Test(groups = "Functional")
760   public void testGetTotalFeatureLength()
761   {
762     SequenceFeaturesI store = new SequenceFeatures();
763     assertEquals(store.getTotalFeatureLength(), 0);
764
765     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
766             Float.NaN, null);
767     assertTrue(store.add(sf1));
768     assertEquals(store.getTotalFeatureLength(), 11);
769     assertEquals(store.getTotalFeatureLength("Metal"), 11);
770     assertEquals(store.getTotalFeatureLength("Plastic"), 0);
771
772     // re-add does nothing!
773     assertFalse(store.add(sf1));
774     assertEquals(store.getTotalFeatureLength(), 11);
775
776     /*
777      * add non-positional feature
778      */
779     SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
780             Float.NaN, null);
781     store.add(sf3);
782     assertEquals(store.getTotalFeatureLength(), 11);
783
784     /*
785      * add contact feature - counts 1 to feature length
786      */
787     SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc", 10,
788             20, Float.NaN, null);
789     store.add(sf4);
790     assertEquals(store.getTotalFeatureLength(), 12);
791
792     /*
793      * add another Pfam
794      */
795     SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
796             Float.NaN, null);
797     store.add(sf5);
798     assertEquals(store.getTotalFeatureLength(), 23);
799
800     /*
801      * delete features
802      */
803     assertTrue(store.delete(sf3)); // non-positional
804     assertEquals(store.getTotalFeatureLength(), 23); // no change
805
806     assertTrue(store.delete(sf5));
807     assertEquals(store.getTotalFeatureLength(), 12);
808
809     assertTrue(store.delete(sf4)); // contact
810     assertEquals(store.getTotalFeatureLength(), 11);
811
812     assertTrue(store.delete(sf1));
813     assertEquals(store.getTotalFeatureLength(), 0);
814   }
815
816   @Test(groups = "Functional")
817   public void testGetMinimumScore_getMaximumScore()
818   {
819     SequenceFeatures sf = new SequenceFeatures();
820     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 0, 0,
821             Float.NaN, "group"); // non-positional, no score
822     sf.add(sf1);
823     SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 10, 20,
824             Float.NaN, "group"); // positional, no score
825     sf.add(sf2);
826     SequenceFeature sf3 = new SequenceFeature("Metal", "desc", 10, 20, 1f,
827             "group");
828     sf.add(sf3);
829     SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 12, 16, 4f,
830             "group");
831     sf.add(sf4);
832     SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 0, 0, 11f,
833             "group");
834     sf.add(sf5);
835     SequenceFeature sf6 = new SequenceFeature("Cath", "desc", 0, 0, -7f,
836             "group");
837     sf.add(sf6);
838
839     assertEquals(sf.getMinimumScore("nosuchtype", true), Float.NaN);
840     assertEquals(sf.getMinimumScore("nosuchtype", false), Float.NaN);
841     assertEquals(sf.getMaximumScore("nosuchtype", true), Float.NaN);
842     assertEquals(sf.getMaximumScore("nosuchtype", false), Float.NaN);
843
844     // positional features min-max:
845     assertEquals(sf.getMinimumScore("Metal", true), 1f);
846     assertEquals(sf.getMaximumScore("Metal", true), 4f);
847     assertEquals(sf.getMinimumScore("Cath", true), Float.NaN);
848     assertEquals(sf.getMaximumScore("Cath", true), Float.NaN);
849
850     // non-positional features min-max:
851     assertEquals(sf.getMinimumScore("Cath", false), -7f);
852     assertEquals(sf.getMaximumScore("Cath", false), 11f);
853     assertEquals(sf.getMinimumScore("Metal", false), Float.NaN);
854     assertEquals(sf.getMaximumScore("Metal", false), Float.NaN);
855
856     // delete features; min-max should get recomputed
857     sf.delete(sf6);
858     assertEquals(sf.getMinimumScore("Cath", false), 11f);
859     assertEquals(sf.getMaximumScore("Cath", false), 11f);
860     sf.delete(sf4);
861     assertEquals(sf.getMinimumScore("Metal", true), 1f);
862     assertEquals(sf.getMaximumScore("Metal", true), 1f);
863     sf.delete(sf5);
864     assertEquals(sf.getMinimumScore("Cath", false), Float.NaN);
865     assertEquals(sf.getMaximumScore("Cath", false), Float.NaN);
866     sf.delete(sf3);
867     assertEquals(sf.getMinimumScore("Metal", true), Float.NaN);
868     assertEquals(sf.getMaximumScore("Metal", true), Float.NaN);
869     sf.delete(sf1);
870     sf.delete(sf2);
871     assertFalse(sf.hasFeatures());
872     assertEquals(sf.getMinimumScore("Cath", false), Float.NaN);
873     assertEquals(sf.getMaximumScore("Cath", false), Float.NaN);
874     assertEquals(sf.getMinimumScore("Metal", true), Float.NaN);
875     assertEquals(sf.getMaximumScore("Metal", true), Float.NaN);
876   }
877
878   @Test(groups = "Functional")
879   public void testVarargsToTypes()
880   {
881     SequenceFeatures sf = new SequenceFeatures();
882     sf.add(new SequenceFeature("Metal", "desc", 0, 0, Float.NaN, "group"));
883     sf.add(new SequenceFeature("Cath", "desc", 10, 20, Float.NaN, "group"));
884
885     /*
886      * no type specified - get all types stored
887      * they are returned in keyset (alphabetical) order
888      */
889     Map<String, FeatureStore> featureStores = (Map<String, FeatureStore>) PA
890             .getValue(sf, "featureStore");
891
892     Iterable<FeatureStore> types = sf.varargToTypes();
893     Iterator<FeatureStore> iterator = types.iterator();
894     assertTrue(iterator.hasNext());
895     assertSame(iterator.next(), featureStores.get("Cath"));
896     assertTrue(iterator.hasNext());
897     assertSame(iterator.next(), featureStores.get("Metal"));
898     assertFalse(iterator.hasNext());
899
900     /*
901      * empty array is the same as no vararg parameter supplied
902      * so treated as all stored types
903      */
904     types = sf.varargToTypes(new String[] {});
905     iterator = types.iterator();
906     assertTrue(iterator.hasNext());
907     assertSame(iterator.next(), featureStores.get("Cath"));
908     assertTrue(iterator.hasNext());
909     assertSame(iterator.next(), featureStores.get("Metal"));
910     assertFalse(iterator.hasNext());
911
912     /*
913      * null type specified; this is passed as vararg
914      * String[1] {null}
915      */
916     types = sf.varargToTypes((String) null);
917     assertFalse(types.iterator().hasNext());
918
919     /*
920      * null types array specified; this is passed as vararg null
921      */
922     types = sf.varargToTypes((String[]) null);
923     iterator = types.iterator();
924     assertTrue(iterator.hasNext());
925     assertSame(iterator.next(), featureStores.get("Cath"));
926     assertTrue(iterator.hasNext());
927     assertSame(iterator.next(), featureStores.get("Metal"));
928     assertFalse(iterator.hasNext());
929
930     /*
931      * one type specified
932      */
933     types = sf.varargToTypes("Metal");
934     iterator = types.iterator();
935     assertTrue(iterator.hasNext());
936     assertSame(iterator.next(), featureStores.get("Metal"));
937     assertFalse(iterator.hasNext());
938
939     /*
940      * two types specified - order is preserved
941      */
942     types = sf.varargToTypes("Metal", "Cath");
943     iterator = types.iterator();
944     assertTrue(iterator.hasNext());
945     assertSame(iterator.next(), featureStores.get("Metal"));
946     assertTrue(iterator.hasNext());
947     assertSame(iterator.next(), featureStores.get("Cath"));
948     assertFalse(iterator.hasNext());
949
950     /*
951      * null type included - should be ignored
952      */
953     types = sf.varargToTypes("Metal", null, "Helix");
954     iterator = types.iterator();
955     assertTrue(iterator.hasNext());
956     assertSame(iterator.next(), featureStores.get("Metal"));
957     assertFalse(iterator.hasNext());
958   }
959
960   @Test(groups = "Functional")
961   public void testGetFeatureTypes_byOntology()
962   {
963     SequenceFeaturesI store = new SequenceFeatures();
964
965     SequenceFeature sf1 = new SequenceFeature("transcript", "desc", 10, 20,
966             Float.NaN, null);
967     store.add(sf1);
968     // mRNA isA mature_transcript isA transcript
969     SequenceFeature sf2 = new SequenceFeature("mRNA", "desc", 10, 20,
970             Float.NaN, null);
971     store.add(sf2);
972     // just to prove non-positional feature types are included
973     SequenceFeature sf3 = new SequenceFeature("mRNA", "desc", 0, 0,
974             Float.NaN, null);
975     store.add(sf3);
976     SequenceFeature sf4 = new SequenceFeature("CDS", "desc", 0, 0,
977             Float.NaN, null);
978     store.add(sf4);
979
980     Set<String> types = store.getFeatureTypes("transcript");
981     assertEquals(types.size(), 2);
982     assertTrue(types.contains("transcript"));
983     assertTrue(types.contains("mRNA"));
984
985     // matches include arguments whether SO terms or not
986     types = store.getFeatureTypes("transcript", "CDS");
987     assertEquals(types.size(), 3);
988     assertTrue(types.contains("transcript"));
989     assertTrue(types.contains("mRNA"));
990     assertTrue(types.contains("CDS"));
991
992     types = store.getFeatureTypes("exon");
993     assertTrue(types.isEmpty());
994   }
995
996   @Test(groups = "Functional")
997   public void testGetFeaturesByOntology()
998   {
999     SequenceFeaturesI store = new SequenceFeatures();
1000     List<SequenceFeature> features = store.getFeaturesByOntology();
1001     assertTrue(features.isEmpty());
1002     assertTrue(store.getFeaturesByOntology(new String[] {}).isEmpty());
1003     assertTrue(store.getFeaturesByOntology((String[]) null).isEmpty());
1004
1005     SequenceFeature transcriptFeature = new SequenceFeature("transcript",
1006             "desc", 10, 20, Float.NaN, null);
1007     store.add(transcriptFeature);
1008
1009     /*
1010      * mRNA is a sub-type of transcript; added here 'as if' non-positional
1011      * just to show that non-positional features are included in results
1012      */
1013     SequenceFeature mrnaFeature = new SequenceFeature("mRNA", "desc", 0, 0,
1014             Float.NaN, null);
1015     store.add(mrnaFeature);
1016
1017     SequenceFeature pfamFeature = new SequenceFeature("Pfam", "desc", 30,
1018             40, Float.NaN, null);
1019     store.add(pfamFeature);
1020
1021     /*
1022      * "transcript" matches both itself and the sub-term "mRNA"
1023      */
1024     features = store.getFeaturesByOntology("transcript");
1025     assertEquals(features.size(), 2);
1026     assertTrue(features.contains(transcriptFeature));
1027     assertTrue(features.contains(mrnaFeature));
1028
1029     /*
1030      * "mRNA" matches itself but not parent term "transcript"
1031      */
1032     features = store.getFeaturesByOntology("mRNA");
1033     assertEquals(features.size(), 1);
1034     assertTrue(features.contains(mrnaFeature));
1035
1036     /*
1037      * "pfam" is not an SO term but is included as an exact match
1038      */
1039     features = store.getFeaturesByOntology("mRNA", "Pfam");
1040     assertEquals(features.size(), 2);
1041     assertTrue(features.contains(mrnaFeature));
1042     assertTrue(features.contains(pfamFeature));
1043
1044     features = store.getFeaturesByOntology("sequence_variant");
1045     assertTrue(features.isEmpty());
1046   }
1047
1048   @Test(groups = "Functional")
1049   public void testSortFeatures()
1050   {
1051     List<SequenceFeature> sfs = new ArrayList<>();
1052     SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 30, 60,
1053             Float.NaN, null);
1054     sfs.add(sf1);
1055     SequenceFeature sf2 = new SequenceFeature("Rfam", "desc", 40, 50,
1056             Float.NaN, null);
1057     sfs.add(sf2);
1058     SequenceFeature sf3 = new SequenceFeature("Rfam", "desc", 50, 60,
1059             Float.NaN, null);
1060     sfs.add(sf3);
1061     SequenceFeature sf4 = new SequenceFeature("Xfam", "desc", 30, 80,
1062             Float.NaN, null);
1063     sfs.add(sf4);
1064     SequenceFeature sf5 = new SequenceFeature("Xfam", "desc", 30, 90,
1065             Float.NaN, null);
1066     sfs.add(sf5);
1067
1068     /*
1069      * sort by end position descending, order unchanged if matched
1070      */
1071     SequenceFeatures.sortFeatures(sfs, false);
1072     assertSame(sfs.get(0), sf5); // end 90
1073     assertSame(sfs.get(1), sf4); // end 80
1074     assertSame(sfs.get(2), sf1); // end 60, start 50
1075     assertSame(sfs.get(3), sf3); // end 60, start 30
1076     assertSame(sfs.get(4), sf2); // end 50
1077
1078     /*
1079      * resort {5, 4, 1, 3, 2} by start position ascending, end descending
1080      */
1081     SequenceFeatures.sortFeatures(sfs, true);
1082     assertSame(sfs.get(0), sf5); // start 30, end 90
1083     assertSame(sfs.get(1), sf4); // start 30, end 80
1084     assertSame(sfs.get(2), sf1); // start 30, end 60
1085     assertSame(sfs.get(3), sf2); // start 40
1086     assertSame(sfs.get(4), sf3); // start 50
1087   }
1088
1089   @Test(groups = "Functional")
1090   public void testGetFeaturesForGroup()
1091   {
1092     SequenceFeaturesI store = new SequenceFeatures();
1093
1094     List<SequenceFeature> features = store.getFeaturesForGroup(true, null);
1095     assertTrue(features.isEmpty());
1096     assertTrue(store.getFeaturesForGroup(false, null).isEmpty());
1097     assertTrue(store.getFeaturesForGroup(true, "Uniprot").isEmpty());
1098     assertTrue(store.getFeaturesForGroup(false, "Uniprot").isEmpty());
1099
1100     SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
1101             null);
1102     SequenceFeature sf2 = new SequenceFeature("Pfam", "desc", 0, 0, 0f,
1103             null);
1104     SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
1105             "Uniprot");
1106     SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 0, 0, 0f,
1107             "Rfam");
1108     SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 5, 15, 0f,
1109             null);
1110     store.add(sf1);
1111     store.add(sf2);
1112     store.add(sf3);
1113     store.add(sf4);
1114     store.add(sf5);
1115
1116     // positional features for null group, any type
1117     features = store.getFeaturesForGroup(true, null);
1118     assertEquals(features.size(), 2);
1119     assertTrue(features.contains(sf1));
1120     assertTrue(features.contains(sf5));
1121
1122     // positional features for null group, specified type
1123     features = store.getFeaturesForGroup(true, null,
1124             new String[]
1125             { "Pfam", "Xfam" });
1126     assertEquals(features.size(), 1);
1127     assertTrue(features.contains(sf1));
1128     features = store.getFeaturesForGroup(true, null,
1129             new String[]
1130             { "Pfam", "Xfam", "Cath" });
1131     assertEquals(features.size(), 2);
1132     assertTrue(features.contains(sf1));
1133     assertTrue(features.contains(sf5));
1134
1135     // positional features for non-null group, any type
1136     features = store.getFeaturesForGroup(true, "Uniprot");
1137     assertEquals(features.size(), 1);
1138     assertTrue(features.contains(sf3));
1139     assertTrue(store.getFeaturesForGroup(true, "Rfam").isEmpty());
1140
1141     // positional features for non-null group, specified type
1142     features = store.getFeaturesForGroup(true, "Uniprot", "Pfam", "Xfam",
1143             "Rfam");
1144     assertEquals(features.size(), 1);
1145     assertTrue(features.contains(sf3));
1146     assertTrue(
1147             store.getFeaturesForGroup(true, "Uniprot", "Cath").isEmpty());
1148
1149     // non-positional features for null group, any type
1150     features = store.getFeaturesForGroup(false, null);
1151     assertEquals(features.size(), 1);
1152     assertTrue(features.contains(sf2));
1153
1154     // non-positional features for null group, specified type
1155     features = store.getFeaturesForGroup(false, null, "Pfam", "Xfam");
1156     assertEquals(features.size(), 1);
1157     assertTrue(features.contains(sf2));
1158     assertTrue(store.getFeaturesForGroup(false, null, "Cath").isEmpty());
1159
1160     // non-positional features for non-null group, any type
1161     features = store.getFeaturesForGroup(false, "Rfam");
1162     assertEquals(features.size(), 1);
1163     assertTrue(features.contains(sf4));
1164     assertTrue(store.getFeaturesForGroup(false, "Uniprot").isEmpty());
1165
1166     // non-positional features for non-null group, specified type
1167     features = store.getFeaturesForGroup(false, "Rfam", "Pfam", "Metal");
1168     assertEquals(features.size(), 1);
1169     assertTrue(features.contains(sf4));
1170     assertTrue(store.getFeaturesForGroup(false, "Rfam", "Cath", "Pfam")
1171             .isEmpty());
1172   }
1173
1174   @Test(groups = "Functional")
1175   public void testShiftFeatures()
1176   {
1177     SequenceFeatures store = new SequenceFeatures();
1178     assertFalse(store.shiftFeatures(0, 1));
1179
1180     SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
1181     store.add(sf1);
1182     // nested feature:
1183     SequenceFeature sf2 = new SequenceFeature("Metal", "", 8, 14, 0f, null);
1184     store.add(sf2);
1185     // contact feature:
1186     SequenceFeature sf3 = new SequenceFeature("Disulfide bond", "", 23, 32,
1187             0f, null);
1188     store.add(sf3);
1189     // non-positional feature:
1190     SequenceFeature sf4 = new SequenceFeature("Pfam", "", 0, 0, 0f, null);
1191     store.add(sf4);
1192
1193     /*
1194      * shift features right by 5
1195      */
1196     assertTrue(store.shiftFeatures(0, 5));
1197
1198     // non-positional features untouched:
1199     List<SequenceFeature> nonPos = store.getNonPositionalFeatures();
1200     assertEquals(nonPos.size(), 1);
1201     assertTrue(nonPos.contains(sf4));
1202
1203     // positional features are replaced
1204     List<SequenceFeature> pos = store.getPositionalFeatures();
1205     assertEquals(pos.size(), 3);
1206     assertFalse(pos.contains(sf1));
1207     assertFalse(pos.contains(sf2));
1208     assertFalse(pos.contains(sf3));
1209     SequenceFeatures.sortFeatures(pos, true); // ascending start pos
1210     assertEquals(pos.get(0).getBegin(), 7);
1211     assertEquals(pos.get(0).getEnd(), 10);
1212     assertEquals(pos.get(0).getType(), "Cath");
1213     assertEquals(pos.get(1).getBegin(), 13);
1214     assertEquals(pos.get(1).getEnd(), 19);
1215     assertEquals(pos.get(1).getType(), "Metal");
1216     assertEquals(pos.get(2).getBegin(), 28);
1217     assertEquals(pos.get(2).getEnd(), 37);
1218     assertEquals(pos.get(2).getType(), "Disulfide bond");
1219
1220     /*
1221      * now shift left by 15
1222      * feature at [7-10] should be removed
1223      * feature at [13-19] should become [1-4] 
1224      */
1225     assertTrue(store.shiftFeatures(0, -15));
1226     pos = store.getPositionalFeatures();
1227     assertEquals(pos.size(), 2);
1228     SequenceFeatures.sortFeatures(pos, true);
1229     assertEquals(pos.get(0).getBegin(), 1);
1230     assertEquals(pos.get(0).getEnd(), 4);
1231     assertEquals(pos.get(0).getType(), "Metal");
1232     assertEquals(pos.get(1).getBegin(), 13);
1233     assertEquals(pos.get(1).getEnd(), 22);
1234     assertEquals(pos.get(1).getType(), "Disulfide bond");
1235
1236     /*
1237      * shift right by 4 from column 2
1238      * feature at [1-4] should be unchanged
1239      * feature at [13-22] should become [17-26] 
1240      */
1241     assertTrue(store.shiftFeatures(2, 4));
1242     pos = store.getPositionalFeatures();
1243     assertEquals(pos.size(), 2);
1244     SequenceFeatures.sortFeatures(pos, true);
1245     assertEquals(pos.get(0).getBegin(), 1);
1246     assertEquals(pos.get(0).getEnd(), 4);
1247     assertEquals(pos.get(0).getType(), "Metal");
1248     assertEquals(pos.get(1).getBegin(), 17);
1249     assertEquals(pos.get(1).getEnd(), 26);
1250     assertEquals(pos.get(1).getType(), "Disulfide bond");
1251
1252     /*
1253      * shift right from column 18
1254      * should be no updates
1255      */
1256     SequenceFeature f1 = pos.get(0);
1257     SequenceFeature f2 = pos.get(1);
1258     assertFalse(store.shiftFeatures(18, 6));
1259     pos = store.getPositionalFeatures();
1260     assertEquals(pos.size(), 2);
1261     SequenceFeatures.sortFeatures(pos, true);
1262     assertSame(pos.get(0), f1);
1263     assertSame(pos.get(1), f2);
1264   }
1265
1266   @Test(groups = "Functional")
1267   public void testIsOntologyTerm()
1268   {
1269     SequenceFeatures store = new SequenceFeatures();
1270     assertTrue(store.isOntologyTerm("gobbledygook"));
1271     assertTrue(store.isOntologyTerm("transcript", "transcript"));
1272     assertTrue(store.isOntologyTerm("mRNA", "transcript"));
1273     assertFalse(store.isOntologyTerm("transcript", "mRNA"));
1274     assertTrue(store.isOntologyTerm("junk", "transcript", "junk"));
1275     assertTrue(store.isOntologyTerm("junk", new String[] {}));
1276     assertTrue(store.isOntologyTerm("junk", (String[]) null));
1277   }
1278
1279   @Test(groups = "Functional")
1280   public void testDeleteAll()
1281   {
1282     SequenceFeaturesI store = new SequenceFeatures();
1283     assertFalse(store.hasFeatures());
1284     store.deleteAll();
1285     assertFalse(store.hasFeatures());
1286     store.add(new SequenceFeature("Cath", "Desc", 12, 20, 0f, "Group"));
1287     store.add(new SequenceFeature("Pfam", "Desc", 6, 12, 2f, "Group2"));
1288     assertTrue(store.hasFeatures());
1289     store.deleteAll();
1290     assertFalse(store.hasFeatures());
1291   }
1292 }