2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.datamodel.features;
23 import static org.testng.Assert.assertEquals;
24 import static org.testng.Assert.assertFalse;
25 import static org.testng.Assert.assertSame;
26 import static org.testng.Assert.assertTrue;
28 import java.util.ArrayList;
29 import java.util.Iterator;
30 import java.util.List;
34 import org.testng.annotations.Test;
36 import jalview.datamodel.SequenceFeature;
37 import junit.extensions.PA;
39 public class SequenceFeaturesTest
41 @Test(groups = "Functional")
42 public void testConstructor()
44 SequenceFeaturesI store = new SequenceFeatures();
45 assertFalse(store.hasFeatures());
47 store = new SequenceFeatures((List<SequenceFeature>) null);
48 assertFalse(store.hasFeatures());
50 List<SequenceFeature> features = new ArrayList<>();
51 store = new SequenceFeatures(features);
52 assertFalse(store.hasFeatures());
54 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
57 SequenceFeature sf2 = new SequenceFeature("Metal", "desc", 15, 18,
59 features.add(sf2); // nested
60 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc2", 0, 0,
61 Float.NaN, null); // non-positional
63 store = new SequenceFeatures(features);
64 assertTrue(store.hasFeatures());
65 assertEquals(2, store.getFeatureCount(true)); // positional
66 assertEquals(1, store.getFeatureCount(false)); // non-positional
67 assertFalse(store.add(sf1)); // already contained
68 assertFalse(store.add(sf2)); // already contained
69 assertFalse(store.add(sf3)); // already contained
72 @Test(groups = "Functional")
73 public void testGetPositionalFeatures()
75 SequenceFeaturesI store = new SequenceFeatures();
76 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
79 // same range, different description
80 SequenceFeature sf2 = new SequenceFeature("Metal", "desc2", 10, 20,
83 // discontiguous range
84 SequenceFeature sf3 = new SequenceFeature("Metal", "desc", 30, 40,
88 SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 15, 35,
92 SequenceFeature sf5 = new SequenceFeature("Metal", "desc", 5, 50,
95 // non-positional feature
96 SequenceFeature sf6 = new SequenceFeature("Metal", "desc", 0, 0,
100 SequenceFeature sf7 = new SequenceFeature("Disulphide bond", "desc", 18,
101 45, Float.NaN, null);
103 // different feature type
104 SequenceFeature sf8 = new SequenceFeature("Pfam", "desc", 30, 40,
107 SequenceFeature sf9 = new SequenceFeature("Pfam", "desc", 15, 35,
112 * get all positional features
114 List<SequenceFeature> features = store.getPositionalFeatures();
115 assertEquals(features.size(), 8);
116 assertTrue(features.contains(sf1));
117 assertTrue(features.contains(sf2));
118 assertTrue(features.contains(sf3));
119 assertTrue(features.contains(sf4));
120 assertTrue(features.contains(sf5));
121 assertFalse(features.contains(sf6)); // non-positional
122 assertTrue(features.contains(sf7));
123 assertTrue(features.contains(sf8));
124 assertTrue(features.contains(sf9));
127 * get features by type
129 assertTrue(store.getPositionalFeatures((String) null).isEmpty());
130 assertTrue(store.getPositionalFeatures("Cath").isEmpty());
131 assertTrue(store.getPositionalFeatures("METAL").isEmpty());
133 features = store.getPositionalFeatures("Metal");
134 assertEquals(features.size(), 5);
135 assertTrue(features.contains(sf1));
136 assertTrue(features.contains(sf2));
137 assertTrue(features.contains(sf3));
138 assertTrue(features.contains(sf4));
139 assertTrue(features.contains(sf5));
140 assertFalse(features.contains(sf6));
142 features = store.getPositionalFeatures("Disulphide bond");
143 assertEquals(features.size(), 1);
144 assertTrue(features.contains(sf7));
146 features = store.getPositionalFeatures("Pfam");
147 assertEquals(features.size(), 2);
148 assertTrue(features.contains(sf8));
149 assertTrue(features.contains(sf9));
152 @Test(groups = "Functional")
153 public void testGetContactFeatures()
155 SequenceFeaturesI store = new SequenceFeatures();
157 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
161 SequenceFeature sf2 = new SequenceFeature("Metal", "desc", 0, 0,
165 SequenceFeature sf3 = new SequenceFeature("Disulphide bond", "desc", 18,
166 45, Float.NaN, null);
168 // repeat for different feature type
169 SequenceFeature sf4 = new SequenceFeature("Pfam", "desc", 10, 20,
172 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 0, 0,
175 SequenceFeature sf6 = new SequenceFeature("Disulfide bond", "desc", 18,
176 45, Float.NaN, null);
180 * get all contact features
182 List<SequenceFeature> features = store.getContactFeatures();
183 assertEquals(features.size(), 2);
184 assertTrue(features.contains(sf3));
185 assertTrue(features.contains(sf6));
188 * get contact features by type
190 assertTrue(store.getContactFeatures((String) null).isEmpty());
191 assertTrue(store.getContactFeatures("Cath").isEmpty());
192 assertTrue(store.getContactFeatures("Pfam").isEmpty());
193 assertTrue(store.getContactFeatures("DISULPHIDE BOND").isEmpty());
195 features = store.getContactFeatures("Disulphide bond");
196 assertEquals(features.size(), 1);
197 assertTrue(features.contains(sf3));
199 features = store.getContactFeatures("Disulfide bond");
200 assertEquals(features.size(), 1);
201 assertTrue(features.contains(sf6));
204 @Test(groups = "Functional")
205 public void testGetNonPositionalFeatures()
207 SequenceFeaturesI store = new SequenceFeatures();
209 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
213 SequenceFeature sf2 = new SequenceFeature("Metal", "desc", 0, 0,
217 SequenceFeature sf3 = new SequenceFeature("Disulphide bond", "desc", 18,
218 45, Float.NaN, null);
220 // repeat for different feature type
221 SequenceFeature sf4 = new SequenceFeature("Pfam", "desc", 10, 20,
224 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 0, 0,
227 SequenceFeature sf6 = new SequenceFeature("Disulfide bond", "desc", 18,
228 45, Float.NaN, null);
230 // one more non-positional, different description
231 SequenceFeature sf7 = new SequenceFeature("Pfam", "desc2", 0, 0,
236 * get all non-positional features
238 List<SequenceFeature> features = store.getNonPositionalFeatures();
239 assertEquals(features.size(), 3);
240 assertTrue(features.contains(sf2));
241 assertTrue(features.contains(sf5));
242 assertTrue(features.contains(sf7));
245 * get non-positional features by type
247 assertTrue(store.getNonPositionalFeatures((String) null).isEmpty());
248 assertTrue(store.getNonPositionalFeatures("Cath").isEmpty());
249 assertTrue(store.getNonPositionalFeatures("PFAM").isEmpty());
251 features = store.getNonPositionalFeatures("Metal");
252 assertEquals(features.size(), 1);
253 assertTrue(features.contains(sf2));
255 features = store.getNonPositionalFeatures("Pfam");
256 assertEquals(features.size(), 2);
257 assertTrue(features.contains(sf5));
258 assertTrue(features.contains(sf7));
262 * Helper method to add a feature of no particular type
270 SequenceFeature addFeature(SequenceFeaturesI sf, String type, int from,
273 SequenceFeature sf1 = new SequenceFeature(type, "", from, to, Float.NaN,
279 @Test(groups = "Functional")
280 public void testFindFeatures()
282 SequenceFeaturesI sf = new SequenceFeatures();
283 SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
284 SequenceFeature sf2 = addFeature(sf, "Pfam", 1, 15);
285 SequenceFeature sf3 = addFeature(sf, "Pfam", 20, 30);
286 SequenceFeature sf4 = addFeature(sf, "Pfam", 40, 100);
287 SequenceFeature sf5 = addFeature(sf, "Pfam", 60, 100);
288 SequenceFeature sf6 = addFeature(sf, "Pfam", 70, 70);
289 SequenceFeature sf7 = addFeature(sf, "Cath", 10, 50);
290 SequenceFeature sf8 = addFeature(sf, "Cath", 1, 15);
291 SequenceFeature sf9 = addFeature(sf, "Cath", 20, 30);
292 SequenceFeature sf10 = addFeature(sf, "Cath", 40, 100);
293 SequenceFeature sf11 = addFeature(sf, "Cath", 60, 100);
294 SequenceFeature sf12 = addFeature(sf, "Cath", 70, 70);
296 List<SequenceFeature> overlaps = sf.findFeatures(200, 200, "Pfam");
297 assertTrue(overlaps.isEmpty());
299 overlaps = sf.findFeatures(1, 9, "Pfam");
300 assertEquals(overlaps.size(), 1);
301 assertTrue(overlaps.contains(sf2));
303 overlaps = sf.findFeatures(5, 18, "Pfam");
304 assertEquals(overlaps.size(), 2);
305 assertTrue(overlaps.contains(sf1));
306 assertTrue(overlaps.contains(sf2));
308 overlaps = sf.findFeatures(30, 40, "Pfam");
309 assertEquals(overlaps.size(), 3);
310 assertTrue(overlaps.contains(sf1));
311 assertTrue(overlaps.contains(sf3));
312 assertTrue(overlaps.contains(sf4));
314 overlaps = sf.findFeatures(80, 90, "Pfam");
315 assertEquals(overlaps.size(), 2);
316 assertTrue(overlaps.contains(sf4));
317 assertTrue(overlaps.contains(sf5));
319 overlaps = sf.findFeatures(68, 70, "Pfam");
320 assertEquals(overlaps.size(), 3);
321 assertTrue(overlaps.contains(sf4));
322 assertTrue(overlaps.contains(sf5));
323 assertTrue(overlaps.contains(sf6));
325 overlaps = sf.findFeatures(16, 69, "Cath");
326 assertEquals(overlaps.size(), 4);
327 assertTrue(overlaps.contains(sf7));
328 assertFalse(overlaps.contains(sf8));
329 assertTrue(overlaps.contains(sf9));
330 assertTrue(overlaps.contains(sf10));
331 assertTrue(overlaps.contains(sf11));
332 assertFalse(overlaps.contains(sf12));
334 assertTrue(sf.findFeatures(0, 1000, "Metal").isEmpty());
336 overlaps = sf.findFeatures(7, 7, (String) null);
337 assertTrue(overlaps.isEmpty());
340 @Test(groups = "Functional")
341 public void testDelete()
343 SequenceFeaturesI sf = new SequenceFeatures();
344 SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
345 assertTrue(sf.getPositionalFeatures().contains(sf1));
347 assertFalse(sf.delete(null));
348 SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 15, 0f, null);
349 assertFalse(sf.delete(sf2)); // not added, can't delete it
350 assertTrue(sf.delete(sf1));
351 assertTrue(sf.getPositionalFeatures().isEmpty());
354 @Test(groups = "Functional")
355 public void testHasFeatures()
357 SequenceFeaturesI sf = new SequenceFeatures();
358 assertFalse(sf.hasFeatures());
360 SequenceFeature sf1 = addFeature(sf, "Pfam", 10, 50);
361 assertTrue(sf.hasFeatures());
364 assertFalse(sf.hasFeatures());
368 * Tests for the method that gets feature groups for positional or
369 * non-positional features
371 @Test(groups = "Functional")
372 public void testGetFeatureGroups()
374 SequenceFeaturesI sf = new SequenceFeatures();
375 assertTrue(sf.getFeatureGroups(true).isEmpty());
376 assertTrue(sf.getFeatureGroups(false).isEmpty());
379 * add a non-positional feature (begin/end = 0/0)
381 SequenceFeature sfx = new SequenceFeature("AType", "Desc", 0, 0, 0f,
384 Set<String> groups = sf.getFeatureGroups(true); // for positional
385 assertTrue(groups.isEmpty());
386 groups = sf.getFeatureGroups(false); // for non-positional
387 assertEquals(groups.size(), 1);
388 assertTrue(groups.contains("AGroup"));
389 groups = sf.getFeatureGroups(false, "AType");
390 assertEquals(groups.size(), 1);
391 assertTrue(groups.contains("AGroup"));
392 groups = sf.getFeatureGroups(true, "AnotherType");
393 assertTrue(groups.isEmpty());
396 * add, then delete, more non-positional features of different types
398 SequenceFeature sfy = new SequenceFeature("AnotherType", "Desc", 0, 0,
401 SequenceFeature sfz = new SequenceFeature("AThirdType", "Desc", 0, 0,
404 groups = sf.getFeatureGroups(false);
405 assertEquals(groups.size(), 3);
406 assertTrue(groups.contains("AGroup"));
407 assertTrue(groups.contains("AnotherGroup"));
408 assertTrue(groups.contains(null)); // null is a possible group
411 groups = sf.getFeatureGroups(false);
412 assertEquals(groups.size(), 1);
413 assertTrue(groups.contains("AGroup"));
416 * add positional features
418 SequenceFeature sf1 = new SequenceFeature("Pfam", "Desc", 10, 50, 0f,
421 groups = sf.getFeatureGroups(true);
422 assertEquals(groups.size(), 1);
423 assertTrue(groups.contains("PfamGroup"));
424 groups = sf.getFeatureGroups(false); // non-positional unchanged
425 assertEquals(groups.size(), 1);
426 assertTrue(groups.contains("AGroup"));
428 SequenceFeature sf2 = new SequenceFeature("Cath", "Desc", 10, 50, 0f,
431 groups = sf.getFeatureGroups(true);
432 assertEquals(groups.size(), 2);
433 assertTrue(groups.contains("PfamGroup"));
434 assertTrue(groups.contains(null));
438 assertTrue(sf.getFeatureGroups(true).isEmpty());
440 SequenceFeature sf3 = new SequenceFeature("CDS", "", 10, 50, 0f,
443 SequenceFeature sf4 = new SequenceFeature("exon", "", 10, 50, 0f,
446 groups = sf.getFeatureGroups(true);
447 assertEquals(groups.size(), 1);
448 assertTrue(groups.contains("Ensembl"));
451 * delete last Ensembl group feature from CDS features
452 * but still have one in exon features
455 groups = sf.getFeatureGroups(true);
456 assertEquals(groups.size(), 1);
457 assertTrue(groups.contains("Ensembl"));
460 * delete the last non-positional feature
463 groups = sf.getFeatureGroups(false);
464 assertTrue(groups.isEmpty());
467 @Test(groups = "Functional")
468 public void testGetFeatureTypesForGroups()
470 SequenceFeaturesI sf = new SequenceFeatures();
471 assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
474 * add feature with group = "Uniprot", type = "helix"
476 String groupUniprot = "Uniprot";
477 SequenceFeature sf1 = new SequenceFeature("helix", "Desc", 10, 50, 0f,
480 Set<String> groups = sf.getFeatureTypesForGroups(true, groupUniprot);
481 assertEquals(groups.size(), 1);
482 assertTrue(groups.contains("helix"));
483 assertTrue(sf.getFeatureTypesForGroups(true, (String) null).isEmpty());
486 * add feature with group = "Uniprot", type = "strand"
488 SequenceFeature sf2 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
491 groups = sf.getFeatureTypesForGroups(true, groupUniprot);
492 assertEquals(groups.size(), 2);
493 assertTrue(groups.contains("helix"));
494 assertTrue(groups.contains("strand"));
497 * delete the "strand" Uniprot feature - still have "helix"
500 groups = sf.getFeatureTypesForGroups(true, groupUniprot);
501 assertEquals(groups.size(), 1);
502 assertTrue(groups.contains("helix"));
505 * delete the "helix" Uniprot feature - none left
508 assertTrue(sf.getFeatureTypesForGroups(true, groupUniprot).isEmpty());
511 * add some null group features
513 SequenceFeature sf3 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
516 SequenceFeature sf4 = new SequenceFeature("turn", "Desc", 10, 50, 0f,
519 groups = sf.getFeatureTypesForGroups(true, (String) null);
520 assertEquals(groups.size(), 2);
521 assertTrue(groups.contains("strand"));
522 assertTrue(groups.contains("turn"));
525 * add strand/Cath and turn/Scop and query for one or both groups
526 * (find feature types for groups selected in Feature Settings)
528 SequenceFeature sf5 = new SequenceFeature("strand", "Desc", 10, 50, 0f,
531 SequenceFeature sf6 = new SequenceFeature("turn", "Desc", 10, 50, 0f,
534 groups = sf.getFeatureTypesForGroups(true, "Cath");
535 assertEquals(groups.size(), 1);
536 assertTrue(groups.contains("strand"));
537 groups = sf.getFeatureTypesForGroups(true, "Scop");
538 assertEquals(groups.size(), 1);
539 assertTrue(groups.contains("turn"));
540 groups = sf.getFeatureTypesForGroups(true, "Cath", "Scop");
541 assertEquals(groups.size(), 2);
542 assertTrue(groups.contains("turn"));
543 assertTrue(groups.contains("strand"));
544 // alternative vararg syntax
545 groups = sf.getFeatureTypesForGroups(true,
548 assertEquals(groups.size(), 2);
549 assertTrue(groups.contains("turn"));
550 assertTrue(groups.contains("strand"));
553 @Test(groups = "Functional")
554 public void testGetFeatureTypes()
556 SequenceFeaturesI store = new SequenceFeatures();
557 Set<String> types = store.getFeatureTypes();
558 assertTrue(types.isEmpty());
560 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
563 types = store.getFeatureTypes();
564 assertEquals(types.size(), 1);
565 assertTrue(types.contains("Metal"));
567 // null type is rejected...
568 SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20,
570 assertFalse(store.add(sf2));
571 types = store.getFeatureTypes();
572 assertEquals(types.size(), 1);
573 assertFalse(types.contains(null));
574 assertTrue(types.contains("Metal"));
577 * add non-positional feature
579 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
582 types = store.getFeatureTypes();
583 assertEquals(types.size(), 2);
584 assertTrue(types.contains("Pfam"));
587 * add contact feature
589 SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc", 10,
590 20, Float.NaN, null);
592 types = store.getFeatureTypes();
593 assertEquals(types.size(), 3);
594 assertTrue(types.contains("Disulphide Bond"));
599 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
602 types = store.getFeatureTypes();
603 assertEquals(types.size(), 3); // unchanged
606 * delete first Pfam - still have one
608 assertTrue(store.delete(sf3));
609 types = store.getFeatureTypes();
610 assertEquals(types.size(), 3);
611 assertTrue(types.contains("Pfam"));
614 * delete second Pfam - no longer have one
616 assertTrue(store.delete(sf5));
617 types = store.getFeatureTypes();
618 assertEquals(types.size(), 2);
619 assertFalse(types.contains("Pfam"));
622 @Test(groups = "Functional")
623 public void testGetFeatureCount()
625 SequenceFeaturesI store = new SequenceFeatures();
626 assertEquals(store.getFeatureCount(true), 0);
627 assertEquals(store.getFeatureCount(false), 0);
632 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
635 assertEquals(store.getFeatureCount(true), 1);
636 assertEquals(store.getFeatureCount(false), 0);
639 * null feature type is rejected
641 SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20,
643 assertFalse(store.add(sf2));
644 assertEquals(store.getFeatureCount(true), 1);
645 assertEquals(store.getFeatureCount(false), 0);
648 * add non-positional feature
650 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
653 assertEquals(store.getFeatureCount(true), 1);
654 assertEquals(store.getFeatureCount(false), 1);
657 * add contact feature (counts as 1)
659 SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc", 10,
660 20, Float.NaN, null);
662 assertEquals(store.getFeatureCount(true), 2);
663 assertEquals(store.getFeatureCount(false), 1);
666 * add another Pfam but this time as a positional feature
668 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
671 assertEquals(store.getFeatureCount(true), 3); // sf1, sf4, sf5
672 assertEquals(store.getFeatureCount(false), 1); // sf3
673 assertEquals(store.getFeatureCount(true, "Pfam"), 1); // positional
674 assertEquals(store.getFeatureCount(false, "Pfam"), 1); // non-positional
675 // search for type==null
676 assertEquals(store.getFeatureCount(true, (String) null), 0);
677 // search with no type specified
678 assertEquals(store.getFeatureCount(true, (String[]) null), 3);
679 assertEquals(store.getFeatureCount(true, "Metal", "Cath"), 1);
680 assertEquals(store.getFeatureCount(true, "Disulphide Bond"), 1);
681 assertEquals(store.getFeatureCount(true, "Metal", "Pfam", null), 2);
684 * delete first Pfam (non-positional)
686 assertTrue(store.delete(sf3));
687 assertEquals(store.getFeatureCount(true), 3);
688 assertEquals(store.getFeatureCount(false), 0);
691 * delete second Pfam (positional)
693 assertTrue(store.delete(sf5));
694 assertEquals(store.getFeatureCount(true), 2);
695 assertEquals(store.getFeatureCount(false), 0);
698 @Test(groups = "Functional")
699 public void testGetAllFeatures()
701 SequenceFeaturesI store = new SequenceFeatures();
702 List<SequenceFeature> features = store.getAllFeatures();
703 assertTrue(features.isEmpty());
705 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
708 features = store.getAllFeatures();
709 assertEquals(features.size(), 1);
710 assertTrue(features.contains(sf1));
712 SequenceFeature sf2 = new SequenceFeature("Metallic", "desc", 10, 20,
715 features = store.getAllFeatures();
716 assertEquals(features.size(), 2);
717 assertTrue(features.contains(sf2));
720 * add non-positional feature
722 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
725 features = store.getAllFeatures();
726 assertEquals(features.size(), 3);
727 assertTrue(features.contains(sf3));
730 * add contact feature
732 SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc", 10,
733 20, Float.NaN, null);
735 features = store.getAllFeatures();
736 assertEquals(features.size(), 4);
737 assertTrue(features.contains(sf4));
742 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
745 features = store.getAllFeatures();
746 assertEquals(features.size(), 5);
747 assertTrue(features.contains(sf5));
750 * select by type does not apply to non-positional features
752 features = store.getAllFeatures("Cath");
753 assertEquals(features.size(), 1);
754 assertTrue(features.contains(sf3));
756 features = store.getAllFeatures("Pfam", "Cath", "Metal");
757 assertEquals(features.size(), 3);
758 assertTrue(features.contains(sf1));
759 assertTrue(features.contains(sf3));
760 assertTrue(features.contains(sf5));
765 assertTrue(store.delete(sf3));
766 features = store.getAllFeatures();
767 assertEquals(features.size(), 4);
768 assertFalse(features.contains(sf3));
773 assertTrue(store.delete(sf5));
774 features = store.getAllFeatures();
775 assertEquals(features.size(), 3);
776 assertFalse(features.contains(sf3));
779 @Test(groups = "Functional")
780 public void testGetTotalFeatureLength()
782 SequenceFeaturesI store = new SequenceFeatures();
783 assertEquals(store.getTotalFeatureLength(), 0);
785 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
787 assertTrue(store.add(sf1));
788 assertEquals(store.getTotalFeatureLength(), 11);
789 assertEquals(store.getTotalFeatureLength("Metal"), 11);
790 assertEquals(store.getTotalFeatureLength("Plastic"), 0);
792 // re-add does nothing!
793 assertFalse(store.add(sf1));
794 assertEquals(store.getTotalFeatureLength(), 11);
797 * add non-positional feature
799 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0,
802 assertEquals(store.getTotalFeatureLength(), 11);
805 * add contact feature - counts 1 to feature length
807 SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc", 10,
808 20, Float.NaN, null);
810 assertEquals(store.getTotalFeatureLength(), 12);
815 SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20,
818 assertEquals(store.getTotalFeatureLength(), 23);
823 assertTrue(store.delete(sf3)); // non-positional
824 assertEquals(store.getTotalFeatureLength(), 23); // no change
826 assertTrue(store.delete(sf5));
827 assertEquals(store.getTotalFeatureLength(), 12);
829 assertTrue(store.delete(sf4)); // contact
830 assertEquals(store.getTotalFeatureLength(), 11);
832 assertTrue(store.delete(sf1));
833 assertEquals(store.getTotalFeatureLength(), 0);
836 @Test(groups = "Functional")
837 public void testGetMinimumScore_getMaximumScore()
839 SequenceFeatures sf = new SequenceFeatures();
840 SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 0, 0,
841 Float.NaN, "group"); // non-positional, no score
843 SequenceFeature sf2 = new SequenceFeature("Cath", "desc", 10, 20,
844 Float.NaN, "group"); // positional, no score
846 SequenceFeature sf3 = new SequenceFeature("Metal", "desc", 10, 20, 1f,
849 SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 12, 16, 4f,
852 SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 0, 0, 11f,
855 SequenceFeature sf6 = new SequenceFeature("Cath", "desc", 0, 0, -7f,
859 assertEquals(sf.getMinimumScore("nosuchtype", true), Float.NaN);
860 assertEquals(sf.getMinimumScore("nosuchtype", false), Float.NaN);
861 assertEquals(sf.getMaximumScore("nosuchtype", true), Float.NaN);
862 assertEquals(sf.getMaximumScore("nosuchtype", false), Float.NaN);
864 // positional features min-max:
865 assertEquals(sf.getMinimumScore("Metal", true), 1f);
866 assertEquals(sf.getMaximumScore("Metal", true), 4f);
867 assertEquals(sf.getMinimumScore("Cath", true), Float.NaN);
868 assertEquals(sf.getMaximumScore("Cath", true), Float.NaN);
870 // non-positional features min-max:
871 assertEquals(sf.getMinimumScore("Cath", false), -7f);
872 assertEquals(sf.getMaximumScore("Cath", false), 11f);
873 assertEquals(sf.getMinimumScore("Metal", false), Float.NaN);
874 assertEquals(sf.getMaximumScore("Metal", false), Float.NaN);
876 // delete features; min-max should get recomputed
878 assertEquals(sf.getMinimumScore("Cath", false), 11f);
879 assertEquals(sf.getMaximumScore("Cath", false), 11f);
881 assertEquals(sf.getMinimumScore("Metal", true), 1f);
882 assertEquals(sf.getMaximumScore("Metal", true), 1f);
884 assertEquals(sf.getMinimumScore("Cath", false), Float.NaN);
885 assertEquals(sf.getMaximumScore("Cath", false), Float.NaN);
887 assertEquals(sf.getMinimumScore("Metal", true), Float.NaN);
888 assertEquals(sf.getMaximumScore("Metal", true), Float.NaN);
891 assertFalse(sf.hasFeatures());
892 assertEquals(sf.getMinimumScore("Cath", false), Float.NaN);
893 assertEquals(sf.getMaximumScore("Cath", false), Float.NaN);
894 assertEquals(sf.getMinimumScore("Metal", true), Float.NaN);
895 assertEquals(sf.getMaximumScore("Metal", true), Float.NaN);
898 @Test(groups = "Functional")
899 public void testVarargsToTypes()
901 SequenceFeatures sf = new SequenceFeatures();
902 sf.add(new SequenceFeature("Metal", "desc", 0, 0, Float.NaN, "group"));
903 sf.add(new SequenceFeature("Cath", "desc", 10, 20, Float.NaN, "group"));
906 * no type specified - get all types stored
907 * they are returned in keyset (alphabetical) order
909 Map<String, FeatureStore> featureStores = (Map<String, FeatureStore>) PA
910 .getValue(sf, "featureStore");
912 Iterable<FeatureStore> types = sf.varargToTypes();
913 Iterator<FeatureStore> iterator = types.iterator();
914 assertTrue(iterator.hasNext());
915 assertSame(iterator.next(), featureStores.get("Cath"));
916 assertTrue(iterator.hasNext());
917 assertSame(iterator.next(), featureStores.get("Metal"));
918 assertFalse(iterator.hasNext());
921 * empty array is the same as no vararg parameter supplied
922 * so treated as all stored types
924 types = sf.varargToTypes(new String[] {});
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());
933 * null type specified; this is passed as vararg
936 types = sf.varargToTypes((String) null);
937 assertFalse(types.iterator().hasNext());
940 * null types array specified; this is passed as vararg null
942 types = sf.varargToTypes((String[]) null);
943 iterator = types.iterator();
944 assertTrue(iterator.hasNext());
945 assertSame(iterator.next(), featureStores.get("Cath"));
946 assertTrue(iterator.hasNext());
947 assertSame(iterator.next(), featureStores.get("Metal"));
948 assertFalse(iterator.hasNext());
953 types = sf.varargToTypes("Metal");
954 iterator = types.iterator();
955 assertTrue(iterator.hasNext());
956 assertSame(iterator.next(), featureStores.get("Metal"));
957 assertFalse(iterator.hasNext());
960 * two types specified - order is preserved
962 types = sf.varargToTypes("Metal", "Cath");
963 iterator = types.iterator();
964 assertTrue(iterator.hasNext());
965 assertSame(iterator.next(), featureStores.get("Metal"));
966 assertTrue(iterator.hasNext());
967 assertSame(iterator.next(), featureStores.get("Cath"));
968 assertFalse(iterator.hasNext());
971 * null type included - should be ignored
973 types = sf.varargToTypes("Metal", null, "Helix");
974 iterator = types.iterator();
975 assertTrue(iterator.hasNext());
976 assertSame(iterator.next(), featureStores.get("Metal"));
977 assertFalse(iterator.hasNext());
980 @Test(groups = "Functional")
981 public void testGetFeatureTypes_byOntology()
983 SequenceFeaturesI store = new SequenceFeatures();
985 SequenceFeature sf1 = new SequenceFeature("transcript", "desc", 10, 20,
988 // mRNA isA mature_transcript isA transcript
989 SequenceFeature sf2 = new SequenceFeature("mRNA", "desc", 10, 20,
992 // just to prove non-positional feature types are included
993 SequenceFeature sf3 = new SequenceFeature("mRNA", "desc", 0, 0,
996 SequenceFeature sf4 = new SequenceFeature("CDS", "desc", 0, 0,
1000 Set<String> types = store.getFeatureTypes("transcript");
1001 assertEquals(types.size(), 2);
1002 assertTrue(types.contains("transcript"));
1003 assertTrue(types.contains("mRNA"));
1005 // matches include arguments whether SO terms or not
1006 types = store.getFeatureTypes("transcript", "CDS");
1007 assertEquals(types.size(), 3);
1008 assertTrue(types.contains("transcript"));
1009 assertTrue(types.contains("mRNA"));
1010 assertTrue(types.contains("CDS"));
1012 types = store.getFeatureTypes("exon");
1013 assertTrue(types.isEmpty());
1016 @Test(groups = "Functional")
1017 public void testGetFeaturesByOntology()
1019 SequenceFeaturesI store = new SequenceFeatures();
1020 List<SequenceFeature> features = store.getFeaturesByOntology();
1021 assertTrue(features.isEmpty());
1022 assertTrue(store.getFeaturesByOntology(new String[] {}).isEmpty());
1023 assertTrue(store.getFeaturesByOntology((String[]) null).isEmpty());
1025 SequenceFeature transcriptFeature = new SequenceFeature("transcript",
1026 "desc", 10, 20, Float.NaN, null);
1027 store.add(transcriptFeature);
1030 * mRNA is a sub-type of transcript; added here 'as if' non-positional
1031 * just to show that non-positional features are included in results
1033 SequenceFeature mrnaFeature = new SequenceFeature("mRNA", "desc", 0, 0,
1035 store.add(mrnaFeature);
1037 SequenceFeature pfamFeature = new SequenceFeature("Pfam", "desc", 30,
1038 40, Float.NaN, null);
1039 store.add(pfamFeature);
1042 * "transcript" matches both itself and the sub-term "mRNA"
1044 features = store.getFeaturesByOntology("transcript");
1045 assertEquals(features.size(), 2);
1046 assertTrue(features.contains(transcriptFeature));
1047 assertTrue(features.contains(mrnaFeature));
1050 * "mRNA" matches itself but not parent term "transcript"
1052 features = store.getFeaturesByOntology("mRNA");
1053 assertEquals(features.size(), 1);
1054 assertTrue(features.contains(mrnaFeature));
1057 * "pfam" is not an SO term but is included as an exact match
1059 features = store.getFeaturesByOntology("mRNA", "Pfam");
1060 assertEquals(features.size(), 2);
1061 assertTrue(features.contains(mrnaFeature));
1062 assertTrue(features.contains(pfamFeature));
1064 features = store.getFeaturesByOntology("sequence_variant");
1065 assertTrue(features.isEmpty());
1068 @Test(groups = "Functional")
1069 public void testSortFeatures()
1071 List<SequenceFeature> sfs = new ArrayList<>();
1072 SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 30, 60,
1075 SequenceFeature sf2 = new SequenceFeature("Rfam", "desc", 40, 50,
1078 SequenceFeature sf3 = new SequenceFeature("Rfam", "desc", 50, 60,
1081 SequenceFeature sf4 = new SequenceFeature("Xfam", "desc", 30, 80,
1084 SequenceFeature sf5 = new SequenceFeature("Xfam", "desc", 30, 90,
1089 * sort by end position descending, order unchanged if matched
1091 SequenceFeatures.sortFeatures(sfs, false);
1092 assertSame(sfs.get(0), sf5); // end 90
1093 assertSame(sfs.get(1), sf4); // end 80
1094 assertSame(sfs.get(2), sf1); // end 60, start 50
1095 assertSame(sfs.get(3), sf3); // end 60, start 30
1096 assertSame(sfs.get(4), sf2); // end 50
1099 * resort {5, 4, 1, 3, 2} by start position ascending, end descending
1101 SequenceFeatures.sortFeatures(sfs, true);
1102 assertSame(sfs.get(0), sf5); // start 30, end 90
1103 assertSame(sfs.get(1), sf4); // start 30, end 80
1104 assertSame(sfs.get(2), sf1); // start 30, end 60
1105 assertSame(sfs.get(3), sf2); // start 40
1106 assertSame(sfs.get(4), sf3); // start 50
1109 @Test(groups = "Functional")
1110 public void testGetFeaturesForGroup()
1112 SequenceFeaturesI store = new SequenceFeatures();
1114 List<SequenceFeature> features = store.getFeaturesForGroup(true, null);
1115 assertTrue(features.isEmpty());
1116 assertTrue(store.getFeaturesForGroup(false, null).isEmpty());
1117 assertTrue(store.getFeaturesForGroup(true, "Uniprot").isEmpty());
1118 assertTrue(store.getFeaturesForGroup(false, "Uniprot").isEmpty());
1120 SequenceFeature sf1 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
1122 SequenceFeature sf2 = new SequenceFeature("Pfam", "desc", 0, 0, 0f,
1124 SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 4, 10, 0f,
1126 SequenceFeature sf4 = new SequenceFeature("Metal", "desc", 0, 0, 0f,
1128 SequenceFeature sf5 = new SequenceFeature("Cath", "desc", 5, 15, 0f,
1136 // positional features for null group, any type
1137 features = store.getFeaturesForGroup(true, null);
1138 assertEquals(features.size(), 2);
1139 assertTrue(features.contains(sf1));
1140 assertTrue(features.contains(sf5));
1142 // positional features for null group, specified type
1143 features = store.getFeaturesForGroup(true, null,
1145 { "Pfam", "Xfam" });
1146 assertEquals(features.size(), 1);
1147 assertTrue(features.contains(sf1));
1148 features = store.getFeaturesForGroup(true, null,
1150 { "Pfam", "Xfam", "Cath" });
1151 assertEquals(features.size(), 2);
1152 assertTrue(features.contains(sf1));
1153 assertTrue(features.contains(sf5));
1155 // positional features for non-null group, any type
1156 features = store.getFeaturesForGroup(true, "Uniprot");
1157 assertEquals(features.size(), 1);
1158 assertTrue(features.contains(sf3));
1159 assertTrue(store.getFeaturesForGroup(true, "Rfam").isEmpty());
1161 // positional features for non-null group, specified type
1162 features = store.getFeaturesForGroup(true, "Uniprot", "Pfam", "Xfam",
1164 assertEquals(features.size(), 1);
1165 assertTrue(features.contains(sf3));
1167 store.getFeaturesForGroup(true, "Uniprot", "Cath").isEmpty());
1169 // non-positional features for null group, any type
1170 features = store.getFeaturesForGroup(false, null);
1171 assertEquals(features.size(), 1);
1172 assertTrue(features.contains(sf2));
1174 // non-positional features for null group, specified type
1175 features = store.getFeaturesForGroup(false, null, "Pfam", "Xfam");
1176 assertEquals(features.size(), 1);
1177 assertTrue(features.contains(sf2));
1178 assertTrue(store.getFeaturesForGroup(false, null, "Cath").isEmpty());
1180 // non-positional features for non-null group, any type
1181 features = store.getFeaturesForGroup(false, "Rfam");
1182 assertEquals(features.size(), 1);
1183 assertTrue(features.contains(sf4));
1184 assertTrue(store.getFeaturesForGroup(false, "Uniprot").isEmpty());
1186 // non-positional features for non-null group, specified type
1187 features = store.getFeaturesForGroup(false, "Rfam", "Pfam", "Metal");
1188 assertEquals(features.size(), 1);
1189 assertTrue(features.contains(sf4));
1190 assertTrue(store.getFeaturesForGroup(false, "Rfam", "Cath", "Pfam")
1194 @Test(groups = "Functional")
1195 public void testShiftFeatures()
1197 SequenceFeatures store = new SequenceFeatures();
1198 assertFalse(store.shiftFeatures(0, 1));
1200 SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
1203 SequenceFeature sf2 = new SequenceFeature("Metal", "", 8, 14, 0f, null);
1206 SequenceFeature sf3 = new SequenceFeature("Disulfide bond", "", 23, 32,
1209 // non-positional feature:
1210 SequenceFeature sf4 = new SequenceFeature("Pfam", "", 0, 0, 0f, null);
1214 * shift features right by 5
1216 assertTrue(store.shiftFeatures(0, 5));
1218 // non-positional features untouched:
1219 List<SequenceFeature> nonPos = store.getNonPositionalFeatures();
1220 assertEquals(nonPos.size(), 1);
1221 assertTrue(nonPos.contains(sf4));
1223 // positional features are replaced
1224 List<SequenceFeature> pos = store.getPositionalFeatures();
1225 assertEquals(pos.size(), 3);
1226 assertFalse(pos.contains(sf1));
1227 assertFalse(pos.contains(sf2));
1228 assertFalse(pos.contains(sf3));
1229 SequenceFeatures.sortFeatures(pos, true); // ascending start pos
1230 assertEquals(pos.get(0).getBegin(), 7);
1231 assertEquals(pos.get(0).getEnd(), 10);
1232 assertEquals(pos.get(0).getType(), "Cath");
1233 assertEquals(pos.get(1).getBegin(), 13);
1234 assertEquals(pos.get(1).getEnd(), 19);
1235 assertEquals(pos.get(1).getType(), "Metal");
1236 assertEquals(pos.get(2).getBegin(), 28);
1237 assertEquals(pos.get(2).getEnd(), 37);
1238 assertEquals(pos.get(2).getType(), "Disulfide bond");
1241 * now shift left by 15
1242 * feature at [7-10] should be removed
1243 * feature at [13-19] should become [1-4]
1245 assertTrue(store.shiftFeatures(0, -15));
1246 pos = store.getPositionalFeatures();
1247 assertEquals(pos.size(), 2);
1248 SequenceFeatures.sortFeatures(pos, true);
1249 assertEquals(pos.get(0).getBegin(), 1);
1250 assertEquals(pos.get(0).getEnd(), 4);
1251 assertEquals(pos.get(0).getType(), "Metal");
1252 assertEquals(pos.get(1).getBegin(), 13);
1253 assertEquals(pos.get(1).getEnd(), 22);
1254 assertEquals(pos.get(1).getType(), "Disulfide bond");
1257 * shift right by 4 from column 2
1258 * feature at [1-4] should be unchanged
1259 * feature at [13-22] should become [17-26]
1261 assertTrue(store.shiftFeatures(2, 4));
1262 pos = store.getPositionalFeatures();
1263 assertEquals(pos.size(), 2);
1264 SequenceFeatures.sortFeatures(pos, true);
1265 assertEquals(pos.get(0).getBegin(), 1);
1266 assertEquals(pos.get(0).getEnd(), 4);
1267 assertEquals(pos.get(0).getType(), "Metal");
1268 assertEquals(pos.get(1).getBegin(), 17);
1269 assertEquals(pos.get(1).getEnd(), 26);
1270 assertEquals(pos.get(1).getType(), "Disulfide bond");
1273 * shift right from column 18
1274 * should be no updates
1276 SequenceFeature f1 = pos.get(0);
1277 SequenceFeature f2 = pos.get(1);
1278 assertFalse(store.shiftFeatures(18, 6));
1279 pos = store.getPositionalFeatures();
1280 assertEquals(pos.size(), 2);
1281 SequenceFeatures.sortFeatures(pos, true);
1282 assertSame(pos.get(0), f1);
1283 assertSame(pos.get(1), f2);
1286 @Test(groups = "Functional")
1287 public void testIsOntologyTerm()
1289 SequenceFeatures store = new SequenceFeatures();
1290 assertTrue(store.isOntologyTerm("gobbledygook"));
1291 assertTrue(store.isOntologyTerm("transcript", "transcript"));
1292 assertTrue(store.isOntologyTerm("mRNA", "transcript"));
1293 assertFalse(store.isOntologyTerm("transcript", "mRNA"));
1294 assertTrue(store.isOntologyTerm("junk", "transcript", "junk"));
1295 assertTrue(store.isOntologyTerm("junk", new String[] {}));
1296 assertTrue(store.isOntologyTerm("junk", (String[]) null));
1299 @Test(groups = "Functional")
1300 public void testDeleteAll()
1302 SequenceFeaturesI store = new SequenceFeatures();
1303 assertFalse(store.hasFeatures());
1305 assertFalse(store.hasFeatures());
1306 store.add(new SequenceFeature("Cath", "Desc", 12, 20, 0f, "Group"));
1307 store.add(new SequenceFeature("Pfam", "Desc", 6, 12, 2f, "Group2"));
1308 assertTrue(store.hasFeatures());
1310 assertFalse(store.hasFeatures());