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",
81 18, 45, Float.NaN, null);
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",
146 18, 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",
198 18, 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,
260 @Test(groups = "Functional")
261 public void testFindFeatures()
263 SequenceFeaturesI sf = new SequenceFeatures();
264 SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
265 SequenceFeature sf2 = addFeature(sf, "Pfam", 1, 15);
266 SequenceFeature sf3 = addFeature(sf, "Pfam", 20, 30);
267 SequenceFeature sf4 = addFeature(sf, "Pfam", 40, 100);
268 SequenceFeature sf5 = addFeature(sf, "Pfam", 60, 100);
269 SequenceFeature sf6 = addFeature(sf, "Pfam", 70, 70);
270 SequenceFeature sf7 = addFeature(sf, "Cath", 10, 50);
271 SequenceFeature sf8 = addFeature(sf, "Cath", 1, 15);
272 SequenceFeature sf9 = addFeature(sf, "Cath", 20, 30);
273 SequenceFeature sf10 = addFeature(sf, "Cath", 40, 100);
274 SequenceFeature sf11 = addFeature(sf, "Cath", 60, 100);
275 SequenceFeature sf12 = addFeature(sf, "Cath", 70, 70);
277 List<SequenceFeature> overlaps = sf.findFeatures(200, 200, "Pfam");
278 assertTrue(overlaps.isEmpty());
280 overlaps = sf.findFeatures( 1, 9, "Pfam");
281 assertEquals(overlaps.size(), 1);
282 assertTrue(overlaps.contains(sf2));
284 overlaps = sf.findFeatures( 5, 18, "Pfam");
285 assertEquals(overlaps.size(), 2);
286 assertTrue(overlaps.contains(sf1));
287 assertTrue(overlaps.contains(sf2));
289 overlaps = sf.findFeatures(30, 40, "Pfam");
290 assertEquals(overlaps.size(), 3);
291 assertTrue(overlaps.contains(sf1));
292 assertTrue(overlaps.contains(sf3));
293 assertTrue(overlaps.contains(sf4));
295 overlaps = sf.findFeatures( 80, 90, "Pfam");
296 assertEquals(overlaps.size(), 2);
297 assertTrue(overlaps.contains(sf4));
298 assertTrue(overlaps.contains(sf5));
300 overlaps = sf.findFeatures( 68, 70, "Pfam");
301 assertEquals(overlaps.size(), 3);
302 assertTrue(overlaps.contains(sf4));
303 assertTrue(overlaps.contains(sf5));
304 assertTrue(overlaps.contains(sf6));
306 overlaps = sf.findFeatures(16, 69, "Cath");
307 assertEquals(overlaps.size(), 4);
308 assertTrue(overlaps.contains(sf7));
309 assertFalse(overlaps.contains(sf8));
310 assertTrue(overlaps.contains(sf9));
311 assertTrue(overlaps.contains(sf10));
312 assertTrue(overlaps.contains(sf11));
313 assertFalse(overlaps.contains(sf12));
315 assertTrue(sf.findFeatures(0, 1000, "Metal").isEmpty());
317 overlaps = sf.findFeatures(7, 7, (String) null);
318 assertTrue(overlaps.isEmpty());
321 @Test(groups = "Functional")
322 public void testDelete()
324 SequenceFeaturesI sf = new SequenceFeatures();
325 SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
326 assertTrue(sf.getPositionalFeatures().contains(sf1));
328 assertFalse(sf.delete(null));
329 SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 15, 0f, null);
330 assertFalse(sf.delete(sf2)); // not added, can't delete it
331 assertTrue(sf.delete(sf1));
332 assertTrue(sf.getPositionalFeatures().isEmpty());
335 @Test(groups = "Functional")
336 public void testHasFeatures()
338 SequenceFeaturesI sf = new SequenceFeatures();
339 assertFalse(sf.hasFeatures());
341 SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
342 assertTrue(sf.hasFeatures());
345 assertFalse(sf.hasFeatures());
349 * Tests for the method that gets feature groups for positional or
350 * non-positional features
352 @Test(groups = "Functional")
353 public void testGetFeatureGroups()
355 SequenceFeaturesI sf = new SequenceFeatures();
356 assertTrue(sf.getFeatureGroups(true).isEmpty());
357 assertTrue(sf.getFeatureGroups(false).isEmpty());
360 * add a non-positional feature (begin/end = 0/0)
362 SequenceFeature sfx = new SequenceFeature("AType", "Desc", 0, 0, 0f,
365 Set<String> groups = sf.getFeatureGroups(true); // for positional
366 assertTrue(groups.isEmpty());
367 groups = sf.getFeatureGroups(false); // for non-positional
368 assertEquals(groups.size(), 1);
369 assertTrue(groups.contains("AGroup"));
370 groups = sf.getFeatureGroups(false, "AType");
371 assertEquals(groups.size(), 1);
372 assertTrue(groups.contains("AGroup"));
373 groups = sf.getFeatureGroups(true, "AnotherType");
374 assertTrue(groups.isEmpty());
377 * add, then delete, more non-positional features of different types
379 SequenceFeature sfy = new SequenceFeature("AnotherType", "Desc", 0, 0,
383 SequenceFeature sfz = new SequenceFeature("AThirdType", "Desc", 0, 0,
387 groups = sf.getFeatureGroups(false);
388 assertEquals(groups.size(), 3);
389 assertTrue(groups.contains("AGroup"));
390 assertTrue(groups.contains("AnotherGroup"));
391 assertTrue(groups.contains(null)); // null is a possible group
394 groups = sf.getFeatureGroups(false);
395 assertEquals(groups.size(), 1);
396 assertTrue(groups.contains("AGroup"));
399 * add positional features
401 SequenceFeature sf1 = new SequenceFeature("Pfam", "Desc", 10, 50, 0f,
404 groups = sf.getFeatureGroups(true);
405 assertEquals(groups.size(), 1);
406 assertTrue(groups.contains("PfamGroup"));
407 groups = sf.getFeatureGroups(false); // non-positional unchanged
408 assertEquals(groups.size(), 1);
409 assertTrue(groups.contains("AGroup"));
411 SequenceFeature sf2 = new SequenceFeature("Cath", "Desc", 10, 50, 0f,
414 groups = sf.getFeatureGroups(true);
415 assertEquals(groups.size(), 2);
416 assertTrue(groups.contains("PfamGroup"));
417 assertTrue(groups.contains(null));
421 assertTrue(sf.getFeatureGroups(true).isEmpty());
423 SequenceFeature sf3 = new SequenceFeature("CDS", "", 10, 50, 0f,
426 SequenceFeature sf4 = new SequenceFeature("exon", "", 10, 50, 0f,
429 groups = sf.getFeatureGroups(true);
430 assertEquals(groups.size(), 1);
431 assertTrue(groups.contains("Ensembl"));
434 * delete last Ensembl group feature from CDS features
435 * but still have one in exon features
438 groups = sf.getFeatureGroups(true);
439 assertEquals(groups.size(), 1);
440 assertTrue(groups.contains("Ensembl"));
443 * delete the last non-positional feature
446 groups = sf.getFeatureGroups(false);
447 assertTrue(groups.isEmpty());
450 @Test(groups = "Functional")
451 public void testGetFeatureTypesForGroups()
453 SequenceFeaturesI sf = new SequenceFeatures();
454 assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
457 * add feature with group = "Uniprot", type = "helix"
459 String groupUniprot = "Uniprot";
460 SequenceFeature sf1 = new SequenceFeature("helix", "Desc", 10, 50, 0f,
463 Set<String> groups = sf.getFeatureTypesForGroups(true, groupUniprot);
464 assertEquals(groups.size(), 1);
465 assertTrue(groups.contains("helix"));
466 assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
469 * add feature with group = "Uniprot", type = "strand"
471 SequenceFeature sf2 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
474 groups = sf.getFeatureTypesForGroups(true, groupUniprot);
475 assertEquals(groups.size(), 2);
476 assertTrue(groups.contains("helix"));
477 assertTrue(groups.contains("strand"));
480 * delete the "strand" Uniprot feature - still have "helix"
483 groups = sf.getFeatureTypesForGroups(true, groupUniprot);
484 assertEquals(groups.size(), 1);
485 assertTrue(groups.contains("helix"));
488 * delete the "helix" Uniprot feature - none left
491 assertTrue(sf.getFeatureTypesForGroups(true, groupUniprot).isEmpty());
494 * add some null group features
496 SequenceFeature sf3 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
499 SequenceFeature sf4 = new SequenceFeature("turn", "Desc", 10, 50, 0f,
502 groups = sf.getFeatureTypesForGroups(true, (String) null);
503 assertEquals(groups.size(), 2);
504 assertTrue(groups.contains("strand"));
505 assertTrue(groups.contains("turn"));
508 * add strand/Cath and turn/Scop and query for one or both groups
509 * (find feature types for groups selected in Feature Settings)
511 SequenceFeature sf5 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
514 SequenceFeature sf6 = new SequenceFeature("turn", "Desc", 10, 50, 0f,
517 groups = sf.getFeatureTypesForGroups(true, "Cath");
518 assertEquals(groups.size(), 1);
519 assertTrue(groups.contains("strand"));
520 groups = sf.getFeatureTypesForGroups(true, "Scop");
521 assertEquals(groups.size(), 1);
522 assertTrue(groups.contains("turn"));
523 groups = sf.getFeatureTypesForGroups(true, "Cath", "Scop");
524 assertEquals(groups.size(), 2);
525 assertTrue(groups.contains("turn"));
526 assertTrue(groups.contains("strand"));
527 // alternative vararg syntax
528 groups = sf.getFeatureTypesForGroups(true, new String[] { "Cath",
530 assertEquals(groups.size(), 2);
531 assertTrue(groups.contains("turn"));
532 assertTrue(groups.contains("strand"));
535 @Test(groups = "Functional")
536 public void testGetFeatureTypes()
538 SequenceFeaturesI store = new SequenceFeatures();
539 Set<String> types = store.getFeatureTypes();
540 assertTrue(types.isEmpty());
542 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
545 types = store.getFeatureTypes();
546 assertEquals(types.size(), 1);
547 assertTrue(types.contains("Metal"));
549 // null type is rejected...
550 SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20,
552 assertFalse(store.add(sf2));
553 types = store.getFeatureTypes();
554 assertEquals(types.size(), 1);
555 assertFalse(types.contains(null));
556 assertTrue(types.contains("Metal"));
559 * add non-positional feature
561 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
564 types = store.getFeatureTypes();
565 assertEquals(types.size(), 2);
566 assertTrue(types.contains("Pfam"));
569 * add contact feature
571 SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc",
572 10, 20, Float.NaN, null);
574 types = store.getFeatureTypes();
575 assertEquals(types.size(), 3);
576 assertTrue(types.contains("Disulphide Bond"));
581 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
584 types = store.getFeatureTypes();
585 assertEquals(types.size(), 3); // unchanged
588 * delete first Pfam - still have one
590 assertTrue(store.delete(sf3));
591 types = store.getFeatureTypes();
592 assertEquals(types.size(), 3);
593 assertTrue(types.contains("Pfam"));
596 * delete second Pfam - no longer have one
598 assertTrue(store.delete(sf5));
599 types = store.getFeatureTypes();
600 assertEquals(types.size(), 2);
601 assertFalse(types.contains("Pfam"));
604 @Test(groups = "Functional")
605 public void testGetFeatureCount()
607 SequenceFeaturesI store = new SequenceFeatures();
608 assertEquals(store.getFeatureCount(true), 0);
609 assertEquals(store.getFeatureCount(false), 0);
614 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
617 assertEquals(store.getFeatureCount(true), 1);
618 assertEquals(store.getFeatureCount(false), 0);
621 * null feature type is rejected
623 SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20,
625 assertFalse(store.add(sf2));
626 assertEquals(store.getFeatureCount(true), 1);
627 assertEquals(store.getFeatureCount(false), 0);
630 * add non-positional feature
632 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
635 assertEquals(store.getFeatureCount(true), 1);
636 assertEquals(store.getFeatureCount(false), 1);
639 * add contact feature (counts as 1)
641 SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc",
642 10, 20, Float.NaN, null);
644 assertEquals(store.getFeatureCount(true), 2);
645 assertEquals(store.getFeatureCount(false), 1);
648 * add another Pfam but this time as a positional feature
650 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
653 assertEquals(store.getFeatureCount(true), 3); // sf1, sf4, sf5
654 assertEquals(store.getFeatureCount(false), 1); // sf3
655 assertEquals(store.getFeatureCount(true, "Pfam"), 1); // positional
656 assertEquals(store.getFeatureCount(false, "Pfam"), 1); // non-positional
657 // search for type==null
658 assertEquals(store.getFeatureCount(true, (String) null), 0);
659 // search with no type specified
660 assertEquals(store.getFeatureCount(true, (String[]) null), 3);
661 assertEquals(store.getFeatureCount(true, "Metal", "Cath"), 1);
662 assertEquals(store.getFeatureCount(true, "Disulphide Bond"), 1);
663 assertEquals(store.getFeatureCount(true, "Metal", "Pfam", null), 2);
666 * delete first Pfam (non-positional)
668 assertTrue(store.delete(sf3));
669 assertEquals(store.getFeatureCount(true), 3);
670 assertEquals(store.getFeatureCount(false), 0);
673 * delete second Pfam (positional)
675 assertTrue(store.delete(sf5));
676 assertEquals(store.getFeatureCount(true), 2);
677 assertEquals(store.getFeatureCount(false), 0);
680 @Test(groups = "Functional")
681 public void testGetAllFeatures()
683 SequenceFeaturesI store = new SequenceFeatures();
684 List<SequenceFeature> features = store.getAllFeatures();
685 assertTrue(features.isEmpty());
687 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
690 features = store.getAllFeatures();
691 assertEquals(features.size(), 1);
692 assertTrue(features.contains(sf1));
694 SequenceFeature sf2 = new SequenceFeature("Metallic", "desc", 10, 20,
697 features = store.getAllFeatures();
698 assertEquals(features.size(), 2);
699 assertTrue(features.contains(sf2));
702 * add non-positional feature
704 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
707 features = store.getAllFeatures();
708 assertEquals(features.size(), 3);
709 assertTrue(features.contains(sf3));
712 * add contact feature
714 SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc",
715 10, 20, Float.NaN, null);
717 features = store.getAllFeatures();
718 assertEquals(features.size(), 4);
719 assertTrue(features.contains(sf4));
724 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
727 features = store.getAllFeatures();
728 assertEquals(features.size(), 5);
729 assertTrue(features.contains(sf5));
732 * select by type does not apply to non-positional features
734 features = store.getAllFeatures("Cath");
735 assertEquals(features.size(), 1);
736 assertTrue(features.contains(sf3));
738 features = store.getAllFeatures("Pfam", "Cath", "Metal");
739 assertEquals(features.size(), 3);
740 assertTrue(features.contains(sf1));
741 assertTrue(features.contains(sf3));
742 assertTrue(features.contains(sf5));
747 assertTrue(store.delete(sf3));
748 features = store.getAllFeatures();
749 assertEquals(features.size(), 4);
750 assertFalse(features.contains(sf3));
755 assertTrue(store.delete(sf5));
756 features = store.getAllFeatures();
757 assertEquals(features.size(), 3);
758 assertFalse(features.contains(sf3));
761 @Test(groups = "Functional")
762 public void testGetTotalFeatureLength()
764 SequenceFeaturesI store = new SequenceFeatures();
765 assertEquals(store.getTotalFeatureLength(), 0);
767 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
769 assertTrue(store.add(sf1));
770 assertEquals(store.getTotalFeatureLength(), 11);
771 assertEquals(store.getTotalFeatureLength("Metal"), 11);
772 assertEquals(store.getTotalFeatureLength("Plastic"), 0);
774 // re-add does nothing!
775 assertFalse(store.add(sf1));
776 assertEquals(store.getTotalFeatureLength(), 11);
779 * add non-positional feature
781 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
784 assertEquals(store.getTotalFeatureLength(), 11);
787 * add contact feature - counts 1 to feature length
789 SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc",
790 10, 20, Float.NaN, null);
792 assertEquals(store.getTotalFeatureLength(), 12);
797 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
800 assertEquals(store.getTotalFeatureLength(), 23);
805 assertTrue(store.delete(sf3)); // non-positional
806 assertEquals(store.getTotalFeatureLength(), 23); // no change
808 assertTrue(store.delete(sf5));
809 assertEquals(store.getTotalFeatureLength(), 12);
811 assertTrue(store.delete(sf4)); // contact
812 assertEquals(store.getTotalFeatureLength(), 11);
814 assertTrue(store.delete(sf1));
815 assertEquals(store.getTotalFeatureLength(), 0);
818 @Test(groups = "Functional")
819 public void testGetMinimumScore_getMaximumScore()
821 SequenceFeatures sf = new SequenceFeatures();
822 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 0, 0,
823 Float.NaN, "group"); // non-positional, no score
825 SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 10, 20,
826 Float.NaN, "group"); // positional, no score
828 SequenceFeature sf3 = new SequenceFeature("Metal", "desc", 10, 20, 1f,
831 SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 12, 16, 4f,
834 SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 0, 0, 11f,
837 SequenceFeature sf6 = new SequenceFeature("Cath", "desc", 0, 0, -7f,
841 assertEquals(sf.getMinimumScore("nosuchtype", true), Float.NaN);
842 assertEquals(sf.getMinimumScore("nosuchtype", false), Float.NaN);
843 assertEquals(sf.getMaximumScore("nosuchtype", true), Float.NaN);
844 assertEquals(sf.getMaximumScore("nosuchtype", false), Float.NaN);
846 // positional features min-max:
847 assertEquals(sf.getMinimumScore("Metal", true), 1f);
848 assertEquals(sf.getMaximumScore("Metal", true), 4f);
849 assertEquals(sf.getMinimumScore("Cath", true), Float.NaN);
850 assertEquals(sf.getMaximumScore("Cath", true), Float.NaN);
852 // non-positional features min-max:
853 assertEquals(sf.getMinimumScore("Cath", false), -7f);
854 assertEquals(sf.getMaximumScore("Cath", false), 11f);
855 assertEquals(sf.getMinimumScore("Metal", false), Float.NaN);
856 assertEquals(sf.getMaximumScore("Metal", false), Float.NaN);
858 // delete features; min-max should get recomputed
860 assertEquals(sf.getMinimumScore("Cath", false), 11f);
861 assertEquals(sf.getMaximumScore("Cath", false), 11f);
863 assertEquals(sf.getMinimumScore("Metal", true), 1f);
864 assertEquals(sf.getMaximumScore("Metal", true), 1f);
866 assertEquals(sf.getMinimumScore("Cath", false), Float.NaN);
867 assertEquals(sf.getMaximumScore("Cath", false), Float.NaN);
869 assertEquals(sf.getMinimumScore("Metal", true), Float.NaN);
870 assertEquals(sf.getMaximumScore("Metal", true), Float.NaN);
873 assertFalse(sf.hasFeatures());
874 assertEquals(sf.getMinimumScore("Cath", false), Float.NaN);
875 assertEquals(sf.getMaximumScore("Cath", false), Float.NaN);
876 assertEquals(sf.getMinimumScore("Metal", true), Float.NaN);
877 assertEquals(sf.getMaximumScore("Metal", true), Float.NaN);
880 @Test(groups = "Functional")
881 public void testVarargsToTypes()
883 SequenceFeatures sf = new SequenceFeatures();
884 sf.add(new SequenceFeature("Metal", "desc", 0, 0, Float.NaN, "group"));
885 sf.add(new SequenceFeature("Cath", "desc", 10, 20, Float.NaN, "group"));
888 * no type specified - get all types stored
889 * they are returned in keyset (alphabetical) order
891 Map<String, FeatureStore> featureStores = (Map<String, FeatureStore>) PA
892 .getValue(sf, "featureStore");
894 Iterable<FeatureStore> types = sf.varargToTypes();
895 Iterator<FeatureStore> iterator = types.iterator();
896 assertTrue(iterator.hasNext());
897 assertSame(iterator.next(), featureStores.get("Cath"));
898 assertTrue(iterator.hasNext());
899 assertSame(iterator.next(), featureStores.get("Metal"));
900 assertFalse(iterator.hasNext());
903 * empty array is the same as no vararg parameter supplied
904 * so treated as all stored types
906 types = sf.varargToTypes(new String[] {});
907 iterator = types.iterator();
908 assertTrue(iterator.hasNext());
909 assertSame(iterator.next(), featureStores.get("Cath"));
910 assertTrue(iterator.hasNext());
911 assertSame(iterator.next(), featureStores.get("Metal"));
912 assertFalse(iterator.hasNext());
915 * null type specified; this is passed as vararg
918 types = sf.varargToTypes((String) null);
919 assertFalse(types.iterator().hasNext());
922 * null types array specified; this is passed as vararg null
924 types = sf.varargToTypes((String[]) null);
925 iterator = types.iterator();
926 assertTrue(iterator.hasNext());
927 assertSame(iterator.next(), featureStores.get("Cath"));
928 assertTrue(iterator.hasNext());
929 assertSame(iterator.next(), featureStores.get("Metal"));
930 assertFalse(iterator.hasNext());
935 types = sf.varargToTypes("Metal");
936 iterator = types.iterator();
937 assertTrue(iterator.hasNext());
938 assertSame(iterator.next(), featureStores.get("Metal"));
939 assertFalse(iterator.hasNext());
942 * two types specified - order is preserved
944 types = sf.varargToTypes("Metal", "Cath");
945 iterator = types.iterator();
946 assertTrue(iterator.hasNext());
947 assertSame(iterator.next(), featureStores.get("Metal"));
948 assertTrue(iterator.hasNext());
949 assertSame(iterator.next(), featureStores.get("Cath"));
950 assertFalse(iterator.hasNext());
953 * null type included - should be ignored
955 types = sf.varargToTypes("Metal", null, "Helix");
956 iterator = types.iterator();
957 assertTrue(iterator.hasNext());
958 assertSame(iterator.next(), featureStores.get("Metal"));
959 assertFalse(iterator.hasNext());
962 @Test(groups = "Functional")
963 public void testGetFeatureTypes_byOntology()
965 SequenceFeaturesI store = new SequenceFeatures();
967 SequenceFeature sf1 = new SequenceFeature("transcript", "desc", 10, 20,
970 // mRNA isA mature_transcript isA transcript
971 SequenceFeature sf2 = new SequenceFeature("mRNA", "desc", 10, 20,
974 // just to prove non-positional feature types are included
975 SequenceFeature sf3 = new SequenceFeature("mRNA", "desc", 0, 0,
978 SequenceFeature sf4 = new SequenceFeature("CDS", "desc", 0, 0,
982 Set<String> types = store.getFeatureTypes("transcript");
983 assertEquals(types.size(), 2);
984 assertTrue(types.contains("transcript"));
985 assertTrue(types.contains("mRNA"));
987 // matches include arguments whether SO terms or not
988 types = store.getFeatureTypes("transcript", "CDS");
989 assertEquals(types.size(), 3);
990 assertTrue(types.contains("transcript"));
991 assertTrue(types.contains("mRNA"));
992 assertTrue(types.contains("CDS"));
994 types = store.getFeatureTypes("exon");
995 assertTrue(types.isEmpty());
998 @Test(groups = "Functional")
999 public void testGetFeaturesByOntology()
1001 SequenceFeaturesI store = new SequenceFeatures();
1002 List<SequenceFeature> features = store.getFeaturesByOntology();
1003 assertTrue(features.isEmpty());
1004 assertTrue(store.getFeaturesByOntology(new String[] {}).isEmpty());
1005 assertTrue(store.getFeaturesByOntology((String[]) null).isEmpty());
1007 SequenceFeature transcriptFeature = new SequenceFeature("transcript", "desc", 10, 20,
1009 store.add(transcriptFeature);
1012 * mRNA is a sub-type of transcript; added here 'as if' non-positional
1013 * just to show that non-positional features are included in results
1015 SequenceFeature mrnaFeature = new SequenceFeature("mRNA", "desc", 0, 0,
1017 store.add(mrnaFeature);
1019 SequenceFeature pfamFeature = new SequenceFeature("Pfam", "desc", 30, 40,
1021 store.add(pfamFeature);
1024 * "transcript" matches both itself and the sub-term "mRNA"
1026 features = store.getFeaturesByOntology("transcript");
1027 assertEquals(features.size(), 2);
1028 assertTrue(features.contains(transcriptFeature));
1029 assertTrue(features.contains(mrnaFeature));
1032 * "mRNA" matches itself but not parent term "transcript"
1034 features = store.getFeaturesByOntology("mRNA");
1035 assertEquals(features.size(), 1);
1036 assertTrue(features.contains(mrnaFeature));
1039 * "pfam" is not an SO term but is included as an exact match
1041 features = store.getFeaturesByOntology("mRNA", "Pfam");
1042 assertEquals(features.size(), 2);
1043 assertTrue(features.contains(mrnaFeature));
1044 assertTrue(features.contains(pfamFeature));
1046 features = store.getFeaturesByOntology("sequence_variant");
1047 assertTrue(features.isEmpty());
1050 @Test(groups = "Functional")
1051 public void testSortFeatures()
1053 List<SequenceFeature> sfs = new ArrayList<>();
1054 SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 30,
1058 SequenceFeature sf2 = new SequenceFeature("Rfam", "desc", 40, 50,
1061 SequenceFeature sf3 = new SequenceFeature("Rfam", "desc", 50, 60,
1064 SequenceFeature sf4 = new SequenceFeature("Xfam", "desc", 30,
1068 SequenceFeature sf5 = new SequenceFeature("Xfam", "desc", 30,
1074 * sort by end position descending, order unchanged if matched
1076 SequenceFeatures.sortFeatures(sfs, false);
1077 assertSame(sfs.get(0), sf5); // end 90
1078 assertSame(sfs.get(1), sf4); // end 80
1079 assertSame(sfs.get(2), sf1); // end 60, start 50
1080 assertSame(sfs.get(3), sf3); // end 60, start 30
1081 assertSame(sfs.get(4), sf2); // end 50
1084 * resort {5, 4, 1, 3, 2} by start position ascending, end descending
1086 SequenceFeatures.sortFeatures(sfs, true);
1087 assertSame(sfs.get(0), sf5); // start 30, end 90
1088 assertSame(sfs.get(1), sf4); // start 30, end 80
1089 assertSame(sfs.get(2), sf1); // start 30, end 60
1090 assertSame(sfs.get(3), sf2); // start 40
1091 assertSame(sfs.get(4), sf3); // start 50
1094 @Test(groups = "Functional")
1095 public void testGetFeaturesForGroup()
1097 SequenceFeaturesI store = new SequenceFeatures();
1099 List<SequenceFeature> features = store.getFeaturesForGroup(true, null);
1100 assertTrue(features.isEmpty());
1101 assertTrue(store.getFeaturesForGroup(false, null).isEmpty());
1102 assertTrue(store.getFeaturesForGroup(true, "Uniprot").isEmpty());
1103 assertTrue(store.getFeaturesForGroup(false, "Uniprot").isEmpty());
1105 SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
1107 SequenceFeature sf2 = new SequenceFeature("Pfam", "desc", 0, 0, 0f,
1109 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
1111 SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 0, 0, 0f,
1113 SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 5, 15, 0f,
1121 // positional features for null group, any type
1122 features = store.getFeaturesForGroup(true, null);
1123 assertEquals(features.size(), 2);
1124 assertTrue(features.contains(sf1));
1125 assertTrue(features.contains(sf5));
1127 // positional features for null group, specified type
1128 features = store.getFeaturesForGroup(true, null, new String[] { "Pfam",
1130 assertEquals(features.size(), 1);
1131 assertTrue(features.contains(sf1));
1132 features = store.getFeaturesForGroup(true, null, new String[] { "Pfam",
1134 assertEquals(features.size(), 2);
1135 assertTrue(features.contains(sf1));
1136 assertTrue(features.contains(sf5));
1138 // positional features for non-null group, any type
1139 features = store.getFeaturesForGroup(true, "Uniprot");
1140 assertEquals(features.size(), 1);
1141 assertTrue(features.contains(sf3));
1142 assertTrue(store.getFeaturesForGroup(true, "Rfam").isEmpty());
1144 // positional features for non-null group, specified type
1145 features = store.getFeaturesForGroup(true, "Uniprot", "Pfam", "Xfam",
1147 assertEquals(features.size(), 1);
1148 assertTrue(features.contains(sf3));
1149 assertTrue(store.getFeaturesForGroup(true, "Uniprot", "Cath").isEmpty());
1151 // non-positional features for null group, any type
1152 features = store.getFeaturesForGroup(false, null);
1153 assertEquals(features.size(), 1);
1154 assertTrue(features.contains(sf2));
1156 // non-positional features for null group, specified type
1157 features = store.getFeaturesForGroup(false, null, "Pfam", "Xfam");
1158 assertEquals(features.size(), 1);
1159 assertTrue(features.contains(sf2));
1160 assertTrue(store.getFeaturesForGroup(false, null, "Cath").isEmpty());
1162 // non-positional features for non-null group, any type
1163 features = store.getFeaturesForGroup(false, "Rfam");
1164 assertEquals(features.size(), 1);
1165 assertTrue(features.contains(sf4));
1166 assertTrue(store.getFeaturesForGroup(false, "Uniprot").isEmpty());
1168 // non-positional features for non-null group, specified type
1169 features = store.getFeaturesForGroup(false, "Rfam", "Pfam", "Metal");
1170 assertEquals(features.size(), 1);
1171 assertTrue(features.contains(sf4));
1172 assertTrue(store.getFeaturesForGroup(false, "Rfam", "Cath", "Pfam")
1176 @Test(groups = "Functional")
1177 public void testShiftFeatures()
1179 SequenceFeatures store = new SequenceFeatures();
1180 assertFalse(store.shiftFeatures(0, 1));
1182 SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
1185 SequenceFeature sf2 = new SequenceFeature("Metal", "", 8, 14, 0f, null);
1188 SequenceFeature sf3 = new SequenceFeature("Disulfide bond", "", 23, 32,
1191 // non-positional feature:
1192 SequenceFeature sf4 = new SequenceFeature("Pfam", "", 0, 0, 0f, null);
1196 * shift features right by 5
1198 assertTrue(store.shiftFeatures(0, 5));
1200 // non-positional features untouched:
1201 List<SequenceFeature> nonPos = store.getNonPositionalFeatures();
1202 assertEquals(nonPos.size(), 1);
1203 assertTrue(nonPos.contains(sf4));
1205 // positional features are replaced
1206 List<SequenceFeature> pos = store.getPositionalFeatures();
1207 assertEquals(pos.size(), 3);
1208 assertFalse(pos.contains(sf1));
1209 assertFalse(pos.contains(sf2));
1210 assertFalse(pos.contains(sf3));
1211 SequenceFeatures.sortFeatures(pos, true); // ascending start pos
1212 assertEquals(pos.get(0).getBegin(), 7);
1213 assertEquals(pos.get(0).getEnd(), 10);
1214 assertEquals(pos.get(0).getType(), "Cath");
1215 assertEquals(pos.get(1).getBegin(), 13);
1216 assertEquals(pos.get(1).getEnd(), 19);
1217 assertEquals(pos.get(1).getType(), "Metal");
1218 assertEquals(pos.get(2).getBegin(), 28);
1219 assertEquals(pos.get(2).getEnd(), 37);
1220 assertEquals(pos.get(2).getType(), "Disulfide bond");
1223 * now shift left by 15
1224 * feature at [7-10] should be removed
1225 * feature at [13-19] should become [1-4]
1227 assertTrue(store.shiftFeatures(0, -15));
1228 pos = store.getPositionalFeatures();
1229 assertEquals(pos.size(), 2);
1230 SequenceFeatures.sortFeatures(pos, true);
1231 assertEquals(pos.get(0).getBegin(), 1);
1232 assertEquals(pos.get(0).getEnd(), 4);
1233 assertEquals(pos.get(0).getType(), "Metal");
1234 assertEquals(pos.get(1).getBegin(), 13);
1235 assertEquals(pos.get(1).getEnd(), 22);
1236 assertEquals(pos.get(1).getType(), "Disulfide bond");
1239 * shift right by 4 from column 2
1240 * feature at [1-4] should be unchanged
1241 * feature at [13-22] should become [17-26]
1243 assertTrue(store.shiftFeatures(2, 4));
1244 pos = store.getPositionalFeatures();
1245 assertEquals(pos.size(), 2);
1246 SequenceFeatures.sortFeatures(pos, true);
1247 assertEquals(pos.get(0).getBegin(), 1);
1248 assertEquals(pos.get(0).getEnd(), 4);
1249 assertEquals(pos.get(0).getType(), "Metal");
1250 assertEquals(pos.get(1).getBegin(), 17);
1251 assertEquals(pos.get(1).getEnd(), 26);
1252 assertEquals(pos.get(1).getType(), "Disulfide bond");
1255 * shift right from column 18
1256 * should be no updates
1258 SequenceFeature f1 = pos.get(0);
1259 SequenceFeature f2 = pos.get(1);
1260 assertFalse(store.shiftFeatures(18, 6));
1261 pos = store.getPositionalFeatures();
1262 assertEquals(pos.size(), 2);
1263 SequenceFeatures.sortFeatures(pos, true);
1264 assertSame(pos.get(0), f1);
1265 assertSame(pos.get(1), f2);
1268 @Test(groups = "Functional")
1269 public void testIsOntologyTerm()
1271 SequenceFeatures store = new SequenceFeatures();
1272 assertTrue(store.isOntologyTerm("gobbledygook"));
1273 assertTrue(store.isOntologyTerm("transcript", "transcript"));
1274 assertTrue(store.isOntologyTerm("mRNA", "transcript"));
1275 assertFalse(store.isOntologyTerm("transcript", "mRNA"));
1276 assertTrue(store.isOntologyTerm("junk", "transcript", "junk"));
1277 assertTrue(store.isOntologyTerm("junk", new String[] {}));
1278 assertTrue(store.isOntologyTerm("junk", (String[]) null));
1281 @Test(groups = "Functional")
1282 public void testDeleteAll()
1284 SequenceFeaturesI store = new SequenceFeatures();
1285 assertFalse(store.hasFeatures());
1287 assertFalse(store.hasFeatures());
1288 store.add(new SequenceFeature("Cath", "Desc", 12, 20, 0f, "Group"));
1289 store.add(new SequenceFeature("Pfam", "Desc", 6, 12, 2f, "Group2"));
1290 assertTrue(store.hasFeatures());
1292 assertFalse(store.hasFeatures());