1 package jalview.datamodel.features;
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;
8 import jalview.datamodel.SequenceFeature;
10 import java.util.ArrayList;
11 import java.util.Iterator;
12 import java.util.List;
15 import org.testng.annotations.Test;
17 public class SequenceFeaturesTest
19 @Test(groups = "Functional")
20 public void testConstructor()
22 SequenceFeaturesI store = new SequenceFeatures();
23 assertFalse(store.hasFeatures());
25 store = new SequenceFeatures((List<SequenceFeature>) null);
26 assertFalse(store.hasFeatures());
28 List<SequenceFeature> features = new ArrayList<>();
29 store = new SequenceFeatures(features);
30 assertFalse(store.hasFeatures());
32 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
35 SequenceFeature sf2 = new SequenceFeature("Metal", "desc", 15, 18,
37 features.add(sf2); // nested
38 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc2", 0, 0,
39 Float.NaN, null); // non-positional
41 store = new SequenceFeatures(features);
42 assertTrue(store.hasFeatures());
43 assertEquals(2, store.getFeatureCount(true)); // positional
44 assertEquals(1, store.getFeatureCount(false)); // non-positional
45 assertFalse(store.add(sf1)); // already contained
46 assertFalse(store.add(sf2)); // already contained
47 assertFalse(store.add(sf3)); // already contained
50 @Test(groups = "Functional")
51 public void testGetPositionalFeatures()
53 SequenceFeaturesI store = new SequenceFeatures();
54 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
57 // same range, different description
58 SequenceFeature sf2 = new SequenceFeature("Metal", "desc2", 10, 20,
61 // discontiguous range
62 SequenceFeature sf3 = new SequenceFeature("Metal", "desc", 30, 40,
66 SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 15, 35,
70 SequenceFeature sf5 = new SequenceFeature("Metal", "desc", 5, 50,
73 // non-positional feature
74 SequenceFeature sf6 = new SequenceFeature("Metal", "desc", 0, 0,
78 SequenceFeature sf7 = new SequenceFeature("Disulphide bond", "desc",
79 18, 45, Float.NaN, null);
81 // different feature type
82 SequenceFeature sf8 = new SequenceFeature("Pfam", "desc", 30, 40,
85 SequenceFeature sf9 = new SequenceFeature("Pfam", "desc", 15, 35,
90 * get all positional features
92 List<SequenceFeature> features = store.getPositionalFeatures();
93 assertEquals(features.size(), 8);
94 assertTrue(features.contains(sf1));
95 assertTrue(features.contains(sf2));
96 assertTrue(features.contains(sf3));
97 assertTrue(features.contains(sf4));
98 assertTrue(features.contains(sf5));
99 assertFalse(features.contains(sf6)); // non-positional
100 assertTrue(features.contains(sf7));
101 assertTrue(features.contains(sf8));
102 assertTrue(features.contains(sf9));
105 * get features by type
107 assertTrue(store.getPositionalFeatures((String) null).isEmpty());
108 assertTrue(store.getPositionalFeatures("Cath").isEmpty());
109 assertTrue(store.getPositionalFeatures("METAL").isEmpty());
111 features = store.getPositionalFeatures("Metal");
112 assertEquals(features.size(), 5);
113 assertTrue(features.contains(sf1));
114 assertTrue(features.contains(sf2));
115 assertTrue(features.contains(sf3));
116 assertTrue(features.contains(sf4));
117 assertTrue(features.contains(sf5));
118 assertFalse(features.contains(sf6));
120 features = store.getPositionalFeatures("Disulphide bond");
121 assertEquals(features.size(), 1);
122 assertTrue(features.contains(sf7));
124 features = store.getPositionalFeatures("Pfam");
125 assertEquals(features.size(), 2);
126 assertTrue(features.contains(sf8));
127 assertTrue(features.contains(sf9));
130 @Test(groups = "Functional")
131 public void testGetContactFeatures()
133 SequenceFeaturesI store = new SequenceFeatures();
135 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
139 SequenceFeature sf2 = new SequenceFeature("Metal", "desc", 0, 0,
143 SequenceFeature sf3 = new SequenceFeature("Disulphide bond", "desc",
144 18, 45, Float.NaN, null);
146 // repeat for different feature type
147 SequenceFeature sf4 = new SequenceFeature("Pfam", "desc", 10, 20,
150 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 0, 0,
153 SequenceFeature sf6 = new SequenceFeature("Disulfide bond", "desc", 18,
154 45, Float.NaN, null);
158 * get all contact features
160 List<SequenceFeature> features = store.getContactFeatures();
161 assertEquals(features.size(), 2);
162 assertTrue(features.contains(sf3));
163 assertTrue(features.contains(sf6));
166 * get contact features by type
168 assertTrue(store.getContactFeatures((String) null).isEmpty());
169 assertTrue(store.getContactFeatures("Cath").isEmpty());
170 assertTrue(store.getContactFeatures("Pfam").isEmpty());
171 assertTrue(store.getContactFeatures("DISULPHIDE BOND").isEmpty());
173 features = store.getContactFeatures("Disulphide bond");
174 assertEquals(features.size(), 1);
175 assertTrue(features.contains(sf3));
177 features = store.getContactFeatures("Disulfide bond");
178 assertEquals(features.size(), 1);
179 assertTrue(features.contains(sf6));
182 @Test(groups = "Functional")
183 public void testGetNonPositionalFeatures()
185 SequenceFeaturesI store = new SequenceFeatures();
187 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
191 SequenceFeature sf2 = new SequenceFeature("Metal", "desc", 0, 0,
195 SequenceFeature sf3 = new SequenceFeature("Disulphide bond", "desc",
196 18, 45, Float.NaN, null);
198 // repeat for different feature type
199 SequenceFeature sf4 = new SequenceFeature("Pfam", "desc", 10, 20,
202 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 0, 0,
205 SequenceFeature sf6 = new SequenceFeature("Disulfide bond", "desc", 18,
206 45, Float.NaN, null);
208 // one more non-positional, different description
209 SequenceFeature sf7 = new SequenceFeature("Pfam", "desc2", 0, 0,
214 * get all non-positional features
216 List<SequenceFeature> features = store.getNonPositionalFeatures();
217 assertEquals(features.size(), 3);
218 assertTrue(features.contains(sf2));
219 assertTrue(features.contains(sf5));
220 assertTrue(features.contains(sf7));
223 * get non-positional features by type
225 assertTrue(store.getNonPositionalFeatures((String) null).isEmpty());
226 assertTrue(store.getNonPositionalFeatures("Cath").isEmpty());
227 assertTrue(store.getNonPositionalFeatures("PFAM").isEmpty());
229 features = store.getNonPositionalFeatures("Metal");
230 assertEquals(features.size(), 1);
231 assertTrue(features.contains(sf2));
233 features = store.getNonPositionalFeatures("Pfam");
234 assertEquals(features.size(), 2);
235 assertTrue(features.contains(sf5));
236 assertTrue(features.contains(sf7));
240 * Helper method to add a feature of no particular type
248 SequenceFeature addFeature(SequenceFeaturesI sf, String type, int from,
251 SequenceFeature sf1 = new SequenceFeature(type, "", from, to,
258 @Test(groups = "Functional")
259 public void testFindFeatures()
261 SequenceFeaturesI sf = new SequenceFeatures();
262 SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
263 SequenceFeature sf2 = addFeature(sf, "Pfam", 1, 15);
264 SequenceFeature sf3 = addFeature(sf, "Pfam", 20, 30);
265 SequenceFeature sf4 = addFeature(sf, "Pfam", 40, 100);
266 SequenceFeature sf5 = addFeature(sf, "Pfam", 60, 100);
267 SequenceFeature sf6 = addFeature(sf, "Pfam", 70, 70);
268 SequenceFeature sf7 = addFeature(sf, "Cath", 10, 50);
269 SequenceFeature sf8 = addFeature(sf, "Cath", 1, 15);
270 SequenceFeature sf9 = addFeature(sf, "Cath", 20, 30);
271 SequenceFeature sf10 = addFeature(sf, "Cath", 40, 100);
272 SequenceFeature sf11 = addFeature(sf, "Cath", 60, 100);
273 SequenceFeature sf12 = addFeature(sf, "Cath", 70, 70);
275 List<SequenceFeature> overlaps = sf.findFeatures(200, 200, "Pfam");
276 assertTrue(overlaps.isEmpty());
278 overlaps = sf.findFeatures( 1, 9, "Pfam");
279 assertEquals(overlaps.size(), 1);
280 assertTrue(overlaps.contains(sf2));
282 overlaps = sf.findFeatures( 5, 18, "Pfam");
283 assertEquals(overlaps.size(), 2);
284 assertTrue(overlaps.contains(sf1));
285 assertTrue(overlaps.contains(sf2));
287 overlaps = sf.findFeatures(30, 40, "Pfam");
288 assertEquals(overlaps.size(), 3);
289 assertTrue(overlaps.contains(sf1));
290 assertTrue(overlaps.contains(sf3));
291 assertTrue(overlaps.contains(sf4));
293 overlaps = sf.findFeatures( 80, 90, "Pfam");
294 assertEquals(overlaps.size(), 2);
295 assertTrue(overlaps.contains(sf4));
296 assertTrue(overlaps.contains(sf5));
298 overlaps = sf.findFeatures( 68, 70, "Pfam");
299 assertEquals(overlaps.size(), 3);
300 assertTrue(overlaps.contains(sf4));
301 assertTrue(overlaps.contains(sf5));
302 assertTrue(overlaps.contains(sf6));
304 overlaps = sf.findFeatures(16, 69, "Cath");
305 assertEquals(overlaps.size(), 4);
306 assertTrue(overlaps.contains(sf7));
307 assertFalse(overlaps.contains(sf8));
308 assertTrue(overlaps.contains(sf9));
309 assertTrue(overlaps.contains(sf10));
310 assertTrue(overlaps.contains(sf11));
311 assertFalse(overlaps.contains(sf12));
313 assertTrue(sf.findFeatures(0, 1000, "Metal").isEmpty());
315 overlaps = sf.findFeatures(7, 7, (String) null);
316 assertTrue(overlaps.isEmpty());
319 @Test(groups = "Functional")
320 public void testDelete()
322 SequenceFeaturesI sf = new SequenceFeatures();
323 SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
324 assertTrue(sf.getPositionalFeatures().contains(sf1));
326 assertFalse(sf.delete(null));
327 SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 15, 0f, null);
328 assertFalse(sf.delete(sf2)); // not added, can't delete it
329 assertTrue(sf.delete(sf1));
330 assertTrue(sf.getPositionalFeatures().isEmpty());
333 @Test(groups = "Functional")
334 public void testHasFeatures()
336 SequenceFeaturesI sf = new SequenceFeatures();
337 assertFalse(sf.hasFeatures());
339 SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
340 assertTrue(sf.hasFeatures());
343 assertFalse(sf.hasFeatures());
347 * Tests for the method that gets feature groups for positional or
348 * non-positional features
350 @Test(groups = "Functional")
351 public void testGetFeatureGroups()
353 SequenceFeaturesI sf = new SequenceFeatures();
354 assertTrue(sf.getFeatureGroups(true).isEmpty());
355 assertTrue(sf.getFeatureGroups(false).isEmpty());
358 * add a non-positional feature (begin/end = 0/0)
360 SequenceFeature sfx = new SequenceFeature("AType", "Desc", 0, 0, 0f,
363 Set<String> groups = sf.getFeatureGroups(true); // for positional
364 assertTrue(groups.isEmpty());
365 groups = sf.getFeatureGroups(false); // for non-positional
366 assertEquals(groups.size(), 1);
367 assertTrue(groups.contains("AGroup"));
368 groups = sf.getFeatureGroups(false, "AType");
369 assertEquals(groups.size(), 1);
370 assertTrue(groups.contains("AGroup"));
371 groups = sf.getFeatureGroups(true, "AnotherType");
372 assertTrue(groups.isEmpty());
375 * add, then delete, more non-positional features of different types
377 SequenceFeature sfy = new SequenceFeature("AnotherType", "Desc", 0, 0,
381 SequenceFeature sfz = new SequenceFeature("AThirdType", "Desc", 0, 0,
385 groups = sf.getFeatureGroups(false);
386 assertEquals(groups.size(), 3);
387 assertTrue(groups.contains("AGroup"));
388 assertTrue(groups.contains("AnotherGroup"));
389 assertTrue(groups.contains(null)); // null is a possible group
392 groups = sf.getFeatureGroups(false);
393 assertEquals(groups.size(), 1);
394 assertTrue(groups.contains("AGroup"));
397 * add positional features
399 SequenceFeature sf1 = new SequenceFeature("Pfam", "Desc", 10, 50, 0f,
402 groups = sf.getFeatureGroups(true);
403 assertEquals(groups.size(), 1);
404 assertTrue(groups.contains("PfamGroup"));
405 groups = sf.getFeatureGroups(false); // non-positional unchanged
406 assertEquals(groups.size(), 1);
407 assertTrue(groups.contains("AGroup"));
409 SequenceFeature sf2 = new SequenceFeature("Cath", "Desc", 10, 50, 0f,
412 groups = sf.getFeatureGroups(true);
413 assertEquals(groups.size(), 2);
414 assertTrue(groups.contains("PfamGroup"));
415 assertTrue(groups.contains(null));
419 assertTrue(sf.getFeatureGroups(true).isEmpty());
421 SequenceFeature sf3 = new SequenceFeature("CDS", "", 10, 50, 0f,
424 SequenceFeature sf4 = new SequenceFeature("exon", "", 10, 50, 0f,
427 groups = sf.getFeatureGroups(true);
428 assertEquals(groups.size(), 1);
429 assertTrue(groups.contains("Ensembl"));
432 * delete last Ensembl group feature from CDS features
433 * but still have one in exon features
436 groups = sf.getFeatureGroups(true);
437 assertEquals(groups.size(), 1);
438 assertTrue(groups.contains("Ensembl"));
441 * delete the last non-positional feature
444 groups = sf.getFeatureGroups(false);
445 assertTrue(groups.isEmpty());
448 @Test(groups = "Functional")
449 public void testGetFeatureTypesForGroups()
451 SequenceFeaturesI sf = new SequenceFeatures();
452 assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
455 * add feature with group = "Uniprot", type = "helix"
457 String groupUniprot = "Uniprot";
458 SequenceFeature sf1 = new SequenceFeature("helix", "Desc", 10, 50, 0f,
461 Set<String> groups = sf.getFeatureTypesForGroups(true, groupUniprot);
462 assertEquals(groups.size(), 1);
463 assertTrue(groups.contains("helix"));
464 assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
467 * add feature with group = "Uniprot", type = "strand"
469 SequenceFeature sf2 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
472 groups = sf.getFeatureTypesForGroups(true, groupUniprot);
473 assertEquals(groups.size(), 2);
474 assertTrue(groups.contains("helix"));
475 assertTrue(groups.contains("strand"));
478 * delete the "strand" Uniprot feature - still have "helix"
481 groups = sf.getFeatureTypesForGroups(true, groupUniprot);
482 assertEquals(groups.size(), 1);
483 assertTrue(groups.contains("helix"));
486 * delete the "helix" Uniprot feature - none left
489 assertTrue(sf.getFeatureTypesForGroups(true, groupUniprot).isEmpty());
492 * add some null group features
494 SequenceFeature sf3 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
497 SequenceFeature sf4 = new SequenceFeature("turn", "Desc", 10, 50, 0f,
500 groups = sf.getFeatureTypesForGroups(true, (String) null);
501 assertEquals(groups.size(), 2);
502 assertTrue(groups.contains("strand"));
503 assertTrue(groups.contains("turn"));
506 * add strand/Cath and turn/Scop and query for one or both groups
507 * (find feature types for groups selected in Feature Settings)
509 SequenceFeature sf5 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
512 SequenceFeature sf6 = new SequenceFeature("turn", "Desc", 10, 50, 0f,
515 groups = sf.getFeatureTypesForGroups(true, "Cath");
516 assertEquals(groups.size(), 1);
517 assertTrue(groups.contains("strand"));
518 groups = sf.getFeatureTypesForGroups(true, "Scop");
519 assertEquals(groups.size(), 1);
520 assertTrue(groups.contains("turn"));
521 groups = sf.getFeatureTypesForGroups(true, "Cath", "Scop");
522 assertEquals(groups.size(), 2);
523 assertTrue(groups.contains("turn"));
524 assertTrue(groups.contains("strand"));
525 // alternative vararg syntax
526 groups = sf.getFeatureTypesForGroups(true, new String[] { "Cath",
528 assertEquals(groups.size(), 2);
529 assertTrue(groups.contains("turn"));
530 assertTrue(groups.contains("strand"));
533 @Test(groups = "Functional")
534 public void testGetFeatureTypes()
536 SequenceFeaturesI store = new SequenceFeatures();
537 Set<String> types = store.getFeatureTypes();
538 assertTrue(types.isEmpty());
540 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
543 types = store.getFeatureTypes();
544 assertEquals(types.size(), 1);
545 assertTrue(types.contains("Metal"));
547 // null type is rejected...
548 SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20,
550 assertFalse(store.add(sf2));
551 types = store.getFeatureTypes();
552 assertEquals(types.size(), 1);
553 assertFalse(types.contains(null));
554 assertTrue(types.contains("Metal"));
557 * add non-positional feature
559 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
562 types = store.getFeatureTypes();
563 assertEquals(types.size(), 2);
564 assertTrue(types.contains("Pfam"));
567 * add contact feature
569 SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc",
570 10, 20, Float.NaN, null);
572 types = store.getFeatureTypes();
573 assertEquals(types.size(), 3);
574 assertTrue(types.contains("Disulphide Bond"));
579 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
582 types = store.getFeatureTypes();
583 assertEquals(types.size(), 3); // unchanged
586 * delete first Pfam - still have one
588 assertTrue(store.delete(sf3));
589 types = store.getFeatureTypes();
590 assertEquals(types.size(), 3);
591 assertTrue(types.contains("Pfam"));
594 * delete second Pfam - no longer have one
596 assertTrue(store.delete(sf5));
597 types = store.getFeatureTypes();
598 assertEquals(types.size(), 2);
599 assertFalse(types.contains("Pfam"));
602 @Test(groups = "Functional")
603 public void testGetFeatureCount()
605 SequenceFeaturesI store = new SequenceFeatures();
606 assertEquals(store.getFeatureCount(true), 0);
607 assertEquals(store.getFeatureCount(false), 0);
612 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
615 assertEquals(store.getFeatureCount(true), 1);
616 assertEquals(store.getFeatureCount(false), 0);
619 * null feature type is rejected
621 SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20,
623 assertFalse(store.add(sf2));
624 assertEquals(store.getFeatureCount(true), 1);
625 assertEquals(store.getFeatureCount(false), 0);
628 * add non-positional feature
630 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
633 assertEquals(store.getFeatureCount(true), 1);
634 assertEquals(store.getFeatureCount(false), 1);
637 * add contact feature (counts as 1)
639 SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc",
640 10, 20, Float.NaN, null);
642 assertEquals(store.getFeatureCount(true), 2);
643 assertEquals(store.getFeatureCount(false), 1);
646 * add another Pfam but this time as a positional feature
648 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
651 assertEquals(store.getFeatureCount(true), 3); // sf1, sf4, sf5
652 assertEquals(store.getFeatureCount(false), 1); // sf3
653 assertEquals(store.getFeatureCount(true, "Pfam"), 1); // positional
654 assertEquals(store.getFeatureCount(false, "Pfam"), 1); // non-positional
655 // search for type==null
656 assertEquals(store.getFeatureCount(true, (String) null), 0);
657 // search with no type specified
658 assertEquals(store.getFeatureCount(true, (String[]) null), 3);
659 assertEquals(store.getFeatureCount(true, "Metal", "Cath"), 1);
660 assertEquals(store.getFeatureCount(true, "Disulphide Bond"), 1);
661 assertEquals(store.getFeatureCount(true, "Metal", "Pfam", null), 2);
664 * delete first Pfam (non-positional)
666 assertTrue(store.delete(sf3));
667 assertEquals(store.getFeatureCount(true), 3);
668 assertEquals(store.getFeatureCount(false), 0);
671 * delete second Pfam (positional)
673 assertTrue(store.delete(sf5));
674 assertEquals(store.getFeatureCount(true), 2);
675 assertEquals(store.getFeatureCount(false), 0);
678 @Test(groups = "Functional")
679 public void testGetAllFeatures()
681 SequenceFeaturesI store = new SequenceFeatures();
682 List<SequenceFeature> features = store.getAllFeatures();
683 assertTrue(features.isEmpty());
685 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
688 features = store.getAllFeatures();
689 assertEquals(features.size(), 1);
690 assertTrue(features.contains(sf1));
692 SequenceFeature sf2 = new SequenceFeature("Metallic", "desc", 10, 20,
695 features = store.getAllFeatures();
696 assertEquals(features.size(), 2);
697 assertTrue(features.contains(sf2));
700 * add non-positional feature
702 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
705 features = store.getAllFeatures();
706 assertEquals(features.size(), 3);
707 assertTrue(features.contains(sf3));
710 * add contact feature
712 SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc",
713 10, 20, Float.NaN, null);
715 features = store.getAllFeatures();
716 assertEquals(features.size(), 4);
717 assertTrue(features.contains(sf4));
722 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
725 features = store.getAllFeatures();
726 assertEquals(features.size(), 5);
727 assertTrue(features.contains(sf5));
730 * select by type does not apply to non-positional features
732 features = store.getAllFeatures("Cath");
733 assertEquals(features.size(), 1);
734 assertTrue(features.contains(sf3));
736 features = store.getAllFeatures("Pfam", "Cath", "Metal");
737 assertEquals(features.size(), 3);
738 assertTrue(features.contains(sf1));
739 assertTrue(features.contains(sf3));
740 assertTrue(features.contains(sf5));
745 assertTrue(store.delete(sf3));
746 features = store.getAllFeatures();
747 assertEquals(features.size(), 4);
748 assertFalse(features.contains(sf3));
753 assertTrue(store.delete(sf5));
754 features = store.getAllFeatures();
755 assertEquals(features.size(), 3);
756 assertFalse(features.contains(sf3));
759 @Test(groups = "Functional")
760 public void testGetTotalFeatureLength()
762 SequenceFeaturesI store = new SequenceFeatures();
763 assertEquals(store.getTotalFeatureLength(), 0);
765 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
767 assertTrue(store.add(sf1));
768 assertEquals(store.getTotalFeatureLength(), 11);
769 assertEquals(store.getTotalFeatureLength("Metal"), 11);
770 assertEquals(store.getTotalFeatureLength("Plastic"), 0);
772 // re-add does nothing!
773 assertFalse(store.add(sf1));
774 assertEquals(store.getTotalFeatureLength(), 11);
777 * add non-positional feature
779 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
782 assertEquals(store.getTotalFeatureLength(), 11);
785 * add contact feature - counts 1 to feature length
787 SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc",
788 10, 20, Float.NaN, null);
790 assertEquals(store.getTotalFeatureLength(), 12);
795 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
798 assertEquals(store.getTotalFeatureLength(), 23);
803 assertTrue(store.delete(sf3)); // non-positional
804 assertEquals(store.getTotalFeatureLength(), 23); // no change
806 assertTrue(store.delete(sf5));
807 assertEquals(store.getTotalFeatureLength(), 12);
809 assertTrue(store.delete(sf4)); // contact
810 assertEquals(store.getTotalFeatureLength(), 11);
812 assertTrue(store.delete(sf1));
813 assertEquals(store.getTotalFeatureLength(), 0);
816 @Test(groups = "Functional")
817 public void testGetMinimumScore_getMaximumScore()
819 SequenceFeatures sf = new SequenceFeatures();
820 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 0, 0,
821 Float.NaN, "group"); // non-positional, no score
823 SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 10, 20,
824 Float.NaN, "group"); // positional, no score
826 SequenceFeature sf3 = new SequenceFeature("Metal", "desc", 10, 20, 1f,
829 SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 12, 16, 4f,
832 SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 0, 0, 11f,
835 SequenceFeature sf6 = new SequenceFeature("Cath", "desc", 0, 0, -7f,
839 assertEquals(sf.getMinimumScore("nosuchtype", true), Float.NaN);
840 assertEquals(sf.getMinimumScore("nosuchtype", false), Float.NaN);
841 assertEquals(sf.getMaximumScore("nosuchtype", true), Float.NaN);
842 assertEquals(sf.getMaximumScore("nosuchtype", false), Float.NaN);
844 // positional features min-max:
845 assertEquals(sf.getMinimumScore("Metal", true), 1f);
846 assertEquals(sf.getMaximumScore("Metal", true), 4f);
847 assertEquals(sf.getMinimumScore("Cath", true), Float.NaN);
848 assertEquals(sf.getMaximumScore("Cath", true), Float.NaN);
850 // non-positional features min-max:
851 assertEquals(sf.getMinimumScore("Cath", false), -7f);
852 assertEquals(sf.getMaximumScore("Cath", false), 11f);
853 assertEquals(sf.getMinimumScore("Metal", false), Float.NaN);
854 assertEquals(sf.getMaximumScore("Metal", false), Float.NaN);
856 // delete features; min-max should get recomputed
858 assertEquals(sf.getMinimumScore("Cath", false), 11f);
859 assertEquals(sf.getMaximumScore("Cath", false), 11f);
861 assertEquals(sf.getMinimumScore("Metal", true), 1f);
862 assertEquals(sf.getMaximumScore("Metal", true), 1f);
864 assertEquals(sf.getMinimumScore("Cath", false), Float.NaN);
865 assertEquals(sf.getMaximumScore("Cath", false), Float.NaN);
867 assertEquals(sf.getMinimumScore("Metal", true), Float.NaN);
868 assertEquals(sf.getMaximumScore("Metal", true), Float.NaN);
871 assertFalse(sf.hasFeatures());
872 assertEquals(sf.getMinimumScore("Cath", false), Float.NaN);
873 assertEquals(sf.getMaximumScore("Cath", false), Float.NaN);
874 assertEquals(sf.getMinimumScore("Metal", true), Float.NaN);
875 assertEquals(sf.getMaximumScore("Metal", true), Float.NaN);
878 @Test(groups = "Functional")
879 public void testVarargsToTypes()
881 SequenceFeatures sf = new SequenceFeatures();
882 sf.add(new SequenceFeature("Metal", "desc", 0, 0, Float.NaN, "group"));
883 sf.add(new SequenceFeature("Cath", "desc", 10, 20, Float.NaN, "group"));
886 * no type specified - get all types stored
887 * they are returned in keyset (alphabetical) order
889 Iterable<String> types = sf.varargToTypes();
890 Iterator<String> iterator = types.iterator();
891 assertTrue(iterator.hasNext());
892 assertEquals(iterator.next(), "Cath");
893 assertTrue(iterator.hasNext());
894 assertEquals(iterator.next(), "Metal");
895 assertFalse(iterator.hasNext());
898 * empty array is the same as no vararg parameter supplied
899 * so treated as all stored types
901 types = sf.varargToTypes(new String[] {});
902 iterator = types.iterator();
903 assertTrue(iterator.hasNext());
904 assertEquals(iterator.next(), "Cath");
905 assertTrue(iterator.hasNext());
906 assertEquals(iterator.next(), "Metal");
907 assertFalse(iterator.hasNext());
910 * null type specified; this is passed as vararg
913 types = sf.varargToTypes((String) null);
914 assertFalse(types.iterator().hasNext());
917 * null types array specified; this is passed as vararg null
919 types = sf.varargToTypes((String[]) null);
920 iterator = types.iterator();
921 assertTrue(iterator.hasNext());
922 assertEquals(iterator.next(), "Cath");
923 assertTrue(iterator.hasNext());
924 assertEquals(iterator.next(), "Metal");
925 assertFalse(iterator.hasNext());
930 types = sf.varargToTypes("Metal");
931 iterator = types.iterator();
932 assertTrue(iterator.hasNext());
933 assertEquals(iterator.next(), "Metal");
934 assertFalse(iterator.hasNext());
937 * two types specified - get sorted alphabetically
939 types = sf.varargToTypes("Metal", "Helix");
940 iterator = types.iterator();
941 assertTrue(iterator.hasNext());
942 assertEquals(iterator.next(), "Helix");
943 assertTrue(iterator.hasNext());
944 assertEquals(iterator.next(), "Metal");
945 assertFalse(iterator.hasNext());
948 * null type included - should get removed
950 types = sf.varargToTypes("Metal", null, "Helix");
951 iterator = types.iterator();
952 assertTrue(iterator.hasNext());
953 assertEquals(iterator.next(), "Helix");
954 assertTrue(iterator.hasNext());
955 assertEquals(iterator.next(), "Metal");
956 assertFalse(iterator.hasNext());
959 @Test(groups = "Functional")
960 public void testGetFeatureTypes_byOntology()
962 SequenceFeaturesI store = new SequenceFeatures();
964 SequenceFeature sf1 = new SequenceFeature("transcript", "desc", 10, 20,
967 // mRNA isA mature_transcript isA transcript
968 SequenceFeature sf2 = new SequenceFeature("mRNA", "desc", 10, 20,
971 // just to prove non-positional feature types are included
972 SequenceFeature sf3 = new SequenceFeature("mRNA", "desc", 0, 0,
975 SequenceFeature sf4 = new SequenceFeature("CDS", "desc", 0, 0,
979 Set<String> types = store.getFeatureTypes("transcript");
980 assertEquals(types.size(), 2);
981 assertTrue(types.contains("transcript"));
982 assertTrue(types.contains("mRNA"));
984 // matches include arguments whether SO terms or not
985 types = store.getFeatureTypes("transcript", "CDS");
986 assertEquals(types.size(), 3);
987 assertTrue(types.contains("transcript"));
988 assertTrue(types.contains("mRNA"));
989 assertTrue(types.contains("CDS"));
991 types = store.getFeatureTypes("exon");
992 assertTrue(types.isEmpty());
995 @Test(groups = "Functional")
996 public void testGetFeaturesByOntology()
998 SequenceFeaturesI store = new SequenceFeatures();
999 List<SequenceFeature> features = store.getFeaturesByOntology();
1000 assertTrue(features.isEmpty());
1001 assertTrue(store.getFeaturesByOntology(new String[] {}).isEmpty());
1002 assertTrue(store.getFeaturesByOntology((String[]) null).isEmpty());
1004 SequenceFeature sf1 = new SequenceFeature("transcript", "desc", 10, 20,
1008 // mRNA isA transcript; added here 'as if' non-positional
1009 // just to show that non-positional features are included in results
1010 SequenceFeature sf2 = new SequenceFeature("mRNA", "desc", 0, 0,
1014 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 30, 40,
1018 features = store.getFeaturesByOntology("transcript");
1019 assertEquals(features.size(), 2);
1020 assertTrue(features.contains(sf1));
1021 assertTrue(features.contains(sf2));
1023 features = store.getFeaturesByOntology("mRNA");
1024 assertEquals(features.size(), 1);
1025 assertTrue(features.contains(sf2));
1027 features = store.getFeaturesByOntology("mRNA", "Pfam");
1028 assertEquals(features.size(), 2);
1029 assertTrue(features.contains(sf2));
1030 assertTrue(features.contains(sf3));
1033 @Test(groups = "Functional")
1034 public void testSortFeatures()
1036 List<SequenceFeature> sfs = new ArrayList<SequenceFeature>();
1037 SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 30, 80,
1040 SequenceFeature sf2 = new SequenceFeature("Rfam", "desc", 40, 50,
1043 SequenceFeature sf3 = new SequenceFeature("Rfam", "desc", 50, 60,
1047 // sort by end position descending
1048 SequenceFeatures.sortFeatures(sfs, false);
1049 assertSame(sfs.get(0), sf1);
1050 assertSame(sfs.get(1), sf3);
1051 assertSame(sfs.get(2), sf2);
1053 // sort by start position ascending
1054 SequenceFeatures.sortFeatures(sfs, true);
1055 assertSame(sfs.get(0), sf1);
1056 assertSame(sfs.get(1), sf2);
1057 assertSame(sfs.get(2), sf3);
1060 @Test(groups = "Functional")
1061 public void testGetFeaturesForGroup()
1063 SequenceFeaturesI store = new SequenceFeatures();
1065 List<SequenceFeature> features = store.getFeaturesForGroup(true, null);
1066 assertTrue(features.isEmpty());
1067 assertTrue(store.getFeaturesForGroup(false, null).isEmpty());
1068 assertTrue(store.getFeaturesForGroup(true, "Uniprot").isEmpty());
1069 assertTrue(store.getFeaturesForGroup(false, "Uniprot").isEmpty());
1071 SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
1073 SequenceFeature sf2 = new SequenceFeature("Pfam", "desc", 0, 0, 0f,
1075 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
1077 SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 0, 0, 0f,
1079 SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 5, 15, 0f,
1087 // positional features for null group, any type
1088 features = store.getFeaturesForGroup(true, null);
1089 assertEquals(features.size(), 2);
1090 assertTrue(features.contains(sf1));
1091 assertTrue(features.contains(sf5));
1093 // positional features for null group, specified type
1094 features = store.getFeaturesForGroup(true, null, new String[] { "Pfam",
1096 assertEquals(features.size(), 1);
1097 assertTrue(features.contains(sf1));
1098 features = store.getFeaturesForGroup(true, null, new String[] { "Pfam",
1100 assertEquals(features.size(), 2);
1101 assertTrue(features.contains(sf1));
1102 assertTrue(features.contains(sf5));
1104 // positional features for non-null group, any type
1105 features = store.getFeaturesForGroup(true, "Uniprot");
1106 assertEquals(features.size(), 1);
1107 assertTrue(features.contains(sf3));
1108 assertTrue(store.getFeaturesForGroup(true, "Rfam").isEmpty());
1110 // positional features for non-null group, specified type
1111 features = store.getFeaturesForGroup(true, "Uniprot", "Pfam", "Xfam",
1113 assertEquals(features.size(), 1);
1114 assertTrue(features.contains(sf3));
1115 assertTrue(store.getFeaturesForGroup(true, "Uniprot", "Cath").isEmpty());
1117 // non-positional features for null group, any type
1118 features = store.getFeaturesForGroup(false, null);
1119 assertEquals(features.size(), 1);
1120 assertTrue(features.contains(sf2));
1122 // non-positional features for null group, specified type
1123 features = store.getFeaturesForGroup(false, null, "Pfam", "Xfam");
1124 assertEquals(features.size(), 1);
1125 assertTrue(features.contains(sf2));
1126 assertTrue(store.getFeaturesForGroup(false, null, "Cath").isEmpty());
1128 // non-positional features for non-null group, any type
1129 features = store.getFeaturesForGroup(false, "Rfam");
1130 assertEquals(features.size(), 1);
1131 assertTrue(features.contains(sf4));
1132 assertTrue(store.getFeaturesForGroup(false, "Uniprot").isEmpty());
1134 // non-positional features for non-null group, specified type
1135 features = store.getFeaturesForGroup(false, "Rfam", "Pfam", "Metal");
1136 assertEquals(features.size(), 1);
1137 assertTrue(features.contains(sf4));
1138 assertTrue(store.getFeaturesForGroup(false, "Rfam", "Cath", "Pfam")
1142 @Test(groups = "Functional")
1143 public void testShiftFeatures()
1145 SequenceFeatures store = new SequenceFeatures();
1146 assertFalse(store.shiftFeatures(1));
1148 SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
1151 SequenceFeature sf2 = new SequenceFeature("Metal", "", 8, 14, 0f, null);
1154 SequenceFeature sf3 = new SequenceFeature("Disulfide bond", "", 23, 32,
1157 // non-positional feature:
1158 SequenceFeature sf4 = new SequenceFeature("Pfam", "", 0, 0, 0f, null);
1162 * shift features right by 5
1164 assertTrue(store.shiftFeatures(5));
1166 // non-positional features untouched:
1167 List<SequenceFeature> nonPos = store.getNonPositionalFeatures();
1168 assertEquals(nonPos.size(), 1);
1169 assertTrue(nonPos.contains(sf4));
1171 // positional features are replaced
1172 List<SequenceFeature> pos = store.getPositionalFeatures();
1173 assertEquals(pos.size(), 3);
1174 assertFalse(pos.contains(sf1));
1175 assertFalse(pos.contains(sf2));
1176 assertFalse(pos.contains(sf3));
1177 SequenceFeatures.sortFeatures(pos, true); // ascending start pos
1178 assertEquals(pos.get(0).getBegin(), 7);
1179 assertEquals(pos.get(0).getEnd(), 10);
1180 assertEquals(pos.get(0).getType(), "Cath");
1181 assertEquals(pos.get(1).getBegin(), 13);
1182 assertEquals(pos.get(1).getEnd(), 19);
1183 assertEquals(pos.get(1).getType(), "Metal");
1184 assertEquals(pos.get(2).getBegin(), 28);
1185 assertEquals(pos.get(2).getEnd(), 37);
1186 assertEquals(pos.get(2).getType(), "Disulfide bond");
1189 * now shift left by 15
1190 * feature at [7-10] should be removed
1191 * feature at [13-19] should become [1-4]
1193 assertTrue(store.shiftFeatures(-15));
1194 pos = store.getPositionalFeatures();
1195 assertEquals(pos.size(), 2);
1196 SequenceFeatures.sortFeatures(pos, true);
1197 assertEquals(pos.get(0).getBegin(), 1);
1198 assertEquals(pos.get(0).getEnd(), 4);
1199 assertEquals(pos.get(0).getType(), "Metal");
1200 assertEquals(pos.get(1).getBegin(), 13);
1201 assertEquals(pos.get(1).getEnd(), 22);
1202 assertEquals(pos.get(1).getType(), "Disulfide bond");
1205 @Test(groups = "Functional")
1206 public void testIsOntologyTerm()
1208 SequenceFeatures store = new SequenceFeatures();
1209 assertTrue(store.isOntologyTerm("gobbledygook"));
1210 assertTrue(store.isOntologyTerm("transcript", "transcript"));
1211 assertTrue(store.isOntologyTerm("mRNA", "transcript"));
1212 assertFalse(store.isOntologyTerm("transcript", "mRNA"));
1213 assertTrue(store.isOntologyTerm("junk", "transcript", "junk"));
1214 assertTrue(store.isOntologyTerm("junk", new String[] {}));
1215 assertTrue(store.isOntologyTerm("junk", (String[]) null));