Handle subseq when the parent is on the minus strand
[mussa.git] / alg / test / test_seq_span.cpp
1 #define BOOST_AUTO_TEST_MAIN
2 #include <boost/test/auto_unit_test.hpp>
3
4 #include "seq_span.hpp"
5 #include "mussa_exceptions.hpp"
6
7 #include <stdlib.h>
8
9 BOOST_AUTO_TEST_CASE( seqspan_from_string )
10 {
11   std::string str1("AAGGCCTT");
12   SeqSpanRef span1(new SeqSpan(str1));
13   BOOST_CHECK_EQUAL(span1->length(), str1.length());
14   BOOST_CHECK_EQUAL(span1->sequence(), str1);
15   BOOST_CHECK_EQUAL(span1->strand(), SeqSpan::PlusStrand);
16 }
17
18 BOOST_AUTO_TEST_CASE( seqspan_from_string_with_alphabet )
19 {
20   std::string str1("AAGGCCUU");
21   SeqSpanRef span1(new SeqSpan(str1, reduced_rna_alphabet));
22   BOOST_CHECK_EQUAL(span1->length(), str1.length());
23   BOOST_CHECK_EQUAL(span1->sequence(), str1);
24   BOOST_CHECK_EQUAL(span1->get_alphabet(), Alphabet::reduced_rna_alphabet());
25 }
26
27 BOOST_AUTO_TEST_CASE( seqspan_from_string_with_alphabet_and_plusstrand )
28 {
29   std::string str1("AAGGCCUU");
30   SeqSpanRef span1(new SeqSpan(str1, reduced_rna_alphabet, SeqSpan::PlusStrand));
31   BOOST_CHECK_EQUAL(span1->length(), str1.length());
32   BOOST_CHECK_EQUAL(span1->sequence(), str1);
33   BOOST_CHECK_EQUAL(span1->get_alphabet(), Alphabet::reduced_rna_alphabet());
34   BOOST_CHECK_EQUAL(span1->strand(), SeqSpan::PlusStrand);
35 }
36
37 BOOST_AUTO_TEST_CASE( seqspan_from_string_with_alphabet_and_singlestrand )
38 {
39   std::string str1("AAAAGCT");
40   SeqSpanRef span1(new SeqSpan(str1, reduced_dna_alphabet, SeqSpan::SingleStrand));
41   BOOST_CHECK_EQUAL(span1->length(), str1.length());
42   BOOST_CHECK_EQUAL(span1->sequence(), str1);
43   BOOST_CHECK_EQUAL(span1->get_alphabet(), Alphabet::reduced_dna_alphabet());
44   // we always store strands as Plus
45   BOOST_CHECK_EQUAL(span1->strand(), SeqSpan::SingleStrand);
46   BOOST_CHECK_EQUAL(span1->sequence(), "AAAAGCT");
47   BOOST_CHECK_THROW(span1->subseq(0,2,SeqSpan::OppositeStrand), sequence_invalid_strand);
48 }
49
50 BOOST_AUTO_TEST_CASE( seqspan_from_string_with_invalidstrand )
51 {
52   std::string s("AAAAGCT");
53   BOOST_CHECK_THROW(SeqSpan(s, reduced_dna_alphabet, SeqSpan::UnknownStrand), sequence_invalid_strand);
54   BOOST_CHECK_THROW(SeqSpan(s, reduced_dna_alphabet, SeqSpan::BothStrand), sequence_invalid_strand);
55   BOOST_CHECK_THROW(SeqSpan(s, reduced_dna_alphabet, SeqSpan::SameStrand), sequence_invalid_strand);
56   BOOST_CHECK_THROW(SeqSpan(s, reduced_dna_alphabet, SeqSpan::OppositeStrand), sequence_invalid_strand);
57   BOOST_CHECK_THROW(SeqSpan(s, reduced_dna_alphabet, SeqSpan::BothStrand), sequence_invalid_strand);
58 }
59
60 BOOST_AUTO_TEST_CASE( seqspan_from_seqspan )
61 {
62   std::string str1("AAGGCCTT");
63   SeqSpanRef span1(new SeqSpan(str1));
64   SeqSpanRef span2(new SeqSpan(span1));
65   SeqSpanRef span3(new SeqSpan(span1));
66   
67   BOOST_CHECK_EQUAL(span1->length(), str1.length());
68   BOOST_CHECK_EQUAL(span1->sequence(), str1);
69   BOOST_CHECK_EQUAL(span1->length(), span2->length());
70   BOOST_CHECK_EQUAL(span2->sequence(), str1);
71
72   BOOST_CHECK_EQUAL(span1->length(), span3->length());
73   BOOST_CHECK_EQUAL(span3->sequence(), str1);
74 }
75
76 BOOST_AUTO_TEST_CASE( seqspan_equality )
77 {
78   std::string str1("AAGGCCTT");
79   std::string str2("AACCGGTT");
80   std::string str3("AACCGGTT");
81   SeqSpanRef span1(new SeqSpan(str1));
82   SeqSpanRef span1copy(new SeqSpan(span1));
83   SeqSpanRef span2(new SeqSpan(str2));
84   SeqSpanRef span3(new SeqSpan(str3));
85   
86   BOOST_CHECK_EQUAL(*span1, *span1copy);
87   BOOST_CHECK(*span1 != *span3);
88   // if its different source strings, compare the underlying string
89   BOOST_CHECK(*span2 != *span3);
90   BOOST_CHECK_EQUAL(SeqSpan::isFamily(*span2, *span3), false);
91 }
92
93 BOOST_AUTO_TEST_CASE( seqspan_find_first_not_of )
94 {
95   std::string str1("AAAAT");
96   SeqSpan seq1(str1);
97   BOOST_CHECK_EQUAL(seq1.find_first_not_of("A"), str1.find_first_not_of("A"));
98   
99   std::string str2("AATTGGCC");
100   SeqSpan seq2(str2);
101   BOOST_CHECK_EQUAL(seq2.find_first_not_of("qwer"), str2.find_first_not_of("qwer"));
102 }
103
104 BOOST_AUTO_TEST_CASE( seqspan_at )
105 {
106   std::string str1("AAGGCCTT");
107   SeqSpanRef seq1(new SeqSpan(str1));
108   SeqSpanRef seq2(new SeqSpan(seq1, 2, 2));
109   
110   BOOST_CHECK_EQUAL( seq1->at(0), str1.at(0) );
111   BOOST_CHECK_EQUAL( seq1->at(2), seq2->at(0) );
112   BOOST_CHECK_EQUAL( str1[2], seq2->at(0) ); 
113   BOOST_CHECK_EQUAL( (*seq1)[0], seq1->at(0) );
114   BOOST_CHECK_EQUAL( (*seq1)[2], (*seq2)[0] );
115   
116   SeqSpanRef seq3 = seq1->subseq(0, 4, SeqSpan::OppositeStrand);
117   BOOST_CHECK_EQUAL( seq3->at(0), 'C');
118   BOOST_CHECK_EQUAL( seq3->at(1), 'C');
119   BOOST_CHECK_EQUAL( seq3->at(2), 'T');
120   BOOST_CHECK_EQUAL( seq3->at(3), 'T');
121   
122 }
123
124 BOOST_AUTO_TEST_CASE( seqspan_data ) 
125 {
126   std::string str1("AAGGCCTT");
127   SeqSpanRef seq1(new SeqSpan(str1));
128   SeqSpanRef seq2(new SeqSpan(seq1, 3, 2));
129
130   BOOST_REQUIRE_EQUAL( str1.length(), seq1->length());
131   BOOST_CHECK_EQUAL( str1.data(), seq1->data() );
132   std::string str1sub = str1.substr(3,2);
133   BOOST_REQUIRE_EQUAL( seq2->size(), str1sub.size() );
134   BOOST_REQUIRE_EQUAL( seq2->length(), str1sub.length() );
135   for (int i = 0; i != seq2->size(); ++i) {
136     BOOST_CHECK_EQUAL( seq2->data()[i], str1sub.data()[i] );
137   }
138 }
139
140 BOOST_AUTO_TEST_CASE( seqspan_begin_end )
141 {
142   std::string str1("AAGGCCTT");
143   SeqSpanRef seq1(new SeqSpan(str1));
144   SeqSpanRef seq2(new SeqSpan(seq1, 2, 2));
145   
146   BOOST_CHECK(seq1->begin() + 2 == seq2->begin());
147   
148   std::string::const_iterator str1_i = str1.begin();
149   SeqSpan::const_iterator seq1_i = seq1->begin();
150   for(; not ((str1_i == str1.end()) or (seq1_i == seq1->end())); ++str1_i, ++seq1_i) {
151     BOOST_CHECK_EQUAL( *str1_i, *seq1_i );
152   }   
153 }
154
155 BOOST_AUTO_TEST_CASE( seqspan_subseq_reverse_begin_end )
156 {
157   std::string str1("AAAACCTT");
158   std::string str1rc("AAGGTTTT");
159   SeqSpanRef seq1(new SeqSpan(str1));
160   SeqSpanRef seq2(new SeqSpan(seq1, 0, SeqSpan::npos, SeqSpan::OppositeStrand ));
161   
162   
163   std::string::const_iterator str1rc_i = str1rc.begin();
164   SeqSpan::const_iterator seq2_i = seq2->begin();
165   for(; not ((str1rc_i == str1rc.end()) or (seq2_i == seq2->end())); ++str1rc_i, ++seq2_i) {
166     BOOST_CHECK_EQUAL( *str1rc_i, *seq2_i );
167   }   
168 }
169
170 BOOST_AUTO_TEST_CASE( seqspan_rbegin_rend )
171 {
172   std::string str1("AAGGCCTT");
173   SeqSpanRef seq1(new SeqSpan(str1));
174   
175   std::string::const_reverse_iterator str1_i = str1.rbegin();
176   SeqSpan::const_reverse_iterator seq1_i = seq1->rbegin();
177   for(; seq1_i != seq1->rend(); ++str1_i, ++seq1_i) {
178     BOOST_CHECK_EQUAL( *str1_i, *seq1_i );
179   }   
180 }
181
182 BOOST_AUTO_TEST_CASE( seqspan_empty_start_stop )
183 {
184   SeqSpanRef s1(new SeqSpan(""));
185   BOOST_CHECK_EQUAL( s1->start(), 0 );
186   BOOST_CHECK_EQUAL( s1->stop(), 0 );
187
188   BOOST_CHECK_EQUAL( s1->parentStart(), 0 );
189   BOOST_CHECK_EQUAL( s1->parentStop(), 0 );
190   
191   BOOST_CHECK_EQUAL( s1->size(), 0 );
192 }
193
194 BOOST_AUTO_TEST_CASE( seqspan_global_start_stop )
195 {
196   std::string seq_string("AAGGCCTT");
197   SeqSpanRef s1(new SeqSpan(seq_string));
198   BOOST_CHECK_EQUAL( s1->start(), 0 );
199   BOOST_CHECK_EQUAL( s1->stop(), seq_string.size() );
200
201   std::string s2seq_string = seq_string.substr(2,3);
202   SeqSpanRef s2 = s1->subseq(2,3);
203   BOOST_CHECK_EQUAL( s2->start(), 2);
204   BOOST_CHECK_EQUAL( s2->stop(), 2+3);
205   BOOST_CHECK_EQUAL( s2->size(), 3);
206   BOOST_CHECK_EQUAL( s2->sequence(), s2seq_string);
207   
208   std::string s3seq_string = s2seq_string.substr(1,1);
209   SeqSpanRef s3 = s2->subseq(1,1);
210   BOOST_CHECK_EQUAL( s3->start(), 2+1 );
211   BOOST_CHECK_EQUAL( s3->stop(), 2+1+1);
212   BOOST_CHECK_EQUAL( s3->size(), 1);
213   BOOST_CHECK_EQUAL( s3->sequence(), s3seq_string);
214 }
215
216 BOOST_AUTO_TEST_CASE( seqspan_global_to_large )
217 {
218   std::string seq_string("AAGGCCTT");
219   SeqSpanRef s1(new SeqSpan(seq_string));
220   BOOST_CHECK_EQUAL( s1->start(), 0 );
221   BOOST_CHECK_EQUAL( s1->stop(), seq_string.size() );
222
223   std::string s2seq_string = seq_string.substr(2,3);
224   SeqSpanRef s2 = s1->subseq(4,8);
225   BOOST_CHECK_EQUAL( s2->start(), 4);
226   BOOST_CHECK_EQUAL( s2->size(), 4);
227   BOOST_CHECK_EQUAL( s2->stop(), 8);
228 }
229
230 BOOST_AUTO_TEST_CASE( seqspan_parent_start_stop )
231 {
232   std::string seq_string("AAGGCCTT");
233   SeqSpanRef s1(new SeqSpan(seq_string));
234   BOOST_CHECK_EQUAL( s1->parentStart(), 0 );
235   BOOST_CHECK_EQUAL( s1->parentStop(), seq_string.size() );
236
237   std::string s2seq_string = seq_string.substr(2,3);
238   SeqSpanRef s2 = s1->subseq(2,3);
239   BOOST_CHECK_EQUAL( s2->parentStart(), 2);
240   BOOST_CHECK_EQUAL( s2->parentStop(), 2+3);
241   BOOST_CHECK_EQUAL( s2->size(), 3);
242   BOOST_CHECK_EQUAL( s2->sequence(), s2seq_string);
243   
244   std::string s3seq_string = s2seq_string.substr(1,1);
245   SeqSpanRef s3 = s2->subseq(1,1);
246   BOOST_CHECK_EQUAL( s3->parentStart(), 1 );
247   BOOST_CHECK_EQUAL( s3->parentStop(), 1+1);
248   BOOST_CHECK_EQUAL( s3->size(), 1);
249   BOOST_CHECK_EQUAL( s3->sequence(), s3seq_string);
250 }
251
252 BOOST_AUTO_TEST_CASE( seqspan_global_mutable_start_stop )
253 {
254   std::string seq_string("AAGGCCTT");
255   SeqSpanRef s1(new SeqSpan(seq_string));
256
257   std::string s2seq_string = seq_string.substr(2,3);
258   SeqSpanRef s2 = s1->subseq(2,3);
259   BOOST_CHECK_EQUAL( s2->start(), 2);
260   BOOST_CHECK_EQUAL( s2->stop(), 2+3);
261   BOOST_CHECK_EQUAL( s2->size(), 3);
262   BOOST_CHECK_EQUAL( s2->sequence(), s2seq_string);
263   
264   std::string s3seq_string = s2seq_string.substr(1,1);
265   SeqSpanRef s3 = s2->subseq(1,1);
266   // Check root location
267   BOOST_CHECK_EQUAL( s3->start(), 2+1 );
268   BOOST_CHECK_EQUAL( s3->stop(), 2+1+1);
269   BOOST_CHECK_EQUAL( s3->size(), 1);
270   // Check parent location
271   BOOST_CHECK_EQUAL( s3->parentStart(), 1 );
272   BOOST_CHECK_EQUAL( s3->parentStop(), 1+1);
273   BOOST_CHECK_EQUAL( s3->sequence(), s3seq_string);
274   
275   // Extend s2 to the left
276   s2->setStart(1);  
277   BOOST_CHECK_EQUAL( s2->start(), 1);
278   BOOST_CHECK_EQUAL( s2->stop(), 1+1+3);
279   BOOST_CHECK_EQUAL( s2->size(), 4);
280
281   // Child sequence should have the same global location  
282   BOOST_CHECK_EQUAL( s3->start(), 2+1 );
283   BOOST_CHECK_EQUAL( s3->stop(), 2+1+1);
284   BOOST_CHECK_EQUAL( s3->size(), 1);
285   // Child sequence should now have different parent location
286   BOOST_CHECK_EQUAL( s3->parentStart(), 2 );
287   BOOST_CHECK_EQUAL( s3->parentStop(), 2+1);
288   BOOST_CHECK_EQUAL( s3->size(), 1);
289 }
290
291 BOOST_AUTO_TEST_CASE( seqspan_global_mutable_start_stop_minus_strand )
292 {
293   std::string seq_string("AAAAGCTA");
294   SeqSpanRef s1(new SeqSpan(seq_string));
295
296   SeqSpanRef s2 = s1->subseq(2,3, SeqSpan::MinusStrand);
297   BOOST_CHECK_EQUAL( s2->start(), 2);
298   BOOST_CHECK_EQUAL( s2->stop(), 2+3);
299   BOOST_CHECK_EQUAL( s2->size(), 3);
300   BOOST_CHECK_EQUAL( s2->sequence(), "CTT");
301   
302   SeqSpanRef s3 = s2->subseq(1,2, SeqSpan::SameStrand);
303   BOOST_CHECK_EQUAL(s3->sequence(), "TT");
304   
305   // Could also argue that it should be CT
306   // if you assume that the locations are all relative to the global sequence
307   // and are then reverse complemented
308   
309   s2->setStart(1);
310   BOOST_CHECK_EQUAL( s2->sequence(), "CTTT");
311 }
312
313 BOOST_AUTO_TEST_CASE( seqspan_parent_mutable_start_stop )
314 {
315   std::string seq_string("AAGGCCTT");
316   SeqSpanRef s1(new SeqSpan(seq_string));
317
318   std::string s2seq_string = seq_string.substr(3,3);
319   SeqSpanRef s2 = s1->subseq(3,3);
320   BOOST_CHECK_EQUAL( s2->start(), 3);
321   BOOST_CHECK_EQUAL( s2->stop(), 3+3);
322   BOOST_CHECK_EQUAL( s2->size(), 3);
323   BOOST_CHECK_EQUAL( s2->sequence(), s2seq_string);
324   
325   std::string s3seq_string = s2seq_string.substr(1,1);
326   SeqSpanRef s3 = s2->subseq(1,1);
327   // Check root location
328   BOOST_CHECK_EQUAL( s3->start(), 3+1 );
329   BOOST_CHECK_EQUAL( s3->stop(), 3+1+1);
330   BOOST_CHECK_EQUAL( s3->size(), 1);
331   // Check parent location
332   BOOST_CHECK_EQUAL( s3->parentStart(), 1 );
333   BOOST_CHECK_EQUAL( s3->parentStop(), 1+1);
334   BOOST_CHECK_EQUAL( s3->sequence(), s3seq_string);
335   
336   // s2 should now be equivalent to s1->subseq(1,5)
337   s2->setParentStart(1);  
338   BOOST_CHECK_EQUAL( s2->start(), 1);
339   BOOST_CHECK_EQUAL( s2->stop(), 3+3);
340   BOOST_CHECK_EQUAL( s2->size(), 5);
341
342   // Child sequence should have the same global location  
343   BOOST_CHECK_EQUAL( s3->start(), 3+1 );
344   BOOST_CHECK_EQUAL( s3->stop(), 3+1+1);
345   BOOST_CHECK_EQUAL( s3->size(), 1);
346   // Child sequence should now have different parent location
347   BOOST_CHECK_EQUAL( s3->parentStart(),  1+2);
348   BOOST_CHECK_EQUAL( s3->parentStop(), 1+2+1);
349 }
350
351 // what happens if we set a stop past our actual end
352 BOOST_AUTO_TEST_CASE( seqspan_stop_past_end )
353 {
354   std::string seq_string("AAGGCCTT");
355   SeqSpanRef s1(new SeqSpan(seq_string));
356   std::string s2seq_string = seq_string.substr(3,3);
357   SeqSpanRef s2 = s1->subseq(3,3);
358   std::string s3seq_string = s2seq_string.substr(1,1);
359   SeqSpanRef s3 = s2->subseq(1,1);
360
361   // should be limited by our parent sequence
362   s3->setStop(8);
363   BOOST_CHECK_EQUAL( s3->size(), 2); 
364   
365   s2->setStop(8);
366   BOOST_CHECK_EQUAL( s2->size(), 5);
367   
368   s3->setStop(8);
369   BOOST_CHECK_EQUAL( s3->size(), 4);
370 }
371
372 BOOST_AUTO_TEST_CASE( seqspan_strand_sameother )
373 {
374   SeqSpanRef seq1(new SeqSpan("AAAAAGGGGG"));
375   BOOST_CHECK_EQUAL(seq1->strand(), SeqSpan::PlusStrand);
376   
377   SeqSpanRef seq2 = seq1->subseq(0,4,SeqSpan::SameStrand);
378   BOOST_CHECK_EQUAL(seq2->sequence(), "AAAA");
379   BOOST_CHECK_EQUAL(seq2->strand(), SeqSpan::PlusStrand);
380   SeqSpanRef seq3 = seq1->subseq(0,4,SeqSpan::OppositeStrand); 
381   BOOST_CHECK_EQUAL(seq3->sequence(), "TTTT");
382   BOOST_CHECK_EQUAL(seq3->strand(), SeqSpan::MinusStrand);
383
384   // opposite of a plus strand should be minus
385   SeqSpanRef seq4 = seq2->subseq(0,4,SeqSpan::OppositeStrand);
386   BOOST_CHECK_EQUAL(seq4->sequence(), "TTTT");
387   BOOST_CHECK_EQUAL(seq4->strand(), SeqSpan::MinusStrand);
388   // opposite of a minus strand should be plus
389   SeqSpanRef seq5 = seq3->subseq(0,4,SeqSpan::OppositeStrand); 
390   BOOST_CHECK_EQUAL(seq5->sequence(), "AAAA");
391   BOOST_CHECK_EQUAL(seq5->strand(), SeqSpan::PlusStrand);
392 }
393
394 BOOST_AUTO_TEST_CASE( seqspan_strand_plusminus )
395 {
396   SeqSpanRef seq1(new SeqSpan("AAAAAGGGGG"));
397   BOOST_CHECK_EQUAL(seq1->strand(), SeqSpan::PlusStrand);
398   
399   SeqSpanRef seq2 = seq1->subseq(0,4,SeqSpan::PlusStrand);
400   BOOST_CHECK_EQUAL(seq2->sequence(), "AAAA");
401   SeqSpanRef seq3 = seq1->subseq(0,4,SeqSpan::MinusStrand); 
402   BOOST_CHECK_EQUAL(seq3->sequence(), "TTTT");
403 }