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