a b/tests/test_features.py
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
import unittest
4
import itertools
5
6
from singlecellmultiomics.features import FeatureContainer
7
8
"""
9
These tests check if the feature container is working correctly
10
"""
11
12
class TestFeatureContainer(unittest.TestCase):
13
14
15
    def expect(self, result, desired, presenceTestOnly=False):
16
        if presenceTestOnly:
17
            self.assertTrue( any( r[2] in desired for r in result) )
18
        if desired is None:
19
            self.assertTrue(len(result)==0)
20
        elif type(desired) is list:
21
            self.assertTrue( len(result)==len(desired) and all( r[2] in desired for r in result))
22
        else:
23
            self.assertTrue( len(result)==1 and result[0][2]==desired )
24
25
    def test_add(self):
26
        f = FeatureContainer()
27
        f.addFeature('chrY', 1, 3, 'A','+','')
28
        f.addFeature('chrY', 5, 8, 'B','+','')
29
        f.sort()
30
        self.expect( f.findFeaturesAt('chrY',0,'+'), None)
31
        self.expect( f.findFeaturesAt('chrY',1,'+'), 'A')
32
        self.expect( f.findFeaturesAt('chrY',2,'+'), 'A')
33
        self.expect( f.findFeaturesAt('chrY',3,'+'), 'A')
34
        self.expect( f.findFeaturesAt('chrY',4,'+'), None)
35
        self.expect( f.findFeaturesAt('chrY',5,'+'), 'B')
36
        self.expect( f.findFeaturesAt('chrY',6,'+'), 'B')
37
        self.expect( f.findFeaturesAt('chrY',8,'+'), 'B')
38
39
    def test_nested(self):
40
        f = FeatureContainer()
41
        f.addFeature('chrX', 10, 1000, 'parentB','+','')
42
        f.addFeature('chrX', 500, 900, 'nestedB','+','')
43
        f.addFeature('chrX', 10000, 12000, 'C','+','')
44
        f.addFeature('chrX', 100000, 120000, 'D','+','')
45
        f.sort()
46
        self.expect( f.findFeaturesAt('chrX',9,'+'), None)
47
        self.expect( f.findFeaturesAt('chrX',12001,'+'), None)
48
        self.expect( f.findFeaturesAt('chrX',12000,'+'), 'C')
49
        self.expect( f.findFeaturesAt('chrX',120000,'+'), 'D')
50
        self.expect( f.findFeaturesAt('chrX',10,'+'), 'parentB')
51
52
    def test_len(self):
53
        f = FeatureContainer()
54
        f.addFeature('chr1',100, 200,  '1','+','A forward feature from 100 to 200 chr1')
55
        f.addFeature('chr1',110, 200, '2','-',  'A reverse feature from 110 to 200 chr1')
56
        f.addFeature('chr2',100, 200,  '3', '+', 'A forward feature from 100 to 200 chr2')
57
        f.addFeature('chr2',100, 110,  '4','+', 'A forward feature from 100 to 110 chr2')
58
        f.addFeature('chr2',100, 150,  '5', '-','A reverse feature from 100 to 150 chr2')
59
        self.assertEqual( len(f) , 5)
60
61
    def test_stranded(self):
62
        f = FeatureContainer()
63
        f.addFeature('chr1',100, 200,  '1','+','A forward feature from 100 to 200 chr1')
64
        f.addFeature('chr1',110, 200, '2','-',  'A reverse feature from 110 to 200 chr1')
65
        f.addFeature('chr2',100, 200,  '3', '+', 'A forward feature from 100 to 200 chr2')
66
        f.addFeature('chr2',100, 110,  '4','+', 'A forward feature from 100 to 110 chr2')
67
        f.addFeature('chr2',100, 150,  '5', '-','A reverse feature from 100 to 150 chr2')
68
69
        f.addFeature('chr3',100, 150,  '6', '-','feature 6')
70
        f.addFeature('chr3',200, 250,  '7', '-','feature 7')
71
        f.addFeature('chr3',200, 450,  '8', '-','feature 8')
72
        f.addFeature('chr3',10, 15,  '9', '-','feature 9')
73
        f.sort()
74
75
        #printFormatted("[BRIGHT]Test for reference presence:")
76
        result = f.getReferenceList()
77
        desired = ['chr1','chr2','chr3']
78
        #printFormatted("self.expecting %s, %s" % (desired, ("[BRIGHT][GREEN] SUCCES [RESET][DIM]%s\n" % result) if len(result)==len(desired) and all( r in desired for r in result) else '[RED]FAIL %s\n' % result ))
79
80
        #printFormatted("[BRIGHT]Test on leftmost start:")
81
        self.expect( f.findFeaturesAt('chr1',100,'+'), '1')
82
83
        #printFormatted("[BRIGHT]Test on rightmost end:")
84
        self.expect( f.findFeaturesAt('chr1',200,'+'), '1')
85
86
        #printFormatted("[BRIGHT]Test on random location within feature:")
87
        self.expect(  f.findFeaturesAt('chr1',120,'+'), '1')
88
89
        #printFormatted("[BRIGHT]Test on random location within feature:")
90
        self.expect( f.findFeaturesAt('chr2',120,'+'), '3')
91
92
        #printFormatted("[BRIGHT]Test on limit location of feature:")
93
        self.expect( f.findFeaturesAt('chr2',200,'+'), '3')
94
95
        #printFormatted("[BRIGHT]Test on non matching location (match available on other side, and one base left of coord):")
96
        self.expect( f.findFeaturesAt('chr2',151,'-'), None)
97
98
99
    def test_double_matching(self):
100
        f = FeatureContainer()
101
        f.addFeature('chr1',100, 200,  '1','+','A forward feature from 100 to 200 chr1')
102
        f.addFeature('chr1',110, 200, '2','-',  'A reverse feature from 110 to 200 chr1')
103
        f.addFeature('chr2',100, 200,  '3', '+', 'A forward feature from 100 to 200 chr2')
104
        f.addFeature('chr2',100, 110,  '4','+', 'A forward feature from 100 to 110 chr2')
105
        f.addFeature('chr2',100, 150,  '5', '-','A reverse feature from 100 to 150 chr2')
106
107
        f.addFeature('chr3',100, 150,  '6', '-','feature 6')
108
        f.addFeature('chr3',200, 250,  '7', '-','feature 7')
109
        f.addFeature('chr3',200, 450,  '8', '-','feature 8')
110
        f.addFeature('chr3',10, 15,  '9', '-','feature 9')
111
        f.sort()
112
        #printFormatted("[BRIGHT]Tests on double matching locations without strand spec")
113
        self.expect( f.findFeaturesAt('chr1',120), ['1','2'])
114
        self.expect( f.findFeaturesAt('chr2',105), ['3','4','5'])
115
116
117
    def test_ranges(self):
118
        f = FeatureContainer()
119
        f.addFeature('chr1',100, 200,  '1','+','A forward feature from 100 to 200 chr1')
120
        f.addFeature('chr1',110, 200, '2','-',  'A reverse feature from 110 to 200 chr1')
121
        f.addFeature('chr2',100, 200,  '3', '+', 'A forward feature from 100 to 200 chr2')
122
        f.addFeature('chr2',100, 110,  '4','+', 'A forward feature from 100 to 110 chr2')
123
        f.addFeature('chr2',100, 150,  '5', '-','A reverse feature from 100 to 150 chr2')
124
125
        f.addFeature('chr3',100, 150,  '6', '-','feature 6')
126
        f.addFeature('chr3',200, 250,  '7', '-','feature 7')
127
        f.addFeature('chr3',200, 450,  '8', '-','feature 8')
128
        f.addFeature('chr3',10, 15,  '9', '-','feature 9')
129
        f.sort()
130
131
        #printFormatted("[BRIGHT] ==== Range tests... ====" )
132
        #printFormatted("[BRIGHT]Test for matching start and end coordinates overlapping one feature")
133
        self.expect(  f.findFeaturesBetween('chr2',102, 200, '+' ), ['3','4'])
134
135
        #printFormatted("[BRIGHT]Test for matching all features on chromosome")
136
        self.expect(  f.findFeaturesBetween('chr2',0, 20000, None ), ['3','4','5'])
137
138
        #printFormatted("[BRIGHT]Test for matching all but one features on chromosome")
139
        self.expect(  f.findFeaturesBetween('chr3',151, 20000, None ), ['8','7'])
140
141
        #printFormatted("[BRIGHT]Test for matching all but one features on chromosome")
142
        self.expect(  f.findFeaturesBetween('chr3',0, 195, None ), ['6','9'])
143
144
        #printFormatted("[BRIGHT]Test for range finding non-existent feature")
145
        self.expect(  f.findFeaturesBetween('chr2', 2001, 2000, '+' ), None)
146
147
148
        #printFormatted("[BRIGHT]Test for finding non-existent feature LEFT NEXT to the point")
149
        self.expect(  f.findNearestLeftFeature('chr2', 50, '+' ), None)
150
151
        #printFormatted("[BRIGHT]Test for finding existent feature LEFT NEXT to the point")
152
        self.expect(  f.findNearestLeftFeature('chr2', 250, None ), '3')
153
154
155
        #printFormatted("[BRIGHT]Test for finding non-existent feature RIGHT NEXT to the point")
156
        self.expect(  f.findNearestRightFeature('chr2', 250, '+' ), None)
157
158
        #printFormatted("[BRIGHT]Test for finding existent feature RIGHT NEXT to the point")
159
        self.expect(  f.findNearestRightFeature('chr2', 0, '-' ), '5')
160
161
162
        #printFormatted("[BRIGHT]Test for finding closest feature")
163
        self.expect(  f.findNearestFeature('chr1', 0, None ), '1')
164
165
166
if __name__ == '__main__':
167
    unittest.main()