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