Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
AlignmentTest | 56 | 592 | 93 |
1 | /* | |
2 | * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) | |
3 | * Copyright (C) $$Year-Rel$$ The Jalview Authors | |
4 | * | |
5 | * This file is part of Jalview. | |
6 | * | |
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. | |
11 | * | |
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. | |
16 | * | |
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. | |
20 | */ | |
21 | package jalview.datamodel; | |
22 | ||
23 | import static org.testng.AssertJUnit.assertEquals; | |
24 | import static org.testng.AssertJUnit.assertFalse; | |
25 | import static org.testng.AssertJUnit.assertNotNull; | |
26 | import static org.testng.AssertJUnit.assertNull; | |
27 | import static org.testng.AssertJUnit.assertSame; | |
28 | import static org.testng.AssertJUnit.assertTrue; | |
29 | ||
30 | import java.io.IOException; | |
31 | import java.util.Arrays; | |
32 | import java.util.Iterator; | |
33 | import java.util.List; | |
34 | ||
35 | import org.testng.Assert; | |
36 | import org.testng.annotations.BeforeClass; | |
37 | import org.testng.annotations.BeforeMethod; | |
38 | import org.testng.annotations.Test; | |
39 | ||
40 | import jalview.analysis.AlignmentGenerator; | |
41 | import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping; | |
42 | import jalview.gui.JvOptionPane; | |
43 | import jalview.io.DataSourceType; | |
44 | import jalview.io.FileFormat; | |
45 | import jalview.io.FileFormatI; | |
46 | import jalview.io.FormatAdapter; | |
47 | import jalview.util.Comparison; | |
48 | import jalview.util.MapList; | |
49 | ||
50 | /** | |
51 | * Unit tests for Alignment datamodel. | |
52 | * | |
53 | * @author gmcarstairs | |
54 | * | |
55 | */ | |
56 | public class AlignmentTest | |
57 | { | |
58 | ||
59 | 1 | @BeforeClass(alwaysRun = true) |
60 | public void setUpJvOptionPane() | |
61 | { | |
62 | 1 | JvOptionPane.setInteractiveMode(false); |
63 | 1 | JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); |
64 | } | |
65 | ||
66 | // @formatter:off | |
67 | private static final String TEST_DATA = | |
68 | "# STOCKHOLM 1.0\n" + | |
69 | "#=GS D.melanogaster.1 AC AY119185.1/838-902\n" + | |
70 | "#=GS D.melanogaster.2 AC AC092237.1/57223-57161\n" + | |
71 | "#=GS D.melanogaster.3 AC AY060611.1/560-627\n" + | |
72 | "D.melanogaster.1 G.AGCC.CU...AUGAUCGA\n" + | |
73 | "#=GR D.melanogaster.1 SS ................((((\n" + | |
74 | "D.melanogaster.2 C.AUUCAACU.UAUGAGGAU\n" + | |
75 | "#=GR D.melanogaster.2 SS ................((((\n" + | |
76 | "D.melanogaster.3 G.UGGCGCU..UAUGACGCA\n" + | |
77 | "#=GR D.melanogaster.3 SS (.(((...(....(((((((\n" + | |
78 | "//"; | |
79 | ||
80 | private static final String AA_SEQS_1 = | |
81 | ">Seq1Name/5-8\n" + | |
82 | "K-QY--L\n" + | |
83 | ">Seq2Name/12-15\n" + | |
84 | "-R-FP-W-\n"; | |
85 | ||
86 | private static final String CDNA_SEQS_1 = | |
87 | ">Seq1Name/100-111\n" + | |
88 | "AC-GG--CUC-CAA-CT\n" + | |
89 | ">Seq2Name/200-211\n" + | |
90 | "-CG-TTA--ACG---AAGT\n"; | |
91 | ||
92 | private static final String CDNA_SEQS_2 = | |
93 | ">Seq1Name/50-61\n" + | |
94 | "GCTCGUCGTACT\n" + | |
95 | ">Seq2Name/60-71\n" + | |
96 | "GGGTCAGGCAGT\n"; | |
97 | // @formatter:on | |
98 | ||
99 | private AlignmentI al; | |
100 | ||
101 | /** | |
102 | * Helper method to load an alignment and ensure dataset sequences are set up. | |
103 | * | |
104 | * @param data | |
105 | * @param format | |
106 | * TODO | |
107 | * @return | |
108 | * @throws IOException | |
109 | */ | |
110 | 44 | protected AlignmentI loadAlignment(final String data, FileFormatI format) |
111 | throws IOException | |
112 | { | |
113 | 44 | AlignmentI a = new FormatAdapter().readFile(data, DataSourceType.PASTE, |
114 | format); | |
115 | 44 | a.setDataset(null); |
116 | 44 | return a; |
117 | } | |
118 | ||
119 | /** | |
120 | * assert wrapper: tests all references in the given alignment are consistent | |
121 | * | |
122 | * @param alignment | |
123 | */ | |
124 | 0 | public static void assertAlignmentDatasetRefs(AlignmentI alignment) |
125 | { | |
126 | 0 | verifyAlignmentDatasetRefs(alignment, true, null); |
127 | } | |
128 | ||
129 | /** | |
130 | * assert wrapper: tests all references in the given alignment are consistent | |
131 | * | |
132 | * @param alignment | |
133 | * @param message | |
134 | * - prefixed to any assert failed messages | |
135 | */ | |
136 | 1 | public static void assertAlignmentDatasetRefs(AlignmentI alignment, |
137 | String message) | |
138 | { | |
139 | 1 | verifyAlignmentDatasetRefs(alignment, true, message); |
140 | } | |
141 | ||
142 | /** | |
143 | * verify sequence and dataset references are properly contained within | |
144 | * dataset | |
145 | * | |
146 | * @param alignment | |
147 | * - the alignmentI object to verify (either alignment or dataset) | |
148 | * @param raiseAssert | |
149 | * - when set, testng assertions are raised. | |
150 | * @param message | |
151 | * - null or a string message to prepend to the assert failed | |
152 | * messages. | |
153 | * @return true if alignment references were in order, otherwise false. | |
154 | */ | |
155 | 44 | public static boolean verifyAlignmentDatasetRefs(AlignmentI alignment, |
156 | boolean raiseAssert, String message) | |
157 | { | |
158 | 44 | if (message == null) |
159 | { | |
160 | 24 | message = ""; |
161 | } | |
162 | 44 | if (alignment == null) |
163 | { | |
164 | 0 | if (raiseAssert) |
165 | { | |
166 | 0 | Assert.fail(message + "Alignment for verification was null."); |
167 | } | |
168 | 0 | return false; |
169 | } | |
170 | 44 | if (alignment.getDataset() != null) |
171 | { | |
172 | 19 | AlignmentI dataset = alignment.getDataset(); |
173 | // check all alignment sequences have their dataset within the dataset | |
174 | 19 | for (SequenceI seq : alignment.getSequences()) |
175 | { | |
176 | 39 | SequenceI seqds = seq.getDatasetSequence(); |
177 | 39 | if (seqds.getDatasetSequence() != null) |
178 | { | |
179 | 0 | if (raiseAssert) |
180 | { | |
181 | 0 | Assert.fail(message |
182 | + " Alignment contained a sequence who's dataset sequence has a second dataset reference."); | |
183 | } | |
184 | 0 | return false; |
185 | } | |
186 | 39 | if (dataset.findIndex(seqds) == -1) |
187 | { | |
188 | 0 | if (raiseAssert) |
189 | { | |
190 | 0 | Assert.fail(message |
191 | + " Alignment contained a sequence who's dataset sequence was not in the dataset."); | |
192 | } | |
193 | 0 | return false; |
194 | } | |
195 | } | |
196 | 19 | return verifyAlignmentDatasetRefs(alignment.getDataset(), raiseAssert, |
197 | message); | |
198 | } | |
199 | else | |
200 | { | |
201 | 25 | int dsp = -1; |
202 | // verify all dataset sequences | |
203 | 25 | for (SequenceI seqds : alignment.getSequences()) |
204 | { | |
205 | 80 | dsp++; |
206 | 80 | if (seqds.getDatasetSequence() != null) |
207 | { | |
208 | 2 | if (raiseAssert) |
209 | { | |
210 | 1 | Assert.fail(message |
211 | + " Dataset contained a sequence with non-null dataset reference (ie not a dataset sequence!)"); | |
212 | } | |
213 | 1 | return false; |
214 | } | |
215 | 78 | int foundp = alignment.findIndex(seqds); |
216 | 78 | if (foundp != dsp) |
217 | { | |
218 | 2 | if (raiseAssert) |
219 | { | |
220 | 1 | Assert.fail(message |
221 | + " Dataset sequence array contains a reference at " | |
222 | + dsp + " to a sequence first seen at " + foundp + " (" | |
223 | + seqds.toString() + ")"); | |
224 | } | |
225 | 1 | return false; |
226 | } | |
227 | 76 | if (seqds.getDBRefs() != null) |
228 | { | |
229 | 28 | for (DBRefEntry dbr : seqds.getDBRefs()) |
230 | { | |
231 | 28 | if (dbr.getMap() != null) |
232 | { | |
233 | 28 | SequenceI seqdbrmapto = dbr.getMap().getTo(); |
234 | 28 | if (seqdbrmapto != null) |
235 | { | |
236 | 28 | if (seqdbrmapto.getDatasetSequence() != null) |
237 | { | |
238 | 0 | if (raiseAssert) |
239 | { | |
240 | 0 | Assert.fail(message |
241 | + " DBRefEntry for sequence in alignment had map to sequence which was not a dataset sequence"); | |
242 | } | |
243 | 0 | return false; |
244 | ||
245 | } | |
246 | 28 | if (alignment.findIndex(dbr.getMap().getTo()) == -1) |
247 | { | |
248 | 2 | if (raiseAssert) |
249 | { | |
250 | 1 | Assert.fail(message + " DBRefEntry " + dbr |
251 | + " for sequence " + seqds | |
252 | + " in alignment has map to sequence not in dataset"); | |
253 | } | |
254 | 1 | return false; |
255 | } | |
256 | } | |
257 | } | |
258 | } | |
259 | } | |
260 | } | |
261 | // finally, verify codonmappings involve only dataset sequences. | |
262 | 19 | if (alignment.getCodonFrames() != null) |
263 | { | |
264 | 19 | for (AlignedCodonFrame alc : alignment.getCodonFrames()) |
265 | { | |
266 | 6 | for (SequenceToSequenceMapping ssm : alc.getMappings()) |
267 | { | |
268 | 6 | if (ssm.getFromSeq().getDatasetSequence() != null) |
269 | { | |
270 | 0 | if (raiseAssert) |
271 | { | |
272 | 0 | Assert.fail(message |
273 | + " CodonFrame-SSM-FromSeq is not a dataset sequence"); | |
274 | } | |
275 | 0 | return false; |
276 | } | |
277 | 6 | if (alignment.findIndex(ssm.getFromSeq()) == -1) |
278 | { | |
279 | ||
280 | 2 | if (raiseAssert) |
281 | { | |
282 | 1 | Assert.fail(message |
283 | + " CodonFrame-SSM-FromSeq is not contained in dataset"); | |
284 | } | |
285 | 1 | return false; |
286 | } | |
287 | 4 | if (ssm.getMapping().getTo().getDatasetSequence() != null) |
288 | { | |
289 | 0 | if (raiseAssert) |
290 | { | |
291 | 0 | Assert.fail(message |
292 | + " CodonFrame-SSM-Mapping-ToSeq is not a dataset sequence"); | |
293 | } | |
294 | 0 | return false; |
295 | } | |
296 | 4 | if (alignment.findIndex(ssm.getMapping().getTo()) == -1) |
297 | { | |
298 | ||
299 | 0 | if (raiseAssert) |
300 | { | |
301 | 0 | Assert.fail(message |
302 | + " CodonFrame-SSM-Mapping-ToSeq is not contained in dataset"); | |
303 | } | |
304 | 0 | return false; |
305 | } | |
306 | } | |
307 | } | |
308 | } | |
309 | } | |
310 | 17 | return true; // all relationships verified! |
311 | } | |
312 | ||
313 | /** | |
314 | * call verifyAlignmentDatasetRefs with and without assertion raising enabled, | |
315 | * to check expected pass/fail actually occurs in both conditions | |
316 | * | |
317 | * @param al | |
318 | * @param expected | |
319 | * @param msg | |
320 | */ | |
321 | 12 | private void assertVerifyAlignment(AlignmentI al, boolean expected, |
322 | String msg) | |
323 | { | |
324 | 12 | if (expected) |
325 | { | |
326 | 8 | try |
327 | { | |
328 | ||
329 | 8 | Assert.assertTrue(verifyAlignmentDatasetRefs(al, true, null), |
330 | "Valid test alignment failed when raiseAsserts enabled:" | |
331 | + msg); | |
332 | } catch (AssertionError ae) | |
333 | { | |
334 | 0 | ae.printStackTrace(); |
335 | 0 | Assert.fail( |
336 | "Valid test alignment raised assertion errors when raiseAsserts enabled: " | |
337 | + msg, | |
338 | ae); | |
339 | } | |
340 | // also check validation passes with asserts disabled | |
341 | 8 | Assert.assertTrue(verifyAlignmentDatasetRefs(al, false, null), |
342 | "Valid test alignment tested false when raiseAsserts disabled:" | |
343 | + msg); | |
344 | } | |
345 | else | |
346 | { | |
347 | 4 | boolean assertRaised = false; |
348 | 4 | try |
349 | { | |
350 | 4 | verifyAlignmentDatasetRefs(al, true, null); |
351 | } catch (AssertionError ae) | |
352 | { | |
353 | // expected behaviour | |
354 | 4 | assertRaised = true; |
355 | } | |
356 | 4 | if (!assertRaised) |
357 | { | |
358 | 0 | Assert.fail( |
359 | "Invalid test alignment passed when raiseAsserts enabled:" | |
360 | + msg); | |
361 | } | |
362 | // also check validation passes with asserts disabled | |
363 | 4 | Assert.assertFalse(verifyAlignmentDatasetRefs(al, false, null), |
364 | "Invalid test alignment tested true when raiseAsserts disabled:" | |
365 | + msg); | |
366 | } | |
367 | } | |
368 | ||
369 | 1 | @Test(groups = { "Functional" }) |
370 | public void testVerifyAlignmentDatasetRefs() | |
371 | { | |
372 | 1 | SequenceI sq1 = new Sequence("sq1", "ASFDD"), |
373 | sq2 = new Sequence("sq2", "TTTTTT"); | |
374 | ||
375 | // construct simple valid alignment dataset | |
376 | 1 | Alignment al = new Alignment(new SequenceI[] { sq1, sq2 }); |
377 | // expect this to pass | |
378 | 1 | assertVerifyAlignment(al, true, "Simple valid alignment didn't verify"); |
379 | ||
380 | // check test for sequence->datasetSequence validity | |
381 | 1 | sq1.setDatasetSequence(sq2); |
382 | 1 | assertVerifyAlignment(al, false, |
383 | "didn't detect dataset sequence with a dataset sequence reference."); | |
384 | ||
385 | 1 | sq1.setDatasetSequence(null); |
386 | 1 | assertVerifyAlignment(al, true, |
387 | "didn't reinstate validity after nulling dataset sequence dataset reference"); | |
388 | ||
389 | // now create dataset and check again | |
390 | 1 | al.createDatasetAlignment(); |
391 | 1 | assertNotNull(al.getDataset()); |
392 | ||
393 | 1 | assertVerifyAlignment(al, true, |
394 | "verify failed after createDatasetAlignment"); | |
395 | ||
396 | // create a dbref on sq1 with a sequence ref to sq2 | |
397 | 1 | DBRefEntry dbrs1tos2 = new DBRefEntry("UNIPROT", "1", "Q111111"); |
398 | 1 | dbrs1tos2 |
399 | .setMap(new Mapping(sq2.getDatasetSequence(), new int[] | |
400 | { 1, 5 }, new int[] { 2, 6 }, 1, 1)); | |
401 | 1 | sq1.getDatasetSequence().addDBRef(dbrs1tos2); |
402 | 1 | assertVerifyAlignment(al, true, |
403 | "verify failed after addition of valid DBRefEntry/map"); | |
404 | // now create a dbref on a new sequence which maps to another sequence | |
405 | // outside of the dataset | |
406 | 1 | SequenceI sqout = new Sequence("sqout", "ututututucagcagcag"), |
407 | sqnew = new Sequence("sqnew", "EEERRR"); | |
408 | 1 | DBRefEntry sqnewsqout = new DBRefEntry("ENAFOO", "1", "R000001"); |
409 | 1 | sqnewsqout |
410 | .setMap(new Mapping(sqout, new int[] | |
411 | { 1, 6 }, new int[] { 1, 18 }, 1, 3)); | |
412 | 1 | al.getDataset().addSequence(sqnew); |
413 | ||
414 | 1 | assertVerifyAlignment(al, true, |
415 | "verify failed after addition of new sequence to dataset"); | |
416 | // now start checking exception conditions | |
417 | 1 | sqnew.addDBRef(sqnewsqout); |
418 | 1 | assertVerifyAlignment(al, false, |
419 | "verify passed when a dbref with map to sequence outside of dataset was added"); | |
420 | // make the verify pass by adding the outsider back in | |
421 | 1 | al.getDataset().addSequence(sqout); |
422 | 1 | assertVerifyAlignment(al, true, |
423 | "verify should have passed after adding dbref->to sequence in to dataset"); | |
424 | // and now the same for a codon mapping... | |
425 | 1 | SequenceI sqanotherout = new Sequence("sqanotherout", |
426 | "aggtutaggcagcagcag"); | |
427 | ||
428 | 1 | AlignedCodonFrame alc = new AlignedCodonFrame(); |
429 | 1 | alc.addMap(sqanotherout, sqnew, |
430 | new MapList(new int[] | |
431 | { 1, 6 }, new int[] { 1, 18 }, 3, 1)); | |
432 | ||
433 | 1 | al.addCodonFrame(alc); |
434 | 1 | Assert.assertEquals(al.getDataset().getCodonFrames().size(), 1); |
435 | ||
436 | 1 | assertVerifyAlignment(al, false, |
437 | "verify passed when alCodonFrame mapping to sequence outside of dataset was added"); | |
438 | // make the verify pass by adding the outsider back in | |
439 | 1 | al.getDataset().addSequence(sqanotherout); |
440 | 1 | assertVerifyAlignment(al, true, |
441 | "verify should have passed once all sequences involved in alCodonFrame were added to dataset"); | |
442 | 1 | al.getDataset().addSequence(sqanotherout); |
443 | 1 | assertVerifyAlignment(al, false, |
444 | "verify should have failed when a sequence was added twice to the dataset"); | |
445 | 1 | al.getDataset().deleteSequence(sqanotherout); |
446 | 1 | assertVerifyAlignment(al, true, |
447 | "verify should have passed after duplicate entry for sequence was removed"); | |
448 | } | |
449 | ||
450 | /** | |
451 | * checks that the sequence data for an alignment's dataset is non-redundant. | |
452 | * Fails if there are sequences with same id, sequence, start, and. | |
453 | */ | |
454 | ||
455 | 6 | public static void assertDatasetIsNormalised(AlignmentI al) |
456 | { | |
457 | 6 | assertDatasetIsNormalised(al, null); |
458 | } | |
459 | ||
460 | /** | |
461 | * checks that the sequence data for an alignment's dataset is non-redundant. | |
462 | * Fails if there are sequences with same id, sequence, start, and. | |
463 | * | |
464 | * @param al | |
465 | * - alignment to verify | |
466 | * @param message | |
467 | * - null or message prepended to exception message. | |
468 | */ | |
469 | 12 | public static void assertDatasetIsNormalised(AlignmentI al, |
470 | String message) | |
471 | { | |
472 | 12 | if (al.getDataset() != null) |
473 | { | |
474 | 6 | assertDatasetIsNormalised(al.getDataset(), message); |
475 | 5 | return; |
476 | } | |
477 | /* | |
478 | * look for pairs of sequences with same ID, start, end, and sequence | |
479 | */ | |
480 | 6 | List<SequenceI> seqSet = al.getSequences(); |
481 | 18 | for (int p = 0; p < seqSet.size(); p++) |
482 | { | |
483 | 13 | SequenceI pSeq = seqSet.get(p); |
484 | 27 | for (int q = p + 1; q < seqSet.size(); q++) |
485 | { | |
486 | 15 | SequenceI qSeq = seqSet.get(q); |
487 | 15 | if (pSeq.getStart() != qSeq.getStart()) |
488 | { | |
489 | 4 | continue; |
490 | } | |
491 | 11 | if (pSeq.getEnd() != qSeq.getEnd()) |
492 | { | |
493 | 0 | continue; |
494 | } | |
495 | 11 | if (!pSeq.getName().equals(qSeq.getName())) |
496 | { | |
497 | 7 | continue; |
498 | } | |
499 | 4 | if (!Arrays.equals(pSeq.getSequence(), qSeq.getSequence())) |
500 | { | |
501 | 3 | continue; |
502 | } | |
503 | 1 | Assert.fail((message == null ? "" : message + " :") |
504 | + "Found similar sequences at position " + p + " and " + q | |
505 | + "\n" + pSeq.toString()); | |
506 | } | |
507 | } | |
508 | } | |
509 | ||
510 | 1 | @Test(groups = { "Functional", "Asserts" }) |
511 | public void testAssertDatasetIsNormalised() | |
512 | { | |
513 | 1 | Sequence sq1 = new Sequence("s1/1-4", "asdf"); |
514 | 1 | Sequence sq1shift = new Sequence("s1/2-5", "asdf"); |
515 | 1 | Sequence sq1seqd = new Sequence("s1/1-4", "asdt"); |
516 | 1 | Sequence sq2 = new Sequence("s2/1-4", "asdf"); |
517 | 1 | Sequence sq1dup = new Sequence("s1/1-4", "asdf"); |
518 | ||
519 | 1 | Alignment al = new Alignment(new SequenceI[] { sq1 }); |
520 | 1 | al.setDataset(null); |
521 | ||
522 | 1 | try |
523 | { | |
524 | 1 | assertDatasetIsNormalised(al); |
525 | } catch (AssertionError ae) | |
526 | { | |
527 | 0 | Assert.fail("Single sequence should be valid normalised dataset."); |
528 | } | |
529 | 1 | al.addSequence(sq2); |
530 | 1 | try |
531 | { | |
532 | 1 | assertDatasetIsNormalised(al); |
533 | } catch (AssertionError ae) | |
534 | { | |
535 | 0 | Assert.fail( |
536 | "Two different sequences should be valid normalised dataset."); | |
537 | } | |
538 | /* | |
539 | * now change sq2's name in the alignment. should still be valid | |
540 | */ | |
541 | 1 | al.findName(sq2.getName()).setName("sq1"); |
542 | 1 | try |
543 | { | |
544 | 1 | assertDatasetIsNormalised(al); |
545 | } catch (AssertionError ae) | |
546 | { | |
547 | 0 | Assert.fail( |
548 | "Two different sequences in dataset, but same name in alignment, should be valid normalised dataset."); | |
549 | } | |
550 | ||
551 | 1 | al.addSequence(sq1seqd); |
552 | 1 | try |
553 | { | |
554 | 1 | assertDatasetIsNormalised(al); |
555 | } catch (AssertionError ae) | |
556 | { | |
557 | 0 | Assert.fail( |
558 | "sq1 and sq1 with different sequence should be distinct."); | |
559 | } | |
560 | ||
561 | 1 | al.addSequence(sq1shift); |
562 | 1 | try |
563 | { | |
564 | 1 | assertDatasetIsNormalised(al); |
565 | } catch (AssertionError ae) | |
566 | { | |
567 | 0 | Assert.fail( |
568 | "sq1 and sq1 with different start/end should be distinct."); | |
569 | } | |
570 | /* | |
571 | * finally, the failure case | |
572 | */ | |
573 | 1 | al.addSequence(sq1dup); |
574 | 1 | boolean ssertRaised = false; |
575 | 1 | try |
576 | { | |
577 | 1 | assertDatasetIsNormalised(al); |
578 | ||
579 | } catch (AssertionError ae) | |
580 | { | |
581 | 1 | ssertRaised = true; |
582 | } | |
583 | 1 | if (!ssertRaised) |
584 | { | |
585 | 0 | Assert.fail("Expected identical sequence to raise exception."); |
586 | } | |
587 | } | |
588 | ||
589 | /* | |
590 | * Read in Stockholm format test data including secondary structure | |
591 | * annotations. | |
592 | */ | |
593 | 31 | @BeforeMethod(alwaysRun = true) |
594 | public void setUp() throws IOException | |
595 | { | |
596 | 31 | al = loadAlignment(TEST_DATA, FileFormat.Stockholm); |
597 | 31 | int i = 0; |
598 | 31 | for (AlignmentAnnotation ann : al.getAlignmentAnnotation()) |
599 | { | |
600 | 93 | ann.setCalcId("CalcIdFor" + al.getSequenceAt(i).getName()); |
601 | 93 | i++; |
602 | } | |
603 | } | |
604 | ||
605 | /** | |
606 | * Test method that returns annotations that match on calcId. | |
607 | */ | |
608 | 1 | @Test(groups = { "Functional" }) |
609 | public void testFindAnnotation_byCalcId() | |
610 | { | |
611 | 1 | Iterable<AlignmentAnnotation> anns = al |
612 | .findAnnotation("CalcIdForD.melanogaster.2"); | |
613 | 1 | Iterator<AlignmentAnnotation> iter = anns.iterator(); |
614 | 1 | assertTrue(iter.hasNext()); |
615 | 1 | AlignmentAnnotation ann = iter.next(); |
616 | 1 | assertEquals("D.melanogaster.2", ann.sequenceRef.getName()); |
617 | 1 | assertFalse(iter.hasNext()); |
618 | ||
619 | // invalid id | |
620 | 1 | anns = al.findAnnotation("CalcIdForD.melanogaster.?"); |
621 | 1 | assertFalse(iter.hasNext()); |
622 | 1 | anns = al.findAnnotation(null); |
623 | 1 | assertFalse(iter.hasNext()); |
624 | } | |
625 | ||
626 | /** | |
627 | * Test method that returns annotations that match on reference sequence, | |
628 | * label, or calcId. | |
629 | */ | |
630 | 1 | @Test(groups = { "Functional" }) |
631 | public void testFindAnnotations_bySeqLabelandorCalcId() | |
632 | { | |
633 | // TODO: finish testFindAnnotations_bySeqLabelandorCalcId test | |
634 | /* Note - this is an incomplete test - need to check null or | |
635 | * non-null [ matches, not matches ] behaviour for each of the three | |
636 | * parameters..*/ | |
637 | ||
638 | // search for a single, unique calcId with wildcards on other params | |
639 | 1 | Iterable<AlignmentAnnotation> anns = al.findAnnotations(null, |
640 | "CalcIdForD.melanogaster.2", null); | |
641 | 1 | Iterator<AlignmentAnnotation> iter = anns.iterator(); |
642 | 1 | assertTrue(iter.hasNext()); |
643 | 1 | AlignmentAnnotation ann = iter.next(); |
644 | 1 | assertEquals("D.melanogaster.2", ann.sequenceRef.getName()); |
645 | 1 | assertFalse(iter.hasNext()); |
646 | ||
647 | // save reference to test sequence reference parameter | |
648 | 1 | SequenceI rseq = ann.sequenceRef; |
649 | ||
650 | // search for annotation associated with a single sequence | |
651 | 1 | anns = al.findAnnotations(rseq, null, null); |
652 | 1 | iter = anns.iterator(); |
653 | 1 | assertTrue(iter.hasNext()); |
654 | 1 | ann = iter.next(); |
655 | 1 | assertEquals("D.melanogaster.2", ann.sequenceRef.getName()); |
656 | 1 | assertFalse(iter.hasNext()); |
657 | ||
658 | // search for annotation with a non-existant calcId | |
659 | 1 | anns = al.findAnnotations(null, "CalcIdForD.melanogaster.?", null); |
660 | 1 | iter = anns.iterator(); |
661 | 1 | assertFalse(iter.hasNext()); |
662 | ||
663 | // search for annotation with a particular label - expect three | |
664 | 1 | anns = al.findAnnotations(null, null, "Secondary Structure"); |
665 | 1 | iter = anns.iterator(); |
666 | 1 | assertTrue(iter.hasNext()); |
667 | 1 | iter.next(); |
668 | 1 | assertTrue(iter.hasNext()); |
669 | 1 | iter.next(); |
670 | 1 | assertTrue(iter.hasNext()); |
671 | 1 | iter.next(); |
672 | // third found.. so | |
673 | 1 | assertFalse(iter.hasNext()); |
674 | ||
675 | // search for annotation on one sequence with a particular label - expect | |
676 | // one | |
677 | 1 | SequenceI sqfound; |
678 | 1 | anns = al.findAnnotations(sqfound = al.getSequenceAt(1), null, |
679 | "Secondary Structure"); | |
680 | 1 | iter = anns.iterator(); |
681 | 1 | assertTrue(iter.hasNext()); |
682 | // expect reference to sequence 1 in the alignment | |
683 | 1 | assertTrue(sqfound == iter.next().sequenceRef); |
684 | 1 | assertFalse(iter.hasNext()); |
685 | ||
686 | // null on all parameters == find all annotations | |
687 | 1 | anns = al.findAnnotations(null, null, null); |
688 | 1 | iter = anns.iterator(); |
689 | 1 | int n = al.getAlignmentAnnotation().length; |
690 | 4 | while (iter.hasNext()) |
691 | { | |
692 | 3 | n--; |
693 | 3 | iter.next(); |
694 | } | |
695 | 1 | assertTrue("Found " + n + " fewer annotations from search.", n == 0); |
696 | } | |
697 | ||
698 | 1 | @Test(groups = { "Functional" }) |
699 | public void testDeleteAllAnnotations_includingAutocalculated() | |
700 | { | |
701 | 1 | AlignmentAnnotation aa = new AlignmentAnnotation("Consensus", |
702 | "Consensus", 0.5); | |
703 | 1 | aa.autoCalculated = true; |
704 | 1 | al.addAnnotation(aa); |
705 | 1 | AlignmentAnnotation[] anns = al.getAlignmentAnnotation(); |
706 | 1 | assertEquals("Wrong number of annotations before deleting", 4, |
707 | anns.length); | |
708 | 1 | al.deleteAllAnnotations(true); |
709 | 1 | assertEquals("Not all deleted", 0, al.getAlignmentAnnotation().length); |
710 | } | |
711 | ||
712 | 1 | @Test(groups = { "Functional" }) |
713 | public void testDeleteAllAnnotations_excludingAutocalculated() | |
714 | { | |
715 | 1 | AlignmentAnnotation aa = new AlignmentAnnotation("Consensus", |
716 | "Consensus", 0.5); | |
717 | 1 | aa.autoCalculated = true; |
718 | 1 | al.addAnnotation(aa); |
719 | 1 | AlignmentAnnotation[] anns = al.getAlignmentAnnotation(); |
720 | 1 | assertEquals("Wrong number of annotations before deleting", 4, |
721 | anns.length); | |
722 | 1 | al.deleteAllAnnotations(false); |
723 | 1 | assertEquals("Not just one annotation left", 1, |
724 | al.getAlignmentAnnotation().length); | |
725 | } | |
726 | ||
727 | /** | |
728 | * Tests for realigning as per a supplied alignment: Dna as Dna. | |
729 | * | |
730 | * Note: AlignedCodonFrame's state variables are named for protein-to-cDNA | |
731 | * mapping, but can be exploited for a general 'sequence-to-sequence' mapping | |
732 | * as here. | |
733 | * | |
734 | * @throws IOException | |
735 | */ | |
736 | 1 | @Test(groups = { "Functional" }) |
737 | public void testAlignAs_dnaAsDna() throws IOException | |
738 | { | |
739 | // aligned cDNA: | |
740 | 1 | AlignmentI al1 = loadAlignment(CDNA_SEQS_1, FileFormat.Fasta); |
741 | // unaligned cDNA: | |
742 | 1 | AlignmentI al2 = loadAlignment(CDNA_SEQS_2, FileFormat.Fasta); |
743 | ||
744 | /* | |
745 | * Make mappings between sequences. The 'aligned cDNA' is playing the role | |
746 | * of what would normally be protein here. | |
747 | */ | |
748 | 1 | makeMappings(al1, al2); |
749 | ||
750 | 1 | ((Alignment) al2).alignAs(al1, false, true); |
751 | 1 | assertEquals("GC-TC--GUC-GTACT", |
752 | al2.getSequenceAt(0).getSequenceAsString()); | |
753 | 1 | assertEquals("-GG-GTC--AGG--CAGT", |
754 | al2.getSequenceAt(1).getSequenceAsString()); | |
755 | } | |
756 | ||
757 | /** | |
758 | * Aligning protein from cDNA. | |
759 | * | |
760 | * @throws IOException | |
761 | */ | |
762 | 1 | @Test(groups = { "Functional" }) |
763 | public void testAlignAs_proteinAsCdna() throws IOException | |
764 | { | |
765 | // see also AlignmentUtilsTests | |
766 | 1 | AlignmentI al1 = loadAlignment(CDNA_SEQS_1, FileFormat.Fasta); |
767 | 1 | AlignmentI al2 = loadAlignment(AA_SEQS_1, FileFormat.Fasta); |
768 | 1 | makeMappings(al1, al2); |
769 | ||
770 | // Fudge - alignProteinAsCdna expects mappings to be on protein | |
771 | 1 | al2.getCodonFrames().addAll(al1.getCodonFrames()); |
772 | ||
773 | 1 | ((Alignment) al2).alignAs(al1, false, true); |
774 | 1 | assertEquals("K-Q-Y-L-", al2.getSequenceAt(0).getSequenceAsString()); |
775 | 1 | assertEquals("-R-F-P-W", al2.getSequenceAt(1).getSequenceAsString()); |
776 | } | |
777 | ||
778 | /** | |
779 | * Test aligning cdna as per protein alignment. | |
780 | * | |
781 | * @throws IOException | |
782 | */ | |
783 | 1 | @Test(groups = { "Functional" }, enabled = true) |
784 | // TODO review / update this test after redesign of alignAs method | |
785 | public void testAlignAs_cdnaAsProtein() throws IOException | |
786 | { | |
787 | /* | |
788 | * Load alignments and add mappings for cDNA to protein | |
789 | */ | |
790 | 1 | AlignmentI al1 = loadAlignment(CDNA_SEQS_1, FileFormat.Fasta); |
791 | 1 | AlignmentI al2 = loadAlignment(AA_SEQS_1, FileFormat.Fasta); |
792 | 1 | makeMappings(al1, al2); |
793 | ||
794 | /* | |
795 | * Realign DNA; currently keeping existing gaps in introns only | |
796 | */ | |
797 | 1 | ((Alignment) al1).alignAs(al2, false, true); |
798 | 1 | assertEquals("ACG---GCUCCA------ACT---", |
799 | al1.getSequenceAt(0).getSequenceAsString()); | |
800 | 1 | assertEquals("---CGT---TAACGA---AGT---", |
801 | al1.getSequenceAt(1).getSequenceAsString()); | |
802 | } | |
803 | ||
804 | /** | |
805 | * Test aligning cdna as per protein - single sequences | |
806 | * | |
807 | * @throws IOException | |
808 | */ | |
809 | 1 | @Test(groups = { "Functional" }, enabled = true) |
810 | // TODO review / update this test after redesign of alignAs method | |
811 | public void testAlignAs_cdnaAsProtein_singleSequence() throws IOException | |
812 | { | |
813 | /* | |
814 | * simple case insert one gap | |
815 | */ | |
816 | 1 | verifyAlignAs(">dna\nCAAaaa\n", ">protein\nQ-K\n", "CAA---aaa"); |
817 | ||
818 | /* | |
819 | * simple case but with sequence offsets | |
820 | */ | |
821 | 1 | verifyAlignAs(">dna/5-10\nCAAaaa\n", ">protein/20-21\nQ-K\n", |
822 | "CAA---aaa"); | |
823 | ||
824 | /* | |
825 | * insert gaps as per protein, drop gaps within codons | |
826 | */ | |
827 | 1 | verifyAlignAs(">dna/10-18\nCA-Aa-aa--AGA\n", ">aa/6-8\n-Q-K--R\n", |
828 | "---CAA---aaa------AGA"); | |
829 | } | |
830 | ||
831 | /** | |
832 | * Helper method that makes mappings and then aligns the first alignment as | |
833 | * the second | |
834 | * | |
835 | * @param fromSeqs | |
836 | * @param toSeqs | |
837 | * @param expected | |
838 | * @throws IOException | |
839 | */ | |
840 | 3 | public void verifyAlignAs(String fromSeqs, String toSeqs, String expected) |
841 | throws IOException | |
842 | { | |
843 | /* | |
844 | * Load alignments and add mappings from nucleotide to protein (or from | |
845 | * first to second if both the same type) | |
846 | */ | |
847 | 3 | AlignmentI al1 = loadAlignment(fromSeqs, FileFormat.Fasta); |
848 | 3 | AlignmentI al2 = loadAlignment(toSeqs, FileFormat.Fasta); |
849 | 3 | makeMappings(al1, al2); |
850 | ||
851 | /* | |
852 | * Realign DNA; currently keeping existing gaps in introns only | |
853 | */ | |
854 | 3 | ((Alignment) al1).alignAs(al2, false, true); |
855 | 3 | assertEquals(expected, al1.getSequenceAt(0).getSequenceAsString()); |
856 | } | |
857 | ||
858 | /** | |
859 | * Helper method to make mappings between sequences, and add the mappings to | |
860 | * the 'mapped from' alignment | |
861 | * | |
862 | * @param alFrom | |
863 | * @param alTo | |
864 | */ | |
865 | 6 | public void makeMappings(AlignmentI alFrom, AlignmentI alTo) |
866 | { | |
867 | 6 | int ratio = (alFrom.isNucleotide() == alTo.isNucleotide() ? 1 : 3); |
868 | ||
869 | 6 | AlignedCodonFrame acf = new AlignedCodonFrame(); |
870 | ||
871 | 15 | for (int i = 0; i < alFrom.getHeight(); i++) |
872 | { | |
873 | 9 | SequenceI seqFrom = alFrom.getSequenceAt(i); |
874 | 9 | SequenceI seqTo = alTo.getSequenceAt(i); |
875 | 9 | MapList ml = new MapList( |
876 | new int[] | |
877 | { seqFrom.getStart(), seqFrom.getEnd() }, | |
878 | new int[] | |
879 | { seqTo.getStart(), seqTo.getEnd() }, ratio, 1); | |
880 | 9 | acf.addMap(seqFrom, seqTo, ml); |
881 | } | |
882 | ||
883 | /* | |
884 | * not sure whether mappings 'belong' or protein or nucleotide | |
885 | * alignment, so adding to both ;~) | |
886 | */ | |
887 | 6 | alFrom.addCodonFrame(acf); |
888 | 6 | alTo.addCodonFrame(acf); |
889 | } | |
890 | ||
891 | /** | |
892 | * Test aligning dna as per protein alignment, for the case where there are | |
893 | * introns (i.e. some dna sites have no mapping from a peptide). | |
894 | * | |
895 | * @throws IOException | |
896 | */ | |
897 | 0 | @Test(groups = { "Functional" }, enabled = false) |
898 | // TODO review / update this test after redesign of alignAs method | |
899 | public void testAlignAs_dnaAsProtein_withIntrons() throws IOException | |
900 | { | |
901 | /* | |
902 | * Load alignments and add mappings for cDNA to protein | |
903 | */ | |
904 | 0 | String dna1 = "A-Aa-gG-GCC-cT-TT"; |
905 | 0 | String dna2 = "c--CCGgg-TT--T-AA-A"; |
906 | 0 | AlignmentI al1 = loadAlignment( |
907 | ">Dna1/6-17\n" + dna1 + "\n>Dna2/20-31\n" + dna2 + "\n", | |
908 | FileFormat.Fasta); | |
909 | 0 | AlignmentI al2 = loadAlignment( |
910 | ">Pep1/7-9\n-P--YK\n>Pep2/11-13\nG-T--F\n", FileFormat.Fasta); | |
911 | 0 | AlignedCodonFrame acf = new AlignedCodonFrame(); |
912 | // Seq1 has intron at dna positions 3,4,9 so splice is AAG GCC TTT | |
913 | // Seq2 has intron at dna positions 1,5,6 so splice is CCG TTT AAA | |
914 | 0 | MapList ml1 = new MapList(new int[] { 6, 7, 10, 13, 15, 17 }, |
915 | new int[] | |
916 | { 7, 9 }, 3, 1); | |
917 | 0 | acf.addMap(al1.getSequenceAt(0), al2.getSequenceAt(0), ml1); |
918 | 0 | MapList ml2 = new MapList(new int[] { 21, 23, 26, 31 }, |
919 | new int[] | |
920 | { 11, 13 }, 3, 1); | |
921 | 0 | acf.addMap(al1.getSequenceAt(1), al2.getSequenceAt(1), ml2); |
922 | 0 | al2.addCodonFrame(acf); |
923 | ||
924 | /* | |
925 | * Align ignoring gaps in dna introns and exons | |
926 | */ | |
927 | 0 | ((Alignment) al1).alignAs(al2, false, false); |
928 | 0 | assertEquals("---AAagG------GCCcTTT", |
929 | al1.getSequenceAt(0).getSequenceAsString()); | |
930 | // note 1 gap in protein corresponds to 'gg-' in DNA (3 positions) | |
931 | 0 | assertEquals("cCCGgg-TTT------AAA", |
932 | al1.getSequenceAt(1).getSequenceAsString()); | |
933 | ||
934 | /* | |
935 | * Reset and realign, preserving gaps in dna introns and exons | |
936 | */ | |
937 | 0 | al1.getSequenceAt(0).setSequence(dna1); |
938 | 0 | al1.getSequenceAt(1).setSequence(dna2); |
939 | 0 | ((Alignment) al1).alignAs(al2, true, true); |
940 | // String dna1 = "A-Aa-gG-GCC-cT-TT"; | |
941 | // String dna2 = "c--CCGgg-TT--T-AA-A"; | |
942 | // assumption: we include 'the greater of' protein/dna gap lengths, not both | |
943 | 0 | assertEquals("---A-Aa-gG------GCC-cT-TT", |
944 | al1.getSequenceAt(0).getSequenceAsString()); | |
945 | 0 | assertEquals("c--CCGgg-TT--T------AA-A", |
946 | al1.getSequenceAt(1).getSequenceAsString()); | |
947 | } | |
948 | ||
949 | 1 | @Test(groups = "Functional") |
950 | public void testCopyConstructor() throws IOException | |
951 | { | |
952 | 1 | AlignmentI protein = loadAlignment(AA_SEQS_1, FileFormat.Fasta); |
953 | // create sequence and alignment datasets | |
954 | 1 | protein.setDataset(null); |
955 | 1 | AlignedCodonFrame acf = new AlignedCodonFrame(); |
956 | 1 | List<AlignedCodonFrame> acfList = Arrays |
957 | .asList(new AlignedCodonFrame[] | |
958 | { acf }); | |
959 | 1 | protein.getDataset().setCodonFrames(acfList); |
960 | 1 | AlignmentI copy = new Alignment(protein); |
961 | ||
962 | /* | |
963 | * copy has different aligned sequences but the same dataset sequences | |
964 | */ | |
965 | 1 | assertFalse(copy.getSequenceAt(0) == protein.getSequenceAt(0)); |
966 | 1 | assertFalse(copy.getSequenceAt(1) == protein.getSequenceAt(1)); |
967 | 1 | assertSame(copy.getSequenceAt(0).getDatasetSequence(), |
968 | protein.getSequenceAt(0).getDatasetSequence()); | |
969 | 1 | assertSame(copy.getSequenceAt(1).getDatasetSequence(), |
970 | protein.getSequenceAt(1).getDatasetSequence()); | |
971 | ||
972 | // TODO should the copy constructor copy the dataset? | |
973 | // or make a new one referring to the same dataset sequences?? | |
974 | 1 | assertNull(copy.getDataset()); |
975 | // TODO test metadata is copied when AlignmentI is a dataset | |
976 | ||
977 | // assertArrayEquals(copy.getDataset().getSequencesArray(), protein | |
978 | // .getDataset().getSequencesArray()); | |
979 | } | |
980 | ||
981 | /** | |
982 | * Test behaviour of createDataset | |
983 | * | |
984 | * @throws IOException | |
985 | */ | |
986 | 1 | @Test(groups = "Functional") |
987 | public void testCreateDatasetAlignment() throws IOException | |
988 | { | |
989 | 1 | AlignmentI protein = new FormatAdapter().readFile(AA_SEQS_1, |
990 | DataSourceType.PASTE, FileFormat.Fasta); | |
991 | /* | |
992 | * create a dataset sequence on first sequence | |
993 | * leave the second without one | |
994 | */ | |
995 | 1 | protein.getSequenceAt(0).createDatasetSequence(); |
996 | 1 | assertNotNull(protein.getSequenceAt(0).getDatasetSequence()); |
997 | 1 | assertNull(protein.getSequenceAt(1).getDatasetSequence()); |
998 | ||
999 | /* | |
1000 | * add a mapping to the alignment | |
1001 | */ | |
1002 | 1 | AlignedCodonFrame acf = new AlignedCodonFrame(); |
1003 | 1 | protein.addCodonFrame(acf); |
1004 | 1 | assertNull(protein.getDataset()); |
1005 | 1 | assertTrue(protein.getCodonFrames().contains(acf)); |
1006 | ||
1007 | /* | |
1008 | * create the alignment dataset | |
1009 | * note this creates sequence datasets where missing | |
1010 | * as a side-effect (in this case, on seq2 | |
1011 | */ | |
1012 | // TODO promote this method to AlignmentI | |
1013 | 1 | ((Alignment) protein).createDatasetAlignment(); |
1014 | ||
1015 | 1 | AlignmentI ds = protein.getDataset(); |
1016 | ||
1017 | // side-effect: dataset created on second sequence | |
1018 | 1 | assertNotNull(protein.getSequenceAt(1).getDatasetSequence()); |
1019 | // dataset alignment has references to dataset sequences | |
1020 | 1 | assertEquals(ds.getSequenceAt(0), |
1021 | protein.getSequenceAt(0).getDatasetSequence()); | |
1022 | 1 | assertEquals(ds.getSequenceAt(1), |
1023 | protein.getSequenceAt(1).getDatasetSequence()); | |
1024 | ||
1025 | // codon frames should have been moved to the dataset | |
1026 | // getCodonFrames() should delegate to the dataset: | |
1027 | 1 | assertTrue(protein.getCodonFrames().contains(acf)); |
1028 | // prove the codon frames are indeed on the dataset: | |
1029 | 1 | assertTrue(ds.getCodonFrames().contains(acf)); |
1030 | } | |
1031 | ||
1032 | /** | |
1033 | * tests the addition of *all* sequences referred to by a sequence being added | |
1034 | * to the dataset | |
1035 | */ | |
1036 | 1 | @Test(groups = "Functional") |
1037 | public void testCreateDatasetAlignmentWithMappedToSeqs() | |
1038 | { | |
1039 | // Alignment with two sequences, gapped. | |
1040 | 1 | SequenceI sq1 = new Sequence("sq1", "A--SDF"); |
1041 | 1 | SequenceI sq2 = new Sequence("sq2", "G--TRQ"); |
1042 | ||
1043 | // cross-references to two more sequences. | |
1044 | 1 | DBRefEntry dbr = new DBRefEntry("SQ1", "", "sq3"); |
1045 | 1 | SequenceI sq3 = new Sequence("sq3", "VWANG"); |
1046 | 1 | dbr.setMap( |
1047 | new Mapping(sq3, new MapList(new int[] | |
1048 | { 1, 4 }, new int[] { 2, 5 }, 1, 1))); | |
1049 | 1 | sq1.addDBRef(dbr); |
1050 | ||
1051 | 1 | SequenceI sq4 = new Sequence("sq4", "ERKWI"); |
1052 | 1 | DBRefEntry dbr2 = new DBRefEntry("SQ2", "", "sq4"); |
1053 | 1 | dbr2.setMap( |
1054 | new Mapping(sq4, new MapList(new int[] | |
1055 | { 1, 4 }, new int[] { 2, 5 }, 1, 1))); | |
1056 | 1 | sq2.addDBRef(dbr2); |
1057 | // and a 1:1 codonframe mapping between them. | |
1058 | 1 | AlignedCodonFrame alc = new AlignedCodonFrame(); |
1059 | 1 | alc.addMap(sq1, sq2, |
1060 | new MapList(new int[] | |
1061 | { 1, 4 }, new int[] { 1, 4 }, 1, 1)); | |
1062 | ||
1063 | 1 | AlignmentI protein = new Alignment(new SequenceI[] { sq1, sq2 }); |
1064 | ||
1065 | /* | |
1066 | * create the alignment dataset | |
1067 | * note this creates sequence datasets where missing | |
1068 | * as a side-effect (in this case, on seq2 | |
1069 | */ | |
1070 | ||
1071 | // TODO promote this method to AlignmentI | |
1072 | 1 | ((Alignment) protein).createDatasetAlignment(); |
1073 | ||
1074 | 1 | AlignmentI ds = protein.getDataset(); |
1075 | ||
1076 | // should be 4 sequences in dataset - two materialised, and two propagated | |
1077 | // from dbref | |
1078 | 1 | assertEquals(4, ds.getHeight()); |
1079 | 1 | assertTrue(ds.getSequences().contains(sq1.getDatasetSequence())); |
1080 | 1 | assertTrue(ds.getSequences().contains(sq2.getDatasetSequence())); |
1081 | 1 | assertTrue(ds.getSequences().contains(sq3)); |
1082 | 1 | assertTrue(ds.getSequences().contains(sq4)); |
1083 | // Should have one codon frame mapping between sq1 and sq2 via dataset | |
1084 | // sequences | |
1085 | 1 | assertEquals(ds.getCodonFrame(sq1.getDatasetSequence()), |
1086 | ds.getCodonFrame(sq2.getDatasetSequence())); | |
1087 | } | |
1088 | ||
1089 | 1 | @Test(groups = "Functional") |
1090 | public void testAddCodonFrame() | |
1091 | { | |
1092 | 1 | AlignmentI align = new Alignment(new SequenceI[] {}); |
1093 | 1 | AlignedCodonFrame acf = new AlignedCodonFrame(); |
1094 | 1 | align.addCodonFrame(acf); |
1095 | 1 | assertEquals(1, align.getCodonFrames().size()); |
1096 | 1 | assertTrue(align.getCodonFrames().contains(acf)); |
1097 | // can't add the same object twice: | |
1098 | 1 | align.addCodonFrame(acf); |
1099 | 1 | assertEquals(1, align.getCodonFrames().size()); |
1100 | ||
1101 | // create dataset alignment - mappings move to dataset | |
1102 | 1 | ((Alignment) align).createDatasetAlignment(); |
1103 | 1 | assertSame(align.getCodonFrames(), align.getDataset().getCodonFrames()); |
1104 | 1 | assertEquals(1, align.getCodonFrames().size()); |
1105 | ||
1106 | 1 | AlignedCodonFrame acf2 = new AlignedCodonFrame(); |
1107 | 1 | align.addCodonFrame(acf2); |
1108 | 1 | assertTrue(align.getDataset().getCodonFrames().contains(acf)); |
1109 | } | |
1110 | ||
1111 | 1 | @Test(groups = "Functional") |
1112 | public void testAddSequencePreserveDatasetIntegrity() | |
1113 | { | |
1114 | 1 | Sequence seq = new Sequence("testSeq", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); |
1115 | 1 | Alignment align = new Alignment(new SequenceI[] { seq }); |
1116 | 1 | align.createDatasetAlignment(); |
1117 | 1 | AlignmentI ds = align.getDataset(); |
1118 | 1 | SequenceI copy = new Sequence(seq); |
1119 | 1 | copy.insertCharAt(3, 5, '-'); |
1120 | 1 | align.addSequence(copy); |
1121 | 1 | Assert.assertEquals(align.getDataset().getHeight(), 1, |
1122 | "Dataset shouldn't have more than one sequence."); | |
1123 | ||
1124 | 1 | Sequence seq2 = new Sequence("newtestSeq", |
1125 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); | |
1126 | 1 | align.addSequence(seq2); |
1127 | 1 | Assert.assertEquals(align.getDataset().getHeight(), 2, |
1128 | "Dataset should now have two sequences."); | |
1129 | ||
1130 | 1 | assertAlignmentDatasetRefs(align, |
1131 | "addSequence broke dataset reference integrity"); | |
1132 | } | |
1133 | ||
1134 | /** | |
1135 | * Tests that dbrefs with mappings to sequence get updated if the sequence | |
1136 | * acquires a dataset sequence | |
1137 | */ | |
1138 | 1 | @Test(groups = "Functional") |
1139 | public void testCreateDataset_updateDbrefMappings() | |
1140 | { | |
1141 | 1 | SequenceI pep = new Sequence("pep", "ASD"); |
1142 | 1 | SequenceI dna = new Sequence("dna", "aaaGCCTCGGATggg"); |
1143 | 1 | SequenceI cds = new Sequence("cds", "GCCTCGGAT"); |
1144 | ||
1145 | // add dbref from dna to peptide | |
1146 | 1 | DBRefEntry dbr = new DBRefEntry("UNIPROT", "", "pep"); |
1147 | 1 | dbr.setMap( |
1148 | new Mapping(pep, new MapList(new int[] | |
1149 | { 4, 15 }, new int[] { 1, 4 }, 3, 1))); | |
1150 | 1 | dna.addDBRef(dbr); |
1151 | ||
1152 | // add dbref from dna to peptide | |
1153 | 1 | DBRefEntry dbr2 = new DBRefEntry("UNIPROT", "", "pep"); |
1154 | 1 | dbr2.setMap( |
1155 | new Mapping(pep, new MapList(new int[] | |
1156 | { 1, 12 }, new int[] { 1, 4 }, 3, 1))); | |
1157 | 1 | cds.addDBRef(dbr2); |
1158 | ||
1159 | // add dbref from peptide to dna | |
1160 | 1 | DBRefEntry dbr3 = new DBRefEntry("EMBL", "", "dna"); |
1161 | 1 | dbr3.setMap( |
1162 | new Mapping(dna, new MapList(new int[] | |
1163 | { 1, 4 }, new int[] { 4, 15 }, 1, 3))); | |
1164 | 1 | pep.addDBRef(dbr3); |
1165 | ||
1166 | // add dbref from peptide to cds | |
1167 | 1 | DBRefEntry dbr4 = new DBRefEntry("EMBLCDS", "", "cds"); |
1168 | 1 | dbr4.setMap( |
1169 | new Mapping(cds, new MapList(new int[] | |
1170 | { 1, 4 }, new int[] { 1, 12 }, 1, 3))); | |
1171 | 1 | pep.addDBRef(dbr4); |
1172 | ||
1173 | 1 | AlignmentI protein = new Alignment(new SequenceI[] { pep }); |
1174 | ||
1175 | /* | |
1176 | * create the alignment dataset | |
1177 | */ | |
1178 | 1 | ((Alignment) protein).createDatasetAlignment(); |
1179 | ||
1180 | 1 | AlignmentI ds = protein.getDataset(); |
1181 | ||
1182 | // should be 3 sequences in dataset | |
1183 | 1 | assertEquals(3, ds.getHeight()); |
1184 | 1 | assertTrue(ds.getSequences().contains(pep.getDatasetSequence())); |
1185 | 1 | assertTrue(ds.getSequences().contains(dna)); |
1186 | 1 | assertTrue(ds.getSequences().contains(cds)); |
1187 | ||
1188 | /* | |
1189 | * verify peptide.cdsdbref.peptidedbref is now mapped to peptide dataset | |
1190 | */ | |
1191 | 1 | List<DBRefEntry> dbRefs = pep.getDBRefs(); |
1192 | 1 | assertEquals(2, dbRefs.size()); |
1193 | 1 | assertSame(dna, dbRefs.get(0).map.to); |
1194 | 1 | assertSame(cds, dbRefs.get(1).map.to); |
1195 | 1 | assertEquals(1, dna.getDBRefs().size()); |
1196 | 1 | assertSame(pep.getDatasetSequence(), dna.getDBRefs().get(0).map.to); |
1197 | 1 | assertEquals(1, cds.getDBRefs().size()); |
1198 | 1 | assertSame(pep.getDatasetSequence(), cds.getDBRefs().get(0).map.to); |
1199 | } | |
1200 | ||
1201 | 1 | @Test(groups = { "Functional" }) |
1202 | public void testFindGroup() | |
1203 | { | |
1204 | 1 | SequenceI seq1 = new Sequence("seq1", "ABCDEF---GHI"); |
1205 | 1 | SequenceI seq2 = new Sequence("seq2", "---JKLMNO---"); |
1206 | 1 | AlignmentI a = new Alignment(new SequenceI[] { seq1, seq2 }); |
1207 | ||
1208 | 1 | assertNull(a.findGroup(null, 0)); |
1209 | 1 | assertNull(a.findGroup(seq1, 1)); |
1210 | 1 | assertNull(a.findGroup(seq1, -1)); |
1211 | ||
1212 | /* | |
1213 | * add a group consisting of just "DEF" | |
1214 | */ | |
1215 | 1 | SequenceGroup sg1 = new SequenceGroup(); |
1216 | 1 | sg1.addSequence(seq1, false); |
1217 | 1 | sg1.setStartRes(3); |
1218 | 1 | sg1.setEndRes(5); |
1219 | 1 | a.addGroup(sg1); |
1220 | ||
1221 | 1 | assertNull(a.findGroup(seq1, 2)); // position not in group |
1222 | 1 | assertNull(a.findGroup(seq1, 6)); // position not in group |
1223 | 1 | assertNull(a.findGroup(seq2, 5)); // sequence not in group |
1224 | 1 | assertSame(a.findGroup(seq1, 3), sg1); // yes |
1225 | 1 | assertSame(a.findGroup(seq1, 4), sg1); |
1226 | 1 | assertSame(a.findGroup(seq1, 5), sg1); |
1227 | ||
1228 | /* | |
1229 | * add a group consisting of | |
1230 | * EF-- | |
1231 | * KLMN | |
1232 | */ | |
1233 | 1 | SequenceGroup sg2 = new SequenceGroup(); |
1234 | 1 | sg2.addSequence(seq1, false); |
1235 | 1 | sg2.addSequence(seq2, false); |
1236 | 1 | sg2.setStartRes(4); |
1237 | 1 | sg2.setEndRes(7); |
1238 | 1 | a.addGroup(sg2); |
1239 | ||
1240 | 1 | assertNull(a.findGroup(seq1, 2)); // unchanged |
1241 | 1 | assertSame(a.findGroup(seq1, 3), sg1); // unchanged |
1242 | /* | |
1243 | * if a residue is in more than one group, method returns | |
1244 | * the first found (in order groups were added) | |
1245 | */ | |
1246 | 1 | assertSame(a.findGroup(seq1, 4), sg1); |
1247 | 1 | assertSame(a.findGroup(seq1, 5), sg1); |
1248 | ||
1249 | /* | |
1250 | * seq2 only belongs to the second group | |
1251 | */ | |
1252 | 1 | assertSame(a.findGroup(seq2, 4), sg2); |
1253 | 1 | assertSame(a.findGroup(seq2, 5), sg2); |
1254 | 1 | assertSame(a.findGroup(seq2, 6), sg2); |
1255 | 1 | assertSame(a.findGroup(seq2, 7), sg2); |
1256 | 1 | assertNull(a.findGroup(seq2, 3)); |
1257 | 1 | assertNull(a.findGroup(seq2, 8)); |
1258 | } | |
1259 | ||
1260 | 1 | @Test(groups = { "Functional" }) |
1261 | public void testDeleteSequenceByIndex() | |
1262 | { | |
1263 | // create random alignment | |
1264 | 1 | AlignmentGenerator gen = new AlignmentGenerator(false); |
1265 | 1 | AlignmentI a = gen.generate(20, 15, 123, 5, 5); |
1266 | ||
1267 | // delete sequence 10, alignment reduced by 1 | |
1268 | 1 | int height = a.getAbsoluteHeight(); |
1269 | 1 | a.deleteSequence(10); |
1270 | 1 | assertEquals(a.getAbsoluteHeight(), height - 1); |
1271 | ||
1272 | // try to delete -ve index, nothing happens | |
1273 | 1 | a.deleteSequence(-1); |
1274 | 1 | assertEquals(a.getAbsoluteHeight(), height - 1); |
1275 | ||
1276 | // try to delete beyond end of alignment, nothing happens | |
1277 | 1 | a.deleteSequence(14); |
1278 | 1 | assertEquals(a.getAbsoluteHeight(), height - 1); |
1279 | } | |
1280 | ||
1281 | 1 | @Test(groups = { "Functional" }) |
1282 | public void testDeleteSequenceBySeq() | |
1283 | { | |
1284 | // create random alignment | |
1285 | 1 | AlignmentGenerator gen = new AlignmentGenerator(false); |
1286 | 1 | AlignmentI a = gen.generate(20, 15, 123, 5, 5); |
1287 | ||
1288 | // delete sequence 10, alignment reduced by 1 | |
1289 | 1 | int height = a.getAbsoluteHeight(); |
1290 | 1 | SequenceI seq = a.getSequenceAt(10); |
1291 | 1 | a.deleteSequence(seq); |
1292 | 1 | assertEquals(a.getAbsoluteHeight(), height - 1); |
1293 | ||
1294 | // try to delete non-existent sequence, nothing happens | |
1295 | 1 | seq = new Sequence("cds", "GCCTCGGAT"); |
1296 | 1 | assertEquals(a.getAbsoluteHeight(), height - 1); |
1297 | } | |
1298 | ||
1299 | 1 | @Test(groups = { "Functional" }) |
1300 | public void testDeleteHiddenSequence() | |
1301 | { | |
1302 | // create random alignment | |
1303 | 1 | AlignmentGenerator gen = new AlignmentGenerator(false); |
1304 | 1 | AlignmentI a = gen.generate(20, 15, 123, 5, 5); |
1305 | ||
1306 | // delete a sequence which is hidden, check it is NOT removed from hidden | |
1307 | // sequences | |
1308 | 1 | int height = a.getAbsoluteHeight(); |
1309 | 1 | SequenceI seq = a.getSequenceAt(2); |
1310 | 1 | a.getHiddenSequences().hideSequence(seq); |
1311 | 1 | assertEquals(a.getHiddenSequences().getSize(), 1); |
1312 | 1 | a.deleteSequence(2); |
1313 | 1 | assertEquals(a.getAbsoluteHeight(), height - 1); |
1314 | 1 | assertEquals(a.getHiddenSequences().getSize(), 1); |
1315 | ||
1316 | // delete a sequence which is not hidden, check hiddenSequences are not | |
1317 | // affected | |
1318 | 1 | a.deleteSequence(10); |
1319 | 1 | assertEquals(a.getAbsoluteHeight(), height - 2); |
1320 | 1 | assertEquals(a.getHiddenSequences().getSize(), 1); |
1321 | } | |
1322 | ||
1323 | 1 | @Test( |
1324 | groups = "Functional", | |
1325 | expectedExceptions = | |
1326 | { IllegalArgumentException.class }) | |
1327 | public void testSetDataset_selfReference() | |
1328 | { | |
1329 | 1 | SequenceI seq = new Sequence("a", "a"); |
1330 | 1 | AlignmentI alignment = new Alignment(new SequenceI[] { seq }); |
1331 | 1 | alignment.setDataset(alignment); |
1332 | } | |
1333 | ||
1334 | 1 | @Test(groups = "Functional") |
1335 | public void testAppend() | |
1336 | { | |
1337 | 1 | SequenceI seq = new Sequence("seq1", "FRMLPSRT-A--L-"); |
1338 | 1 | AlignmentI alignment = new Alignment(new SequenceI[] { seq }); |
1339 | 1 | alignment.setGapCharacter('-'); |
1340 | 1 | SequenceI seq2 = new Sequence("seq1", "KP..L.FQII."); |
1341 | 1 | AlignmentI alignment2 = new Alignment(new SequenceI[] { seq2 }); |
1342 | 1 | alignment2.setGapCharacter('.'); |
1343 | ||
1344 | 1 | alignment.append(alignment2); |
1345 | ||
1346 | 1 | assertEquals('-', alignment.getGapCharacter()); |
1347 | 1 | assertSame(seq, alignment.getSequenceAt(0)); |
1348 | 1 | assertEquals("KP--L-FQII-", |
1349 | alignment.getSequenceAt(1).getSequenceAsString()); | |
1350 | ||
1351 | // todo test coverage for annotations, mappings, groups, | |
1352 | // hidden sequences, properties | |
1353 | } | |
1354 | ||
1355 | /** | |
1356 | * test that calcId == null on findOrCreate doesn't raise an NPE, and yields | |
1357 | * an annotation with a null calcId | |
1358 | * | |
1359 | */ | |
1360 | 1 | @Test(groups = "Functional") |
1361 | public void testFindOrCreateForNullCalcId() | |
1362 | { | |
1363 | 1 | SequenceI seq = new Sequence("seq1", "FRMLPSRT-A--L-"); |
1364 | 1 | AlignmentI alignment = new Alignment(new SequenceI[] { seq }); |
1365 | ||
1366 | 1 | AlignmentAnnotation ala = alignment.findOrCreateAnnotation( |
1367 | "Temperature Factor", null, false, seq, null); | |
1368 | 1 | assertNotNull(ala); |
1369 | 1 | assertEquals(seq, ala.sequenceRef); |
1370 | 1 | assertEquals("", ala.calcId); |
1371 | } | |
1372 | ||
1373 | 1 | @Test(groups = "Functional") |
1374 | public void testPropagateInsertions() | |
1375 | { | |
1376 | // create an alignment with no gaps - this will be the profile seq and other | |
1377 | // JPRED seqs | |
1378 | 1 | AlignmentGenerator gen = new AlignmentGenerator(false); |
1379 | 1 | AlignmentI al = gen.generate(25, 10, 1234, 0, 0); |
1380 | ||
1381 | // get the profileseq | |
1382 | 1 | SequenceI profileseq = al.getSequenceAt(0); |
1383 | 1 | SequenceI gappedseq = new Sequence(profileseq); |
1384 | 1 | gappedseq.insertCharAt(5, al.getGapCharacter()); |
1385 | 1 | gappedseq.insertCharAt(6, al.getGapCharacter()); |
1386 | 1 | gappedseq.insertCharAt(7, al.getGapCharacter()); |
1387 | 1 | gappedseq.insertCharAt(8, al.getGapCharacter()); |
1388 | ||
1389 | // force different kinds of padding | |
1390 | 1 | al.getSequenceAt(3).deleteChars(2, 23); |
1391 | 1 | al.getSequenceAt(4).deleteChars(2, 27); |
1392 | 1 | al.getSequenceAt(5).deleteChars(10, 27); |
1393 | ||
1394 | // create an alignment view with the gapped sequence | |
1395 | 1 | SequenceI[] seqs = new SequenceI[1]; |
1396 | 1 | seqs[0] = gappedseq; |
1397 | 1 | AlignmentI newal = new Alignment(seqs); |
1398 | 1 | HiddenColumns hidden = new HiddenColumns(); |
1399 | 1 | hidden.hideColumns(15, 17); |
1400 | ||
1401 | 1 | AlignmentView view = new AlignmentView(newal, hidden, null, true, false, |
1402 | false); | |
1403 | ||
1404 | // confirm that original contigs are as expected | |
1405 | 1 | Iterator<int[]> visible = hidden.getVisContigsIterator(0, 25, false); |
1406 | 1 | int[] region = visible.next(); |
1407 | 1 | assertEquals("[0, 14]", Arrays.toString(region)); |
1408 | 1 | region = visible.next(); |
1409 | 1 | assertEquals("[18, 24]", Arrays.toString(region)); |
1410 | ||
1411 | // propagate insertions | |
1412 | 1 | HiddenColumns result = al.propagateInsertions(profileseq, view); |
1413 | ||
1414 | // confirm that the contigs have changed to account for the gaps | |
1415 | 1 | visible = result.getVisContigsIterator(0, 25, false); |
1416 | 1 | region = visible.next(); |
1417 | 1 | assertEquals("[0, 10]", Arrays.toString(region)); |
1418 | 1 | region = visible.next(); |
1419 | 1 | assertEquals("[14, 24]", Arrays.toString(region)); |
1420 | ||
1421 | // confirm the alignment has been changed so that the other sequences have | |
1422 | // gaps inserted where the columns are hidden | |
1423 | 1 | assertFalse(Comparison.isGap(al.getSequenceAt(1).getSequence()[10])); |
1424 | 1 | assertTrue(Comparison.isGap(al.getSequenceAt(1).getSequence()[11])); |
1425 | 1 | assertTrue(Comparison.isGap(al.getSequenceAt(1).getSequence()[12])); |
1426 | 1 | assertTrue(Comparison.isGap(al.getSequenceAt(1).getSequence()[13])); |
1427 | 1 | assertFalse(Comparison.isGap(al.getSequenceAt(1).getSequence()[14])); |
1428 | ||
1429 | } | |
1430 | ||
1431 | 1 | @Test(groups = "Functional") |
1432 | public void testPropagateInsertionsOverlap() | |
1433 | { | |
1434 | // test propagateInsertions where gaps and hiddenColumns overlap | |
1435 | ||
1436 | // create an alignment with no gaps - this will be the profile seq and other | |
1437 | // JPRED seqs | |
1438 | 1 | AlignmentGenerator gen = new AlignmentGenerator(false); |
1439 | 1 | AlignmentI al = gen.generate(20, 10, 1234, 0, 0); |
1440 | ||
1441 | // get the profileseq | |
1442 | 1 | SequenceI profileseq = al.getSequenceAt(0); |
1443 | 1 | SequenceI gappedseq = new Sequence(profileseq); |
1444 | 1 | gappedseq.insertCharAt(5, al.getGapCharacter()); |
1445 | 1 | gappedseq.insertCharAt(6, al.getGapCharacter()); |
1446 | 1 | gappedseq.insertCharAt(7, al.getGapCharacter()); |
1447 | 1 | gappedseq.insertCharAt(8, al.getGapCharacter()); |
1448 | ||
1449 | // create an alignment view with the gapped sequence | |
1450 | 1 | SequenceI[] seqs = new SequenceI[1]; |
1451 | 1 | seqs[0] = gappedseq; |
1452 | 1 | AlignmentI newal = new Alignment(seqs); |
1453 | ||
1454 | // hide columns so that some overlap with the gaps | |
1455 | 1 | HiddenColumns hidden = new HiddenColumns(); |
1456 | 1 | hidden.hideColumns(7, 10); |
1457 | ||
1458 | 1 | AlignmentView view = new AlignmentView(newal, hidden, null, true, false, |
1459 | false); | |
1460 | ||
1461 | // confirm that original contigs are as expected | |
1462 | 1 | Iterator<int[]> visible = hidden.getVisContigsIterator(0, 20, false); |
1463 | 1 | int[] region = visible.next(); |
1464 | 1 | assertEquals("[0, 6]", Arrays.toString(region)); |
1465 | 1 | region = visible.next(); |
1466 | 1 | assertEquals("[11, 19]", Arrays.toString(region)); |
1467 | 1 | assertFalse(visible.hasNext()); |
1468 | ||
1469 | // propagate insertions | |
1470 | 1 | HiddenColumns result = al.propagateInsertions(profileseq, view); |
1471 | ||
1472 | // confirm that the contigs have changed to account for the gaps | |
1473 | 1 | visible = result.getVisContigsIterator(0, 20, false); |
1474 | 1 | region = visible.next(); |
1475 | 1 | assertEquals("[0, 4]", Arrays.toString(region)); |
1476 | 1 | region = visible.next(); |
1477 | 1 | assertEquals("[7, 19]", Arrays.toString(region)); |
1478 | 1 | assertFalse(visible.hasNext()); |
1479 | ||
1480 | // confirm the alignment has been changed so that the other sequences have | |
1481 | // gaps inserted where the columns are hidden | |
1482 | 1 | assertFalse(Comparison.isGap(al.getSequenceAt(1).getSequence()[4])); |
1483 | 1 | assertTrue(Comparison.isGap(al.getSequenceAt(1).getSequence()[5])); |
1484 | 1 | assertTrue(Comparison.isGap(al.getSequenceAt(1).getSequence()[6])); |
1485 | 1 | assertFalse(Comparison.isGap(al.getSequenceAt(1).getSequence()[7])); |
1486 | } | |
1487 | ||
1488 | 1 | @Test(groups = { "Functional" }) |
1489 | public void testPadGaps() | |
1490 | { | |
1491 | 1 | SequenceI seq1 = new Sequence("seq1", "ABCDEF--"); |
1492 | 1 | SequenceI seq2 = new Sequence("seq2", "-JKLMNO--"); |
1493 | 1 | SequenceI seq3 = new Sequence("seq2", "-PQR"); |
1494 | 1 | AlignmentI a = new Alignment(new SequenceI[] { seq1, seq2, seq3 }); |
1495 | 1 | a.setGapCharacter('.'); // this replaces existing gaps |
1496 | 1 | assertEquals("ABCDEF..", seq1.getSequenceAsString()); |
1497 | 1 | a.padGaps(); |
1498 | // trailing gaps are pruned, short sequences padded with gap character | |
1499 | 1 | assertEquals("ABCDEF.", seq1.getSequenceAsString()); |
1500 | 1 | assertEquals(".JKLMNO", seq2.getSequenceAsString()); |
1501 | 1 | assertEquals(".PQR...", seq3.getSequenceAsString()); |
1502 | } | |
1503 | ||
1504 | /** | |
1505 | * Test for setHiddenColumns, to check it returns true if the hidden columns | |
1506 | * have changed, else false | |
1507 | */ | |
1508 | 1 | @Test(groups = { "Functional" }) |
1509 | public void testSetHiddenColumns() | |
1510 | { | |
1511 | 1 | AlignmentI al = new Alignment(new SequenceI[] {}); |
1512 | 1 | assertFalse(al.getHiddenColumns().hasHiddenColumns()); |
1513 | ||
1514 | 1 | HiddenColumns hc = new HiddenColumns(); |
1515 | 1 | assertFalse(al.setHiddenColumns(hc)); // no change |
1516 | 1 | assertSame(hc, al.getHiddenColumns()); |
1517 | ||
1518 | 1 | hc.hideColumns(2, 4); |
1519 | 1 | assertTrue(al.getHiddenColumns().hasHiddenColumns()); |
1520 | ||
1521 | /* | |
1522 | * set a different object but with the same columns hidden | |
1523 | */ | |
1524 | 1 | HiddenColumns hc2 = new HiddenColumns(); |
1525 | 1 | hc2.hideColumns(2, 4); |
1526 | 1 | assertFalse(al.setHiddenColumns(hc2)); // no change |
1527 | 1 | assertSame(hc2, al.getHiddenColumns()); |
1528 | ||
1529 | 1 | assertTrue(al.setHiddenColumns(null)); |
1530 | 1 | assertNull(al.getHiddenColumns()); |
1531 | 1 | assertTrue(al.setHiddenColumns(hc)); |
1532 | 1 | assertSame(hc, al.getHiddenColumns()); |
1533 | ||
1534 | 1 | al.getHiddenColumns().hideColumns(10, 12); |
1535 | 1 | hc2.hideColumns(10, 12); |
1536 | 1 | assertFalse(al.setHiddenColumns(hc2)); // no change |
1537 | ||
1538 | /* | |
1539 | * hide columns 15-16 then 17-18 in hc | |
1540 | * hide columns 15-18 in hc2 | |
1541 | * these are not now 'equal' objects even though they | |
1542 | * represent the same set of columns | |
1543 | */ | |
1544 | 1 | assertSame(hc2, al.getHiddenColumns()); |
1545 | 1 | hc.hideColumns(15, 16); |
1546 | 1 | hc.hideColumns(17, 18); |
1547 | 1 | hc2.hideColumns(15, 18); |
1548 | 1 | assertFalse(hc.equals(hc2)); |
1549 | 1 | assertTrue(al.setHiddenColumns(hc)); // 'changed' |
1550 | } | |
1551 | ||
1552 | 1 | @Test(groups = { "Functional" }) |
1553 | public void testGetWidth() | |
1554 | { | |
1555 | 1 | SequenceI seq1 = new Sequence("seq1", "ABCDEF--"); |
1556 | 1 | SequenceI seq2 = new Sequence("seq2", "-JKLMNO--"); |
1557 | 1 | SequenceI seq3 = new Sequence("seq2", "-PQR"); |
1558 | 1 | AlignmentI a = new Alignment(new SequenceI[] { seq1, seq2, seq3 }); |
1559 | ||
1560 | 1 | assertEquals(9, a.getWidth()); |
1561 | ||
1562 | // width includes hidden columns | |
1563 | 1 | a.getHiddenColumns().hideColumns(2, 5); |
1564 | 1 | assertEquals(9, a.getWidth()); |
1565 | } | |
1566 | ||
1567 | 1 | @Test(groups = { "Functional" }) |
1568 | public void testGetVisibleWidth() | |
1569 | { | |
1570 | 1 | SequenceI seq1 = new Sequence("seq1", "ABCDEF--"); |
1571 | 1 | SequenceI seq2 = new Sequence("seq2", "-JKLMNO--"); |
1572 | 1 | SequenceI seq3 = new Sequence("seq2", "-PQR"); |
1573 | 1 | AlignmentI a = new Alignment(new SequenceI[] { seq1, seq2, seq3 }); |
1574 | ||
1575 | 1 | assertEquals(9, a.getVisibleWidth()); |
1576 | ||
1577 | // width excludes hidden columns | |
1578 | 1 | a.getHiddenColumns().hideColumns(2, 5); |
1579 | 1 | assertEquals(5, a.getVisibleWidth()); |
1580 | } | |
1581 | ||
1582 | 1 | @Test(groups = { "Functional" }) |
1583 | public void testGetContactMap() | |
1584 | { | |
1585 | // TODO | |
1586 | // 1. test adding/removing/manipulating contact maps with/without associated | |
1587 | // sequence(s) or groups | |
1588 | // 2. For sequence associated - ensure that inserting a gap in sequence | |
1589 | // results in the contact map being relocated accordingly | |
1590 | // 3. RENDERER QUESTION - should contact maps reflect gaps in the alignment | |
1591 | // ? | |
1592 | ||
1593 | } | |
1594 | ||
1595 | 1 | @Test(groups = { "Functional" }) |
1596 | public void testEquals() | |
1597 | { | |
1598 | 1 | SequenceI seq1 = new Sequence("seq1", "ABCDEF--"); |
1599 | 1 | SequenceI seq2 = new Sequence("seq2", "-JKLMNO--"); |
1600 | 1 | SequenceI seq3 = new Sequence("seq2", "-PQR"); |
1601 | 1 | AlignmentI a = new Alignment(new SequenceI[] { seq1, seq2, seq3 }); |
1602 | 1 | a.setDataset(null); |
1603 | 1 | assertEquals(a.getDataset(), a.getDataset()); |
1604 | } | |
1605 | } |