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 java.util.ArrayList;
9 import java.util.Iterator;
10 import java.util.List;
14 import org.testng.annotations.Test;
16 import jalview.datamodel.SequenceFeature;
17 import junit.extensions.PA;
19 public class SequenceFeaturesTest
21 @Test(groups = "Functional")
22 public void testConstructor()
24 SequenceFeaturesI store = new SequenceFeatures();
25 assertFalse(store.hasFeatures());
27 store = new SequenceFeatures((List<SequenceFeature>) null);
28 assertFalse(store.hasFeatures());
30 List<SequenceFeature> features = new ArrayList<>();
31 store = new SequenceFeatures(features);
32 assertFalse(store.hasFeatures());
34 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
37 SequenceFeature sf2 = new SequenceFeature("Metal", "desc", 15, 18,
39 features.add(sf2); // nested
40 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc2", 0, 0,
41 Float.NaN, null); // non-positional
43 store = new SequenceFeatures(features);
44 assertTrue(store.hasFeatures());
45 assertEquals(2, store.getFeatureCount(true)); // positional
46 assertEquals(1, store.getFeatureCount(false)); // non-positional
47 assertFalse(store.add(sf1)); // already contained
48 assertFalse(store.add(sf2)); // already contained
49 assertFalse(store.add(sf3)); // already contained
52 @Test(groups = "Functional")
53 public void testGetPositionalFeatures()
55 SequenceFeaturesI store = new SequenceFeatures();
56 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
59 // same range, different description
60 SequenceFeature sf2 = new SequenceFeature("Metal", "desc2", 10, 20,
63 // discontiguous range
64 SequenceFeature sf3 = new SequenceFeature("Metal", "desc", 30, 40,
68 SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 15, 35,
72 SequenceFeature sf5 = new SequenceFeature("Metal", "desc", 5, 50,
75 // non-positional feature
76 SequenceFeature sf6 = new SequenceFeature("Metal", "desc", 0, 0,
80 SequenceFeature sf7 = new SequenceFeature("Disulphide bond", "desc", 18,
83 // different feature type
84 SequenceFeature sf8 = new SequenceFeature("Pfam", "desc", 30, 40,
87 SequenceFeature sf9 = new SequenceFeature("Pfam", "desc", 15, 35,
92 * get all positional features
94 List<SequenceFeature> features = store.getPositionalFeatures();
95 assertEquals(features.size(), 8);
96 assertTrue(features.contains(sf1));
97 assertTrue(features.contains(sf2));
98 assertTrue(features.contains(sf3));
99 assertTrue(features.contains(sf4));
100 assertTrue(features.contains(sf5));
101 assertFalse(features.contains(sf6)); // non-positional
102 assertTrue(features.contains(sf7));
103 assertTrue(features.contains(sf8));
104 assertTrue(features.contains(sf9));
107 * get features by type
109 assertTrue(store.getPositionalFeatures((String) null).isEmpty());
110 assertTrue(store.getPositionalFeatures("Cath").isEmpty());
111 assertTrue(store.getPositionalFeatures("METAL").isEmpty());
113 features = store.getPositionalFeatures("Metal");
114 assertEquals(features.size(), 5);
115 assertTrue(features.contains(sf1));
116 assertTrue(features.contains(sf2));
117 assertTrue(features.contains(sf3));
118 assertTrue(features.contains(sf4));
119 assertTrue(features.contains(sf5));
120 assertFalse(features.contains(sf6));
122 features = store.getPositionalFeatures("Disulphide bond");
123 assertEquals(features.size(), 1);
124 assertTrue(features.contains(sf7));
126 features = store.getPositionalFeatures("Pfam");
127 assertEquals(features.size(), 2);
128 assertTrue(features.contains(sf8));
129 assertTrue(features.contains(sf9));
132 @Test(groups = "Functional")
133 public void testGetContactFeatures()
135 SequenceFeaturesI store = new SequenceFeatures();
137 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
141 SequenceFeature sf2 = new SequenceFeature("Metal", "desc", 0, 0,
145 SequenceFeature sf3 = new SequenceFeature("Disulphide bond", "desc", 18,
146 45, Float.NaN, null);
148 // repeat for different feature type
149 SequenceFeature sf4 = new SequenceFeature("Pfam", "desc", 10, 20,
152 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 0, 0,
155 SequenceFeature sf6 = new SequenceFeature("Disulfide bond", "desc", 18,
156 45, Float.NaN, null);
160 * get all contact features
162 List<SequenceFeature> features = store.getContactFeatures();
163 assertEquals(features.size(), 2);
164 assertTrue(features.contains(sf3));
165 assertTrue(features.contains(sf6));
168 * get contact features by type
170 assertTrue(store.getContactFeatures((String) null).isEmpty());
171 assertTrue(store.getContactFeatures("Cath").isEmpty());
172 assertTrue(store.getContactFeatures("Pfam").isEmpty());
173 assertTrue(store.getContactFeatures("DISULPHIDE BOND").isEmpty());
175 features = store.getContactFeatures("Disulphide bond");
176 assertEquals(features.size(), 1);
177 assertTrue(features.contains(sf3));
179 features = store.getContactFeatures("Disulfide bond");
180 assertEquals(features.size(), 1);
181 assertTrue(features.contains(sf6));
184 @Test(groups = "Functional")
185 public void testGetNonPositionalFeatures()
187 SequenceFeaturesI store = new SequenceFeatures();
189 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
193 SequenceFeature sf2 = new SequenceFeature("Metal", "desc", 0, 0,
197 SequenceFeature sf3 = new SequenceFeature("Disulphide bond", "desc", 18,
198 45, Float.NaN, null);
200 // repeat for different feature type
201 SequenceFeature sf4 = new SequenceFeature("Pfam", "desc", 10, 20,
204 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 0, 0,
207 SequenceFeature sf6 = new SequenceFeature("Disulfide bond", "desc", 18,
208 45, Float.NaN, null);
210 // one more non-positional, different description
211 SequenceFeature sf7 = new SequenceFeature("Pfam", "desc2", 0, 0,
216 * get all non-positional features
218 List<SequenceFeature> features = store.getNonPositionalFeatures();
219 assertEquals(features.size(), 3);
220 assertTrue(features.contains(sf2));
221 assertTrue(features.contains(sf5));
222 assertTrue(features.contains(sf7));
225 * get non-positional features by type
227 assertTrue(store.getNonPositionalFeatures((String) null).isEmpty());
228 assertTrue(store.getNonPositionalFeatures("Cath").isEmpty());
229 assertTrue(store.getNonPositionalFeatures("PFAM").isEmpty());
231 features = store.getNonPositionalFeatures("Metal");
232 assertEquals(features.size(), 1);
233 assertTrue(features.contains(sf2));
235 features = store.getNonPositionalFeatures("Pfam");
236 assertEquals(features.size(), 2);
237 assertTrue(features.contains(sf5));
238 assertTrue(features.contains(sf7));
242 * Helper method to add a feature of no particular type
250 SequenceFeature addFeature(SequenceFeaturesI sf, String type, int from,
253 SequenceFeature sf1 = new SequenceFeature(type, "", from, to, Float.NaN,
259 @Test(groups = "Functional")
260 public void testFindFeatures()
262 SequenceFeaturesI sf = new SequenceFeatures();
263 SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
264 SequenceFeature sf2 = addFeature(sf, "Pfam", 1, 15);
265 SequenceFeature sf3 = addFeature(sf, "Pfam", 20, 30);
266 SequenceFeature sf4 = addFeature(sf, "Pfam", 40, 100);
267 SequenceFeature sf5 = addFeature(sf, "Pfam", 60, 100);
268 SequenceFeature sf6 = addFeature(sf, "Pfam", 70, 70);
269 SequenceFeature sf7 = addFeature(sf, "Cath", 10, 50);
270 SequenceFeature sf8 = addFeature(sf, "Cath", 1, 15);
271 SequenceFeature sf9 = addFeature(sf, "Cath", 20, 30);
272 SequenceFeature sf10 = addFeature(sf, "Cath", 40, 100);
273 SequenceFeature sf11 = addFeature(sf, "Cath", 60, 100);
274 SequenceFeature sf12 = addFeature(sf, "Cath", 70, 70);
276 List<SequenceFeature> overlaps = sf.findFeatures(200, 200, "Pfam");
277 assertTrue(overlaps.isEmpty());
279 overlaps = sf.findFeatures(1, 9, "Pfam");
280 assertEquals(overlaps.size(), 1);
281 assertTrue(overlaps.contains(sf2));
283 overlaps = sf.findFeatures(5, 18, "Pfam");
284 assertEquals(overlaps.size(), 2);
285 assertTrue(overlaps.contains(sf1));
286 assertTrue(overlaps.contains(sf2));
288 overlaps = sf.findFeatures(30, 40, "Pfam");
289 assertEquals(overlaps.size(), 3);
290 assertTrue(overlaps.contains(sf1));
291 assertTrue(overlaps.contains(sf3));
292 assertTrue(overlaps.contains(sf4));
294 overlaps = sf.findFeatures(80, 90, "Pfam");
295 assertEquals(overlaps.size(), 2);
296 assertTrue(overlaps.contains(sf4));
297 assertTrue(overlaps.contains(sf5));
299 overlaps = sf.findFeatures(68, 70, "Pfam");
300 assertEquals(overlaps.size(), 3);
301 assertTrue(overlaps.contains(sf4));
302 assertTrue(overlaps.contains(sf5));
303 assertTrue(overlaps.contains(sf6));
305 overlaps = sf.findFeatures(16, 69, "Cath");
306 assertEquals(overlaps.size(), 4);
307 assertTrue(overlaps.contains(sf7));
308 assertFalse(overlaps.contains(sf8));
309 assertTrue(overlaps.contains(sf9));
310 assertTrue(overlaps.contains(sf10));
311 assertTrue(overlaps.contains(sf11));
312 assertFalse(overlaps.contains(sf12));
314 assertTrue(sf.findFeatures(0, 1000, "Metal").isEmpty());
316 overlaps = sf.findFeatures(7, 7, (String) null);
317 assertTrue(overlaps.isEmpty());
320 @Test(groups = "Functional")
321 public void testDelete()
323 SequenceFeaturesI sf = new SequenceFeatures();
324 SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
325 assertTrue(sf.getPositionalFeatures().contains(sf1));
327 assertFalse(sf.delete(null));
328 SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 15, 0f, null);
329 assertFalse(sf.delete(sf2)); // not added, can't delete it
330 assertTrue(sf.delete(sf1));
331 assertTrue(sf.getPositionalFeatures().isEmpty());
334 @Test(groups = "Functional")
335 public void testHasFeatures()
337 SequenceFeaturesI sf = new SequenceFeatures();
338 assertFalse(sf.hasFeatures());
340 SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
341 assertTrue(sf.hasFeatures());
344 assertFalse(sf.hasFeatures());
348 * Tests for the method that gets feature groups for positional or
349 * non-positional features
351 @Test(groups = "Functional")
352 public void testGetFeatureGroups()
354 SequenceFeaturesI sf = new SequenceFeatures();
355 assertTrue(sf.getFeatureGroups(true).isEmpty());
356 assertTrue(sf.getFeatureGroups(false).isEmpty());
359 * add a non-positional feature (begin/end = 0/0)
361 SequenceFeature sfx = new SequenceFeature("AType", "Desc", 0, 0, 0f,
364 Set<String> groups = sf.getFeatureGroups(true); // for positional
365 assertTrue(groups.isEmpty());
366 groups = sf.getFeatureGroups(false); // for non-positional
367 assertEquals(groups.size(), 1);
368 assertTrue(groups.contains("AGroup"));
369 groups = sf.getFeatureGroups(false, "AType");
370 assertEquals(groups.size(), 1);
371 assertTrue(groups.contains("AGroup"));
372 groups = sf.getFeatureGroups(true, "AnotherType");
373 assertTrue(groups.isEmpty());
376 * add, then delete, more non-positional features of different types
378 SequenceFeature sfy = new SequenceFeature("AnotherType", "Desc", 0, 0,
381 SequenceFeature sfz = new SequenceFeature("AThirdType", "Desc", 0, 0,
384 groups = sf.getFeatureGroups(false);
385 assertEquals(groups.size(), 3);
386 assertTrue(groups.contains("AGroup"));
387 assertTrue(groups.contains("AnotherGroup"));
388 assertTrue(groups.contains(null)); // null is a possible group
391 groups = sf.getFeatureGroups(false);
392 assertEquals(groups.size(), 1);
393 assertTrue(groups.contains("AGroup"));
396 * add positional features
398 SequenceFeature sf1 = new SequenceFeature("Pfam", "Desc", 10, 50, 0f,
401 groups = sf.getFeatureGroups(true);
402 assertEquals(groups.size(), 1);
403 assertTrue(groups.contains("PfamGroup"));
404 groups = sf.getFeatureGroups(false); // non-positional unchanged
405 assertEquals(groups.size(), 1);
406 assertTrue(groups.contains("AGroup"));
408 SequenceFeature sf2 = new SequenceFeature("Cath", "Desc", 10, 50, 0f,
411 groups = sf.getFeatureGroups(true);
412 assertEquals(groups.size(), 2);
413 assertTrue(groups.contains("PfamGroup"));
414 assertTrue(groups.contains(null));
418 assertTrue(sf.getFeatureGroups(true).isEmpty());
420 SequenceFeature sf3 = new SequenceFeature("CDS", "", 10, 50, 0f,
423 SequenceFeature sf4 = new SequenceFeature("exon", "", 10, 50, 0f,
426 groups = sf.getFeatureGroups(true);
427 assertEquals(groups.size(), 1);
428 assertTrue(groups.contains("Ensembl"));
431 * delete last Ensembl group feature from CDS features
432 * but still have one in exon features
435 groups = sf.getFeatureGroups(true);
436 assertEquals(groups.size(), 1);
437 assertTrue(groups.contains("Ensembl"));
440 * delete the last non-positional feature
443 groups = sf.getFeatureGroups(false);
444 assertTrue(groups.isEmpty());
447 @Test(groups = "Functional")
448 public void testGetFeatureTypesForGroups()
450 SequenceFeaturesI sf = new SequenceFeatures();
451 assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
454 * add feature with group = "Uniprot", type = "helix"
456 String groupUniprot = "Uniprot";
457 SequenceFeature sf1 = new SequenceFeature("helix", "Desc", 10, 50, 0f,
460 Set<String> groups = sf.getFeatureTypesForGroups(true, groupUniprot);
461 assertEquals(groups.size(), 1);
462 assertTrue(groups.contains("helix"));
463 assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
466 * add feature with group = "Uniprot", type = "strand"
468 SequenceFeature sf2 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
471 groups = sf.getFeatureTypesForGroups(true, groupUniprot);
472 assertEquals(groups.size(), 2);
473 assertTrue(groups.contains("helix"));
474 assertTrue(groups.contains("strand"));
477 * delete the "strand" Uniprot feature - still have "helix"
480 groups = sf.getFeatureTypesForGroups(true, groupUniprot);
481 assertEquals(groups.size(), 1);
482 assertTrue(groups.contains("helix"));
485 * delete the "helix" Uniprot feature - none left
488 assertTrue(sf.getFeatureTypesForGroups(true, groupUniprot).isEmpty());
491 * add some null group features
493 SequenceFeature sf3 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
496 SequenceFeature sf4 = new SequenceFeature("turn", "Desc", 10, 50, 0f,
499 groups = sf.getFeatureTypesForGroups(true, (String) null);
500 assertEquals(groups.size(), 2);
501 assertTrue(groups.contains("strand"));
502 assertTrue(groups.contains("turn"));
505 * add strand/Cath and turn/Scop and query for one or both groups
506 * (find feature types for groups selected in Feature Settings)
508 SequenceFeature sf5 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
511 SequenceFeature sf6 = new SequenceFeature("turn", "Desc", 10, 50, 0f,
514 groups = sf.getFeatureTypesForGroups(true, "Cath");
515 assertEquals(groups.size(), 1);
516 assertTrue(groups.contains("strand"));
517 groups = sf.getFeatureTypesForGroups(true, "Scop");
518 assertEquals(groups.size(), 1);
519 assertTrue(groups.contains("turn"));
520 groups = sf.getFeatureTypesForGroups(true, "Cath", "Scop");
521 assertEquals(groups.size(), 2);
522 assertTrue(groups.contains("turn"));
523 assertTrue(groups.contains("strand"));
524 // alternative vararg syntax
525 groups = sf.getFeatureTypesForGroups(true,
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", 10,
570 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", 10,
640 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", 10,
713 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", 10,
788 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 Map<String, FeatureStore> featureStores = (Map<String, FeatureStore>) PA
890 .getValue(sf, "featureStore");
892 Iterable<FeatureStore> types = sf.varargToTypes();
893 Iterator<FeatureStore> iterator = types.iterator();
894 assertTrue(iterator.hasNext());
895 assertSame(iterator.next(), featureStores.get("Cath"));
896 assertTrue(iterator.hasNext());
897 assertSame(iterator.next(), featureStores.get("Metal"));
898 assertFalse(iterator.hasNext());
901 * empty array is the same as no vararg parameter supplied
902 * so treated as all stored types
904 types = sf.varargToTypes(new String[] {});
905 iterator = types.iterator();
906 assertTrue(iterator.hasNext());
907 assertSame(iterator.next(), featureStores.get("Cath"));
908 assertTrue(iterator.hasNext());
909 assertSame(iterator.next(), featureStores.get("Metal"));
910 assertFalse(iterator.hasNext());
913 * null type specified; this is passed as vararg
916 types = sf.varargToTypes((String) null);
917 assertFalse(types.iterator().hasNext());
920 * null types array specified; this is passed as vararg null
922 types = sf.varargToTypes((String[]) null);
923 iterator = types.iterator();
924 assertTrue(iterator.hasNext());
925 assertSame(iterator.next(), featureStores.get("Cath"));
926 assertTrue(iterator.hasNext());
927 assertSame(iterator.next(), featureStores.get("Metal"));
928 assertFalse(iterator.hasNext());
933 types = sf.varargToTypes("Metal");
934 iterator = types.iterator();
935 assertTrue(iterator.hasNext());
936 assertSame(iterator.next(), featureStores.get("Metal"));
937 assertFalse(iterator.hasNext());
940 * two types specified - order is preserved
942 types = sf.varargToTypes("Metal", "Cath");
943 iterator = types.iterator();
944 assertTrue(iterator.hasNext());
945 assertSame(iterator.next(), featureStores.get("Metal"));
946 assertTrue(iterator.hasNext());
947 assertSame(iterator.next(), featureStores.get("Cath"));
948 assertFalse(iterator.hasNext());
951 * null type included - should be ignored
953 types = sf.varargToTypes("Metal", null, "Helix");
954 iterator = types.iterator();
955 assertTrue(iterator.hasNext());
956 assertSame(iterator.next(), featureStores.get("Metal"));
957 assertFalse(iterator.hasNext());
960 @Test(groups = "Functional")
961 public void testGetFeatureTypes_byOntology()
963 SequenceFeaturesI store = new SequenceFeatures();
965 SequenceFeature sf1 = new SequenceFeature("transcript", "desc", 10, 20,
968 // mRNA isA mature_transcript isA transcript
969 SequenceFeature sf2 = new SequenceFeature("mRNA", "desc", 10, 20,
972 // just to prove non-positional feature types are included
973 SequenceFeature sf3 = new SequenceFeature("mRNA", "desc", 0, 0,
976 SequenceFeature sf4 = new SequenceFeature("CDS", "desc", 0, 0,
980 Set<String> types = store.getFeatureTypes("transcript");
981 assertEquals(types.size(), 2);
982 assertTrue(types.contains("transcript"));
983 assertTrue(types.contains("mRNA"));
985 // matches include arguments whether SO terms or not
986 types = store.getFeatureTypes("transcript", "CDS");
987 assertEquals(types.size(), 3);
988 assertTrue(types.contains("transcript"));
989 assertTrue(types.contains("mRNA"));
990 assertTrue(types.contains("CDS"));
992 types = store.getFeatureTypes("exon");
993 assertTrue(types.isEmpty());
996 @Test(groups = "Functional")
997 public void testGetFeaturesByOntology()
999 SequenceFeaturesI store = new SequenceFeatures();
1000 List<SequenceFeature> features = store.getFeaturesByOntology();
1001 assertTrue(features.isEmpty());
1002 assertTrue(store.getFeaturesByOntology(new String[] {}).isEmpty());
1003 assertTrue(store.getFeaturesByOntology((String[]) null).isEmpty());
1005 SequenceFeature transcriptFeature = new SequenceFeature("transcript",
1006 "desc", 10, 20, Float.NaN, null);
1007 store.add(transcriptFeature);
1010 * mRNA is a sub-type of transcript; added here 'as if' non-positional
1011 * just to show that non-positional features are included in results
1013 SequenceFeature mrnaFeature = new SequenceFeature("mRNA", "desc", 0, 0,
1015 store.add(mrnaFeature);
1017 SequenceFeature pfamFeature = new SequenceFeature("Pfam", "desc", 30,
1018 40, Float.NaN, null);
1019 store.add(pfamFeature);
1022 * "transcript" matches both itself and the sub-term "mRNA"
1024 features = store.getFeaturesByOntology("transcript");
1025 assertEquals(features.size(), 2);
1026 assertTrue(features.contains(transcriptFeature));
1027 assertTrue(features.contains(mrnaFeature));
1030 * "mRNA" matches itself but not parent term "transcript"
1032 features = store.getFeaturesByOntology("mRNA");
1033 assertEquals(features.size(), 1);
1034 assertTrue(features.contains(mrnaFeature));
1037 * "pfam" is not an SO term but is included as an exact match
1039 features = store.getFeaturesByOntology("mRNA", "Pfam");
1040 assertEquals(features.size(), 2);
1041 assertTrue(features.contains(mrnaFeature));
1042 assertTrue(features.contains(pfamFeature));
1044 features = store.getFeaturesByOntology("sequence_variant");
1045 assertTrue(features.isEmpty());
1048 @Test(groups = "Functional")
1049 public void testSortFeatures()
1051 List<SequenceFeature> sfs = new ArrayList<>();
1052 SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 30, 60,
1055 SequenceFeature sf2 = new SequenceFeature("Rfam", "desc", 40, 50,
1058 SequenceFeature sf3 = new SequenceFeature("Rfam", "desc", 50, 60,
1061 SequenceFeature sf4 = new SequenceFeature("Xfam", "desc", 30, 80,
1064 SequenceFeature sf5 = new SequenceFeature("Xfam", "desc", 30, 90,
1069 * sort by end position descending, order unchanged if matched
1071 SequenceFeatures.sortFeatures(sfs, false);
1072 assertSame(sfs.get(0), sf5); // end 90
1073 assertSame(sfs.get(1), sf4); // end 80
1074 assertSame(sfs.get(2), sf1); // end 60, start 50
1075 assertSame(sfs.get(3), sf3); // end 60, start 30
1076 assertSame(sfs.get(4), sf2); // end 50
1079 * resort {5, 4, 1, 3, 2} by start position ascending, end descending
1081 SequenceFeatures.sortFeatures(sfs, true);
1082 assertSame(sfs.get(0), sf5); // start 30, end 90
1083 assertSame(sfs.get(1), sf4); // start 30, end 80
1084 assertSame(sfs.get(2), sf1); // start 30, end 60
1085 assertSame(sfs.get(3), sf2); // start 40
1086 assertSame(sfs.get(4), sf3); // start 50
1089 @Test(groups = "Functional")
1090 public void testGetFeaturesForGroup()
1092 SequenceFeaturesI store = new SequenceFeatures();
1094 List<SequenceFeature> features = store.getFeaturesForGroup(true, null);
1095 assertTrue(features.isEmpty());
1096 assertTrue(store.getFeaturesForGroup(false, null).isEmpty());
1097 assertTrue(store.getFeaturesForGroup(true, "Uniprot").isEmpty());
1098 assertTrue(store.getFeaturesForGroup(false, "Uniprot").isEmpty());
1100 SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
1102 SequenceFeature sf2 = new SequenceFeature("Pfam", "desc", 0, 0, 0f,
1104 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
1106 SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 0, 0, 0f,
1108 SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 5, 15, 0f,
1116 // positional features for null group, any type
1117 features = store.getFeaturesForGroup(true, null);
1118 assertEquals(features.size(), 2);
1119 assertTrue(features.contains(sf1));
1120 assertTrue(features.contains(sf5));
1122 // positional features for null group, specified type
1123 features = store.getFeaturesForGroup(true, null,
1125 { "Pfam", "Xfam" });
1126 assertEquals(features.size(), 1);
1127 assertTrue(features.contains(sf1));
1128 features = store.getFeaturesForGroup(true, null,
1130 { "Pfam", "Xfam", "Cath" });
1131 assertEquals(features.size(), 2);
1132 assertTrue(features.contains(sf1));
1133 assertTrue(features.contains(sf5));
1135 // positional features for non-null group, any type
1136 features = store.getFeaturesForGroup(true, "Uniprot");
1137 assertEquals(features.size(), 1);
1138 assertTrue(features.contains(sf3));
1139 assertTrue(store.getFeaturesForGroup(true, "Rfam").isEmpty());
1141 // positional features for non-null group, specified type
1142 features = store.getFeaturesForGroup(true, "Uniprot", "Pfam", "Xfam",
1144 assertEquals(features.size(), 1);
1145 assertTrue(features.contains(sf3));
1147 store.getFeaturesForGroup(true, "Uniprot", "Cath").isEmpty());
1149 // non-positional features for null group, any type
1150 features = store.getFeaturesForGroup(false, null);
1151 assertEquals(features.size(), 1);
1152 assertTrue(features.contains(sf2));
1154 // non-positional features for null group, specified type
1155 features = store.getFeaturesForGroup(false, null, "Pfam", "Xfam");
1156 assertEquals(features.size(), 1);
1157 assertTrue(features.contains(sf2));
1158 assertTrue(store.getFeaturesForGroup(false, null, "Cath").isEmpty());
1160 // non-positional features for non-null group, any type
1161 features = store.getFeaturesForGroup(false, "Rfam");
1162 assertEquals(features.size(), 1);
1163 assertTrue(features.contains(sf4));
1164 assertTrue(store.getFeaturesForGroup(false, "Uniprot").isEmpty());
1166 // non-positional features for non-null group, specified type
1167 features = store.getFeaturesForGroup(false, "Rfam", "Pfam", "Metal");
1168 assertEquals(features.size(), 1);
1169 assertTrue(features.contains(sf4));
1170 assertTrue(store.getFeaturesForGroup(false, "Rfam", "Cath", "Pfam")
1174 @Test(groups = "Functional")
1175 public void testShiftFeatures()
1177 SequenceFeatures store = new SequenceFeatures();
1178 assertFalse(store.shiftFeatures(0, 1));
1180 SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
1183 SequenceFeature sf2 = new SequenceFeature("Metal", "", 8, 14, 0f, null);
1186 SequenceFeature sf3 = new SequenceFeature("Disulfide bond", "", 23, 32,
1189 // non-positional feature:
1190 SequenceFeature sf4 = new SequenceFeature("Pfam", "", 0, 0, 0f, null);
1194 * shift features right by 5
1196 assertTrue(store.shiftFeatures(0, 5));
1198 // non-positional features untouched:
1199 List<SequenceFeature> nonPos = store.getNonPositionalFeatures();
1200 assertEquals(nonPos.size(), 1);
1201 assertTrue(nonPos.contains(sf4));
1203 // positional features are replaced
1204 List<SequenceFeature> pos = store.getPositionalFeatures();
1205 assertEquals(pos.size(), 3);
1206 assertFalse(pos.contains(sf1));
1207 assertFalse(pos.contains(sf2));
1208 assertFalse(pos.contains(sf3));
1209 SequenceFeatures.sortFeatures(pos, true); // ascending start pos
1210 assertEquals(pos.get(0).getBegin(), 7);
1211 assertEquals(pos.get(0).getEnd(), 10);
1212 assertEquals(pos.get(0).getType(), "Cath");
1213 assertEquals(pos.get(1).getBegin(), 13);
1214 assertEquals(pos.get(1).getEnd(), 19);
1215 assertEquals(pos.get(1).getType(), "Metal");
1216 assertEquals(pos.get(2).getBegin(), 28);
1217 assertEquals(pos.get(2).getEnd(), 37);
1218 assertEquals(pos.get(2).getType(), "Disulfide bond");
1221 * now shift left by 15
1222 * feature at [7-10] should be removed
1223 * feature at [13-19] should become [1-4]
1225 assertTrue(store.shiftFeatures(0, -15));
1226 pos = store.getPositionalFeatures();
1227 assertEquals(pos.size(), 2);
1228 SequenceFeatures.sortFeatures(pos, true);
1229 assertEquals(pos.get(0).getBegin(), 1);
1230 assertEquals(pos.get(0).getEnd(), 4);
1231 assertEquals(pos.get(0).getType(), "Metal");
1232 assertEquals(pos.get(1).getBegin(), 13);
1233 assertEquals(pos.get(1).getEnd(), 22);
1234 assertEquals(pos.get(1).getType(), "Disulfide bond");
1237 * shift right by 4 from column 2
1238 * feature at [1-4] should be unchanged
1239 * feature at [13-22] should become [17-26]
1241 assertTrue(store.shiftFeatures(2, 4));
1242 pos = store.getPositionalFeatures();
1243 assertEquals(pos.size(), 2);
1244 SequenceFeatures.sortFeatures(pos, true);
1245 assertEquals(pos.get(0).getBegin(), 1);
1246 assertEquals(pos.get(0).getEnd(), 4);
1247 assertEquals(pos.get(0).getType(), "Metal");
1248 assertEquals(pos.get(1).getBegin(), 17);
1249 assertEquals(pos.get(1).getEnd(), 26);
1250 assertEquals(pos.get(1).getType(), "Disulfide bond");
1253 * shift right from column 18
1254 * should be no updates
1256 SequenceFeature f1 = pos.get(0);
1257 SequenceFeature f2 = pos.get(1);
1258 assertFalse(store.shiftFeatures(18, 6));
1259 pos = store.getPositionalFeatures();
1260 assertEquals(pos.size(), 2);
1261 SequenceFeatures.sortFeatures(pos, true);
1262 assertSame(pos.get(0), f1);
1263 assertSame(pos.get(1), f2);
1266 @Test(groups = "Functional")
1267 public void testIsOntologyTerm()
1269 SequenceFeatures store = new SequenceFeatures();
1270 assertTrue(store.isOntologyTerm("gobbledygook"));
1271 assertTrue(store.isOntologyTerm("transcript", "transcript"));
1272 assertTrue(store.isOntologyTerm("mRNA", "transcript"));
1273 assertFalse(store.isOntologyTerm("transcript", "mRNA"));
1274 assertTrue(store.isOntologyTerm("junk", "transcript", "junk"));
1275 assertTrue(store.isOntologyTerm("junk", new String[] {}));
1276 assertTrue(store.isOntologyTerm("junk", (String[]) null));
1279 @Test(groups = "Functional")
1280 public void testDeleteAll()
1282 SequenceFeaturesI store = new SequenceFeatures();
1283 assertFalse(store.hasFeatures());
1285 assertFalse(store.hasFeatures());
1286 store.add(new SequenceFeature("Cath", "Desc", 12, 20, 0f, "Group"));
1287 store.add(new SequenceFeature("Pfam", "Desc", 6, 12, 2f, "Group2"));
1288 assertTrue(store.hasFeatures());
1290 assertFalse(store.hasFeatures());