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