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.commands;
23 import static org.testng.AssertJUnit.assertEquals;
24 import static org.testng.AssertJUnit.assertSame;
26 import jalview.commands.EditCommand.Action;
27 import jalview.commands.EditCommand.Edit;
28 import jalview.datamodel.Alignment;
29 import jalview.datamodel.AlignmentI;
30 import jalview.datamodel.Sequence;
31 import jalview.datamodel.SequenceI;
35 import org.testng.annotations.BeforeMethod;
36 import org.testng.annotations.Test;
39 * Unit tests for EditCommand
44 public class EditCommandTest
47 private EditCommand testee;
49 private SequenceI[] seqs;
53 @BeforeMethod(alwaysRun = true)
56 testee = new EditCommand();
57 seqs = new SequenceI[4];
58 seqs[0] = new Sequence("seq0", "abcdefghjk");
59 seqs[0].setDatasetSequence(new Sequence("seq0ds", "abcdefghjk"));
60 seqs[1] = new Sequence("seq1", "fghjklmnopq");
61 seqs[1].setDatasetSequence(new Sequence("seq1ds", "fghjklmnopq"));
62 seqs[2] = new Sequence("seq2", "qrstuvwxyz");
63 seqs[2].setDatasetSequence(new Sequence("seq2ds", "qrstuvwxyz"));
64 seqs[3] = new Sequence("seq3", "1234567890");
65 seqs[3].setDatasetSequence(new Sequence("seq3ds", "1234567890"));
66 al = new Alignment(seqs);
67 al.setGapCharacter('?');
71 * Test inserting gap characters
73 @Test(groups = { "Functional" })
74 public void testAppendEdit_insertGap()
76 // set a non-standard gap character to prove it is actually used
77 testee.appendEdit(Action.INSERT_GAP, seqs, 4, 3, al, true);
78 assertEquals("abcd???efghjk", seqs[0].getSequenceAsString());
79 assertEquals("fghj???klmnopq", seqs[1].getSequenceAsString());
80 assertEquals("qrst???uvwxyz", seqs[2].getSequenceAsString());
81 assertEquals("1234???567890", seqs[3].getSequenceAsString());
83 // todo: test for handling out of range positions?
87 * Test deleting characters from sequences. Note the deleteGap() action does
88 * not check that only gap characters are being removed.
90 @Test(groups = { "Functional" })
91 public void testAppendEdit_deleteGap()
93 testee.appendEdit(Action.DELETE_GAP, seqs, 4, 3, al, true);
94 assertEquals("abcdhjk", seqs[0].getSequenceAsString());
95 assertEquals("fghjnopq", seqs[1].getSequenceAsString());
96 assertEquals("qrstxyz", seqs[2].getSequenceAsString());
97 assertEquals("1234890", seqs[3].getSequenceAsString());
101 * Test a cut action. The command should store the cut characters to support
104 @Test(groups = { "Functional" })
105 public void testCut()
107 Edit ec = testee.new Edit(Action.CUT, seqs, 4, 3, al);
108 EditCommand.cut(ec, new AlignmentI[] { al });
109 assertEquals("abcdhjk", seqs[0].getSequenceAsString());
110 assertEquals("fghjnopq", seqs[1].getSequenceAsString());
111 assertEquals("qrstxyz", seqs[2].getSequenceAsString());
112 assertEquals("1234890", seqs[3].getSequenceAsString());
114 assertEquals("efg", new String(ec.string[0]));
115 assertEquals("klm", new String(ec.string[1]));
116 assertEquals("uvw", new String(ec.string[2]));
117 assertEquals("567", new String(ec.string[3]));
118 // TODO: case where whole sequence is deleted as nothing left; etc
122 * Test a Paste action, where this adds sequences to an alignment.
124 @Test(groups = { "Functional" }, enabled = false)
125 // TODO fix so it works
126 public void testPaste_addToAlignment()
128 SequenceI[] newSeqs = new SequenceI[2];
129 newSeqs[0] = new Sequence("newseq0", "ACEFKL");
130 newSeqs[1] = new Sequence("newseq1", "JWMPDH");
132 Edit ec = testee.new Edit(Action.PASTE, newSeqs, 0, al.getWidth(), al);
133 EditCommand.paste(ec, new AlignmentI[] { al });
134 assertEquals(6, al.getSequences().size());
135 assertEquals("1234567890", seqs[3].getSequenceAsString());
136 assertEquals("ACEFKL", seqs[4].getSequenceAsString());
137 assertEquals("JWMPDH", seqs[5].getSequenceAsString());
141 * Test insertGap followed by undo command
143 @Test(groups = { "Functional" })
144 public void testUndo_insertGap()
146 // Edit ec = testee.new Edit(Action.INSERT_GAP, seqs, 4, 3, '?');
147 testee.appendEdit(Action.INSERT_GAP, seqs, 4, 3, al, true);
148 // check something changed
149 assertEquals("abcd???efghjk", seqs[0].getSequenceAsString());
150 testee.undoCommand(new AlignmentI[] { al });
151 assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
152 assertEquals("fghjklmnopq", seqs[1].getSequenceAsString());
153 assertEquals("qrstuvwxyz", seqs[2].getSequenceAsString());
154 assertEquals("1234567890", seqs[3].getSequenceAsString());
158 * Test deleteGap followed by undo command
160 @Test(groups = { "Functional" })
161 public void testUndo_deleteGap()
163 testee.appendEdit(Action.DELETE_GAP, seqs, 4, 3, al, true);
164 // check something changed
165 assertEquals("abcdhjk", seqs[0].getSequenceAsString());
166 testee.undoCommand(new AlignmentI[] { al });
167 // deleteGap doesn't 'remember' deleted characters, only gaps get put back
168 assertEquals("abcd???hjk", seqs[0].getSequenceAsString());
169 assertEquals("fghj???nopq", seqs[1].getSequenceAsString());
170 assertEquals("qrst???xyz", seqs[2].getSequenceAsString());
171 assertEquals("1234???890", seqs[3].getSequenceAsString());
175 * Test several commands followed by an undo command
177 @Test(groups = { "Functional" })
178 public void testUndo_multipleCommands()
180 // delete positions 3/4/5 (counting from 1)
181 testee.appendEdit(Action.DELETE_GAP, seqs, 2, 3, al, true);
182 assertEquals("abfghjk", seqs[0].getSequenceAsString());
183 assertEquals("1267890", seqs[3].getSequenceAsString());
185 // insert 2 gaps after the second residue
186 testee.appendEdit(Action.INSERT_GAP, seqs, 2, 2, al, true);
187 assertEquals("ab??fghjk", seqs[0].getSequenceAsString());
188 assertEquals("12??67890", seqs[3].getSequenceAsString());
190 // delete positions 4/5/6
191 testee.appendEdit(Action.DELETE_GAP, seqs, 3, 3, al, true);
192 assertEquals("ab?hjk", seqs[0].getSequenceAsString());
193 assertEquals("12?890", seqs[3].getSequenceAsString());
195 // undo edit commands
196 testee.undoCommand(new AlignmentI[] { al });
197 assertEquals("ab?????hjk", seqs[0].getSequenceAsString());
198 assertEquals("12?????890", seqs[3].getSequenceAsString());
202 * Unit test for JAL-1594 bug: click and drag sequence right to insert gaps -
203 * undo did not remove them all.
205 @Test(groups = { "Functional" })
206 public void testUndo_multipleInsertGaps()
208 testee.appendEdit(Action.INSERT_GAP, seqs, 4, 1, al, true);
209 testee.appendEdit(Action.INSERT_GAP, seqs, 5, 1, al, true);
210 testee.appendEdit(Action.INSERT_GAP, seqs, 6, 1, al, true);
212 // undo edit commands
213 testee.undoCommand(new AlignmentI[] { al });
214 assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
215 assertEquals("1234567890", seqs[3].getSequenceAsString());
220 * Test cut followed by undo command
222 @Test(groups = { "Functional" })
223 public void testUndo_cut()
225 testee.appendEdit(Action.CUT, seqs, 4, 3, al, true);
226 // check something changed
227 assertEquals("abcdhjk", seqs[0].getSequenceAsString());
228 testee.undoCommand(new AlignmentI[] { al });
229 assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
230 assertEquals("fghjklmnopq", seqs[1].getSequenceAsString());
231 assertEquals("qrstuvwxyz", seqs[2].getSequenceAsString());
232 assertEquals("1234567890", seqs[3].getSequenceAsString());
236 * Test the replace command (used to manually edit a sequence)
238 @Test(groups = { "Functional" })
239 public void testReplace()
241 // seem to need a dataset sequence on the edited sequence here
242 seqs[1].createDatasetSequence();
243 new EditCommand("", Action.REPLACE, "ZXY", new SequenceI[] { seqs[1] },
245 assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
246 assertEquals("qrstuvwxyz", seqs[2].getSequenceAsString());
247 assertEquals("1234567890", seqs[3].getSequenceAsString());
248 seqs[1] = new Sequence("seq1", "fghjZXYnopq");
252 * Test that the addEdit command correctly merges insert gap commands when
255 @Test(groups = { "Functional" })
256 public void testAddEdit_multipleInsertGap()
259 * 3 insert gap in a row (aka mouse drag right):
261 Edit e = new EditCommand().new Edit(Action.INSERT_GAP,
262 new SequenceI[] { seqs[0] }, 1, 1, al);
264 SequenceI edited = new Sequence("seq0", "a?bcdefghjk");
265 edited.setDatasetSequence(seqs[0].getDatasetSequence());
266 e = new EditCommand().new Edit(Action.INSERT_GAP,
267 new SequenceI[] { edited }, 2, 1, al);
269 edited = new Sequence("seq0", "a??bcdefghjk");
270 edited.setDatasetSequence(seqs[0].getDatasetSequence());
271 e = new EditCommand().new Edit(Action.INSERT_GAP,
272 new SequenceI[] { edited }, 3, 1, al);
274 assertEquals(1, testee.getSize());
275 assertEquals(Action.INSERT_GAP, testee.getEdit(0).getAction());
276 assertEquals(1, testee.getEdit(0).getPosition());
277 assertEquals(3, testee.getEdit(0).getNumber());
280 * Add a non-contiguous edit - should not be merged.
282 e = new EditCommand().new Edit(Action.INSERT_GAP,
283 new SequenceI[] { edited }, 5, 2, al);
285 assertEquals(2, testee.getSize());
286 assertEquals(5, testee.getEdit(1).getPosition());
287 assertEquals(2, testee.getEdit(1).getNumber());
290 * Add a Delete after the Insert - should not be merged.
292 e = new EditCommand().new Edit(Action.DELETE_GAP,
293 new SequenceI[] { edited }, 6, 2, al);
295 assertEquals(3, testee.getSize());
296 assertEquals(Action.DELETE_GAP, testee.getEdit(2).getAction());
297 assertEquals(6, testee.getEdit(2).getPosition());
298 assertEquals(2, testee.getEdit(2).getNumber());
302 * Test that the addEdit command correctly merges delete gap commands when
305 @Test(groups = { "Functional" })
306 public void testAddEdit_multipleDeleteGap()
309 * 3 delete gap in a row (aka mouse drag left):
311 seqs[0].setSequence("a???bcdefghjk");
312 Edit e = new EditCommand().new Edit(Action.DELETE_GAP,
313 new SequenceI[] { seqs[0] }, 4, 1, al);
315 assertEquals(1, testee.getSize());
317 SequenceI edited = new Sequence("seq0", "a??bcdefghjk");
318 edited.setDatasetSequence(seqs[0].getDatasetSequence());
319 e = new EditCommand().new Edit(Action.DELETE_GAP,
320 new SequenceI[] { edited }, 3, 1, al);
322 assertEquals(1, testee.getSize());
324 edited = new Sequence("seq0", "a?bcdefghjk");
325 edited.setDatasetSequence(seqs[0].getDatasetSequence());
326 e = new EditCommand().new Edit(Action.DELETE_GAP,
327 new SequenceI[] { edited }, 2, 1, al);
329 assertEquals(1, testee.getSize());
330 assertEquals(Action.DELETE_GAP, testee.getEdit(0).getAction());
331 assertEquals(2, testee.getEdit(0).getPosition());
332 assertEquals(3, testee.getEdit(0).getNumber());
335 * Add a non-contiguous edit - should not be merged.
337 e = new EditCommand().new Edit(Action.DELETE_GAP,
338 new SequenceI[] { edited }, 2, 1, al);
340 assertEquals(2, testee.getSize());
341 assertEquals(Action.DELETE_GAP, testee.getEdit(0).getAction());
342 assertEquals(2, testee.getEdit(1).getPosition());
343 assertEquals(1, testee.getEdit(1).getNumber());
346 * Add an Insert after the Delete - should not be merged.
348 e = new EditCommand().new Edit(Action.INSERT_GAP,
349 new SequenceI[] { edited }, 1, 1, al);
351 assertEquals(3, testee.getSize());
352 assertEquals(Action.INSERT_GAP, testee.getEdit(2).getAction());
353 assertEquals(1, testee.getEdit(2).getPosition());
354 assertEquals(1, testee.getEdit(2).getNumber());
358 * Test that the addEdit command correctly handles 'remove gaps' edits for the
359 * case when they appear contiguous but are acting on different sequences.
360 * They should not be merged.
362 @Test(groups = { "Functional" })
363 public void testAddEdit_removeAllGaps()
365 seqs[0].setSequence("a???bcdefghjk");
366 Edit e = new EditCommand().new Edit(Action.DELETE_GAP,
367 new SequenceI[] { seqs[0] }, 4, 1, al);
370 seqs[1].setSequence("f??ghjklmnopq");
371 Edit e2 = new EditCommand().new Edit(Action.DELETE_GAP, new SequenceI[]
372 { seqs[1] }, 3, 1, al);
374 assertEquals(2, testee.getSize());
375 assertSame(e, testee.getEdit(0));
376 assertSame(e2, testee.getEdit(1));
380 * Test that the addEdit command correctly merges insert gap commands acting
381 * on a multi-sequence selection.
383 @Test(groups = { "Functional" })
384 public void testAddEdit_groupInsertGaps()
387 * 2 insert gap in a row (aka mouse drag right), on two sequences:
389 Edit e = new EditCommand().new Edit(Action.INSERT_GAP, new SequenceI[] {
390 seqs[0], seqs[1] }, 1, 1, al);
392 SequenceI seq1edited = new Sequence("seq0", "a?bcdefghjk");
393 seq1edited.setDatasetSequence(seqs[0].getDatasetSequence());
394 SequenceI seq2edited = new Sequence("seq1", "f?ghjklmnopq");
395 seq2edited.setDatasetSequence(seqs[1].getDatasetSequence());
396 e = new EditCommand().new Edit(Action.INSERT_GAP, new SequenceI[] {
397 seq1edited, seq2edited }, 2, 1, al);
400 assertEquals(1, testee.getSize());
401 assertEquals(Action.INSERT_GAP, testee.getEdit(0).getAction());
402 assertEquals(1, testee.getEdit(0).getPosition());
403 assertEquals(2, testee.getEdit(0).getNumber());
404 assertEquals(seqs[0].getDatasetSequence(), testee.getEdit(0)
405 .getSequences()[0].getDatasetSequence());
406 assertEquals(seqs[1].getDatasetSequence(), testee.getEdit(0)
407 .getSequences()[1].getDatasetSequence());
411 * Test for 'undoing' a series of gap insertions.
413 * <li>Start: ABCDEF insert 2 at pos 1</li>
414 * <li>next: A--BCDEF insert 1 at pos 4</li>
415 * <li>next: A--B-CDEF insert 2 at pos 0</li>
416 * <li>last: --A--B-CDEF</li>
419 @Test(groups = { "Functional" })
420 public void testPriorState_multipleInserts()
422 EditCommand command = new EditCommand();
423 SequenceI seq = new Sequence("", "--A--B-CDEF");
424 SequenceI ds = new Sequence("", "ABCDEF");
425 seq.setDatasetSequence(ds);
426 SequenceI[] sqs = new SequenceI[] { seq };
427 Edit e = command.new Edit(Action.INSERT_GAP, sqs, 1, 2, '-');
429 e = command.new Edit(Action.INSERT_GAP, sqs, 4, 1, '-');
431 e = command.new Edit(Action.INSERT_GAP, sqs, 0, 2, '-');
434 Map<SequenceI, SequenceI> unwound = command.priorState(false);
435 assertEquals("ABCDEF", unwound.get(ds).getSequenceAsString());
439 * Test for 'undoing' a series of gap deletions.
441 * <li>Start: A-B-C delete 1 at pos 1</li>
442 * <li>Next: AB-C delete 1 at pos 2</li>
446 @Test(groups = { "Functional" })
447 public void testPriorState_removeAllGaps()
449 EditCommand command = new EditCommand();
450 SequenceI seq = new Sequence("", "ABC");
451 SequenceI ds = new Sequence("", "ABC");
452 seq.setDatasetSequence(ds);
453 SequenceI[] sqs = new SequenceI[] { seq };
454 Edit e = command.new Edit(Action.DELETE_GAP, sqs, 1, 1, '-');
456 e = command.new Edit(Action.DELETE_GAP, sqs, 2, 1, '-');
459 Map<SequenceI, SequenceI> unwound = command.priorState(false);
460 assertEquals("A-B-C", unwound.get(ds).getSequenceAsString());
464 * Test for 'undoing' a single delete edit.
466 @Test(groups = { "Functional" })
467 public void testPriorState_singleDelete()
469 EditCommand command = new EditCommand();
470 SequenceI seq = new Sequence("", "ABCDEF");
471 SequenceI ds = new Sequence("", "ABCDEF");
472 seq.setDatasetSequence(ds);
473 SequenceI[] sqs = new SequenceI[] { seq };
474 Edit e = command.new Edit(Action.DELETE_GAP, sqs, 2, 2, '-');
477 Map<SequenceI, SequenceI> unwound = command.priorState(false);
478 assertEquals("AB--CDEF", unwound.get(ds).getSequenceAsString());
482 * Test 'undoing' a single gap insertion edit command.
484 @Test(groups = { "Functional" })
485 public void testPriorState_singleInsert()
487 EditCommand command = new EditCommand();
488 SequenceI seq = new Sequence("", "AB---CDEF");
489 SequenceI ds = new Sequence("", "ABCDEF");
490 seq.setDatasetSequence(ds);
491 SequenceI[] sqs = new SequenceI[] { seq };
492 Edit e = command.new Edit(Action.INSERT_GAP, sqs, 2, 3, '-');
495 Map<SequenceI, SequenceI> unwound = command.priorState(false);
496 SequenceI prior = unwound.get(ds);
497 assertEquals("ABCDEF", prior.getSequenceAsString());
498 assertEquals(1, prior.getStart());
499 assertEquals(6, prior.getEnd());
503 * Test 'undoing' a single gap insertion edit command, on a sequence whose
504 * start residue is other than 1
506 @Test(groups = { "Functional" })
507 public void testPriorState_singleInsertWithOffset()
509 EditCommand command = new EditCommand();
510 SequenceI seq = new Sequence("", "AB---CDEF", 8, 13);
511 // SequenceI ds = new Sequence("", "ABCDEF", 8, 13);
512 // seq.setDatasetSequence(ds);
513 seq.createDatasetSequence();
514 SequenceI[] sqs = new SequenceI[] { seq };
515 Edit e = command.new Edit(Action.INSERT_GAP, sqs, 2, 3, '-');
518 Map<SequenceI, SequenceI> unwound = command.priorState(false);
519 SequenceI prior = unwound.get(seq.getDatasetSequence());
520 assertEquals("ABCDEF", prior.getSequenceAsString());
521 assertEquals(8, prior.getStart());
522 assertEquals(13, prior.getEnd());
526 * Test that mimics 'remove all gaps' action. This generates delete gap edits
527 * for contiguous gaps in each sequence separately.
529 @Test(groups = { "Functional" })
530 public void testPriorState_removeGapsMultipleSeqs()
532 EditCommand command = new EditCommand();
533 String original1 = "--ABC-DEF";
534 String original2 = "FG-HI--J";
535 String original3 = "M-NOPQ";
538 * Two edits for the first sequence
540 SequenceI seq = new Sequence("", "ABC-DEF");
541 SequenceI ds1 = new Sequence("", "ABCDEF");
542 seq.setDatasetSequence(ds1);
543 SequenceI[] sqs = new SequenceI[] { seq };
544 Edit e = command.new Edit(Action.DELETE_GAP, sqs, 0, 2, '-');
546 seq = new Sequence("", "ABCDEF");
547 seq.setDatasetSequence(ds1);
548 sqs = new SequenceI[] { seq };
549 e = command.new Edit(Action.DELETE_GAP, sqs, 3, 1, '-');
553 * Two edits for the second sequence
555 seq = new Sequence("", "FGHI--J");
556 SequenceI ds2 = new Sequence("", "FGHIJ");
557 seq.setDatasetSequence(ds2);
558 sqs = new SequenceI[] { seq };
559 e = command.new Edit(Action.DELETE_GAP, sqs, 2, 1, '-');
561 seq = new Sequence("", "FGHIJ");
562 seq.setDatasetSequence(ds2);
563 sqs = new SequenceI[] { seq };
564 e = command.new Edit(Action.DELETE_GAP, sqs, 4, 2, '-');
568 * One edit for the third sequence.
570 seq = new Sequence("", "MNOPQ");
571 SequenceI ds3 = new Sequence("", "MNOPQ");
572 seq.setDatasetSequence(ds3);
573 sqs = new SequenceI[] { seq };
574 e = command.new Edit(Action.DELETE_GAP, sqs, 1, 1, '-');
577 Map<SequenceI, SequenceI> unwound = command.priorState(false);
578 assertEquals(original1, unwound.get(ds1).getSequenceAsString());
579 assertEquals(original2, unwound.get(ds2).getSequenceAsString());
580 assertEquals(original3, unwound.get(ds3).getSequenceAsString());
584 * Test that mimics 'remove all gapped columns' action. This generates a
585 * series Delete Gap edits that each act on all sequences that share a gapped
588 @Test(groups = { "Functional" })
589 public void testPriorState_removeGappedCols()
591 EditCommand command = new EditCommand();
592 String original1 = "--ABC--DEF";
593 String original2 = "-G-HI--J";
594 String original3 = "-M-NO--PQ";
597 * First edit deletes the first column.
599 SequenceI seq1 = new Sequence("", "-ABC--DEF");
600 SequenceI ds1 = new Sequence("", "ABCDEF");
601 seq1.setDatasetSequence(ds1);
602 SequenceI seq2 = new Sequence("", "G-HI--J");
603 SequenceI ds2 = new Sequence("", "GHIJ");
604 seq2.setDatasetSequence(ds2);
605 SequenceI seq3 = new Sequence("", "M-NO--PQ");
606 SequenceI ds3 = new Sequence("", "MNOPQ");
607 seq3.setDatasetSequence(ds3);
608 SequenceI[] sqs = new SequenceI[] { seq1, seq2, seq3 };
609 Edit e = command.new Edit(Action.DELETE_GAP, sqs, 0, 1, '-');
613 * Second edit deletes what is now columns 4 and 5.
615 seq1 = new Sequence("", "-ABCDEF");
616 seq1.setDatasetSequence(ds1);
617 seq2 = new Sequence("", "G-HIJ");
618 seq2.setDatasetSequence(ds2);
619 seq3 = new Sequence("", "M-NOPQ");
620 seq3.setDatasetSequence(ds3);
621 sqs = new SequenceI[] { seq1, seq2, seq3 };
622 e = command.new Edit(Action.DELETE_GAP, sqs, 4, 2, '-');
625 Map<SequenceI, SequenceI> unwound = command.priorState(false);
626 assertEquals(original1, unwound.get(ds1).getSequenceAsString());
627 assertEquals(original2, unwound.get(ds2).getSequenceAsString());
628 assertEquals(original3, unwound.get(ds3).getSequenceAsString());
629 assertEquals(ds1, unwound.get(ds1).getDatasetSequence());
630 assertEquals(ds2, unwound.get(ds2).getDatasetSequence());
631 assertEquals(ds3, unwound.get(ds3).getDatasetSequence());