merge
[jalview.git] / test / jalview / commands / EditCommandTest.java
1 package jalview.commands;
2
3 import static org.testng.AssertJUnit.assertEquals;
4 import static org.testng.AssertJUnit.assertSame;
5
6 import jalview.commands.EditCommand.Action;
7 import jalview.commands.EditCommand.Edit;
8 import jalview.datamodel.Alignment;
9 import jalview.datamodel.AlignmentI;
10 import jalview.datamodel.Sequence;
11 import jalview.datamodel.SequenceI;
12
13 import java.util.Map;
14
15 import org.testng.annotations.BeforeMethod;
16 import org.testng.annotations.Test;
17
18 /**
19  * Unit tests for EditCommand
20  * 
21  * @author gmcarstairs
22  *
23  */
24 public class EditCommandTest
25 {
26
27   private EditCommand testee;
28
29   private SequenceI[] seqs;
30
31   private Alignment al;
32
33  @BeforeMethod(alwaysRun = true)
34    public void setUp()
35   {
36     testee = new EditCommand();
37     seqs = new SequenceI[4];
38     seqs[0] = new Sequence("seq0", "abcdefghjk");
39     seqs[0].setDatasetSequence(new Sequence("seq0ds", "abcdefghjk"));
40     seqs[1] = new Sequence("seq1", "fghjklmnopq");
41     seqs[1].setDatasetSequence(new Sequence("seq1ds", "fghjklmnopq"));
42     seqs[2] = new Sequence("seq2", "qrstuvwxyz");
43     seqs[2].setDatasetSequence(new Sequence("seq2ds", "qrstuvwxyz"));
44     seqs[3] = new Sequence("seq3", "1234567890");
45     seqs[3].setDatasetSequence(new Sequence("seq3ds", "1234567890"));
46     al = new Alignment(seqs);
47     al.setGapCharacter('?');
48   }
49
50   /**
51    * Test inserting gap characters
52    */
53   @Test(groups ={ "Functional" })
54   public void testAppendEdit_insertGap()
55   {
56     // set a non-standard gap character to prove it is actually used
57     testee.appendEdit(Action.INSERT_GAP, seqs, 4, 3, al, true);
58     assertEquals("abcd???efghjk", seqs[0].getSequenceAsString());
59     assertEquals("fghj???klmnopq", seqs[1].getSequenceAsString());
60     assertEquals("qrst???uvwxyz", seqs[2].getSequenceAsString());
61     assertEquals("1234???567890", seqs[3].getSequenceAsString());
62
63     // todo: test for handling out of range positions?
64   }
65
66   /**
67    * Test deleting characters from sequences. Note the deleteGap() action does
68    * not check that only gap characters are being removed.
69    */
70   @Test(groups ={ "Functional" })
71   public void testAppendEdit_deleteGap()
72   {
73     testee.appendEdit(Action.DELETE_GAP, seqs, 4, 3, al, true);
74     assertEquals("abcdhjk", seqs[0].getSequenceAsString());
75     assertEquals("fghjnopq", seqs[1].getSequenceAsString());
76     assertEquals("qrstxyz", seqs[2].getSequenceAsString());
77     assertEquals("1234890", seqs[3].getSequenceAsString());
78   }
79
80   /**
81    * Test a cut action. The command should store the cut characters to support
82    * undo.
83    */
84   @Test(groups ={ "Functional" })
85   public void testCut()
86   {
87     Edit ec = testee.new Edit(Action.CUT, seqs, 4, 3, al);
88     testee.cut(ec, new AlignmentI[]
89     { al });
90     assertEquals("abcdhjk", seqs[0].getSequenceAsString());
91     assertEquals("fghjnopq", seqs[1].getSequenceAsString());
92     assertEquals("qrstxyz", seqs[2].getSequenceAsString());
93     assertEquals("1234890", seqs[3].getSequenceAsString());
94
95     assertEquals("efg", new String(ec.string[0]));
96     assertEquals("klm", new String(ec.string[1]));
97     assertEquals("uvw", new String(ec.string[2]));
98     assertEquals("567", new String(ec.string[3]));
99     // TODO: case where whole sequence is deleted as nothing left; etc
100   }
101
102   /**
103    * Test a Paste action, where this adds sequences to an alignment.
104    */
105   @Test(groups =
106   { "Functional" }, enabled = false)
107   // TODO fix so it works
108   public void testPaste_addToAlignment()
109   {
110     SequenceI[] newSeqs = new SequenceI[2];
111     newSeqs[0] = new Sequence("newseq0", "ACEFKL");
112     newSeqs[1] = new Sequence("newseq1", "JWMPDH");
113
114     Edit ec = testee.new Edit(Action.PASTE, newSeqs, 0, al.getWidth(), al);
115     testee.paste(ec, new AlignmentI[]
116     { al });
117     assertEquals(6, al.getSequences().size());
118     assertEquals("1234567890", seqs[3].getSequenceAsString());
119     assertEquals("ACEFKL", seqs[4].getSequenceAsString());
120     assertEquals("JWMPDH", seqs[5].getSequenceAsString());
121   }
122
123   /**
124    * Test insertGap followed by undo command
125    */
126   @Test(groups ={ "Functional" })
127   public void testUndo_insertGap()
128   {
129     // Edit ec = testee.new Edit(Action.INSERT_GAP, seqs, 4, 3, '?');
130     testee.appendEdit(Action.INSERT_GAP, seqs, 4, 3, al, true);
131     // check something changed
132     assertEquals("abcd???efghjk", seqs[0].getSequenceAsString());
133     testee.undoCommand(new AlignmentI[]
134     { al });
135     assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
136     assertEquals("fghjklmnopq", seqs[1].getSequenceAsString());
137     assertEquals("qrstuvwxyz", seqs[2].getSequenceAsString());
138     assertEquals("1234567890", seqs[3].getSequenceAsString());
139   }
140
141   /**
142    * Test deleteGap followed by undo command
143    */
144   @Test(groups ={ "Functional" })
145   public void testUndo_deleteGap()
146   {
147     testee.appendEdit(Action.DELETE_GAP, seqs, 4, 3, al, true);
148     // check something changed
149     assertEquals("abcdhjk", seqs[0].getSequenceAsString());
150     testee.undoCommand(new AlignmentI[]
151     { al });
152     // deleteGap doesn't 'remember' deleted characters, only gaps get put back
153     assertEquals("abcd???hjk", seqs[0].getSequenceAsString());
154     assertEquals("fghj???nopq", seqs[1].getSequenceAsString());
155     assertEquals("qrst???xyz", seqs[2].getSequenceAsString());
156     assertEquals("1234???890", seqs[3].getSequenceAsString());
157   }
158
159   /**
160    * Test several commands followed by an undo command
161    */
162   @Test(groups ={ "Functional" })
163   public void testUndo_multipleCommands()
164   {
165     // delete positions 3/4/5 (counting from 1)
166     testee.appendEdit(Action.DELETE_GAP, seqs, 2, 3, al, true);
167     assertEquals("abfghjk", seqs[0].getSequenceAsString());
168     assertEquals("1267890", seqs[3].getSequenceAsString());
169
170     // insert 2 gaps after the second residue
171     testee.appendEdit(Action.INSERT_GAP, seqs, 2, 2, al, true);
172     assertEquals("ab??fghjk", seqs[0].getSequenceAsString());
173     assertEquals("12??67890", seqs[3].getSequenceAsString());
174
175     // delete positions 4/5/6
176     testee.appendEdit(Action.DELETE_GAP, seqs, 3, 3, al, true);
177     assertEquals("ab?hjk", seqs[0].getSequenceAsString());
178     assertEquals("12?890", seqs[3].getSequenceAsString());
179
180     // undo edit commands
181     testee.undoCommand(new AlignmentI[]
182     { al });
183     assertEquals("ab?????hjk", seqs[0].getSequenceAsString());
184     assertEquals("12?????890", seqs[3].getSequenceAsString());
185   }
186
187   /**
188    * Unit test for JAL-1594 bug: click and drag sequence right to insert gaps -
189    * undo did not remove them all.
190    */
191   @Test(groups ={ "Functional" })
192   public void testUndo_multipleInsertGaps()
193   {
194     testee.appendEdit(Action.INSERT_GAP, seqs, 4, 1, al, true);
195     testee.appendEdit(Action.INSERT_GAP, seqs, 5, 1, al, true);
196     testee.appendEdit(Action.INSERT_GAP, seqs, 6, 1, al, true);
197
198     // undo edit commands
199     testee.undoCommand(new AlignmentI[]
200     { al });
201     assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
202     assertEquals("1234567890", seqs[3].getSequenceAsString());
203
204   }
205
206   /**
207    * Test cut followed by undo command
208    */
209   @Test(groups ={ "Functional" })
210   public void testUndo_cut()
211   {
212     testee.appendEdit(Action.CUT, seqs, 4, 3, al, true);
213     // check something changed
214     assertEquals("abcdhjk", seqs[0].getSequenceAsString());
215     testee.undoCommand(new AlignmentI[]
216     { al });
217     assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
218     assertEquals("fghjklmnopq", seqs[1].getSequenceAsString());
219     assertEquals("qrstuvwxyz", seqs[2].getSequenceAsString());
220     assertEquals("1234567890", seqs[3].getSequenceAsString());
221   }
222
223   /**
224    * Test the replace command (used to manually edit a sequence)
225    */
226   @Test(groups ={ "Functional" })
227   public void testReplace()
228   {
229     // seem to need a dataset sequence on the edited sequence here
230     seqs[1].setDatasetSequence(seqs[1]);
231     new EditCommand("", Action.REPLACE, "ZXY", new SequenceI[]
232     { seqs[1] }, 4, 8, al);
233     assertEquals("abcdefghjk", seqs[0].getSequenceAsString());
234     assertEquals("qrstuvwxyz", seqs[2].getSequenceAsString());
235     assertEquals("1234567890", seqs[3].getSequenceAsString());
236     seqs[1] = new Sequence("seq1", "fghjZXYnopq");
237   }
238
239   /**
240    * Test that the addEdit command correctly merges insert gap commands when
241    * possible.
242    */
243   @Test(groups ={ "Functional" })
244   public void testAddEdit_multipleInsertGap()
245   {
246     /*
247      * 3 insert gap in a row (aka mouse drag right):
248      */
249     Edit e = new EditCommand().new Edit(Action.INSERT_GAP, new SequenceI[]
250     { seqs[0] }, 1, 1, al);
251     testee.addEdit(e);
252     SequenceI edited = new Sequence("seq0", "a?bcdefghjk");
253     edited.setDatasetSequence(seqs[0].getDatasetSequence());
254     e = new EditCommand().new Edit(Action.INSERT_GAP, new SequenceI[]
255     { edited }, 2, 1, al);
256     testee.addEdit(e);
257     edited = new Sequence("seq0", "a??bcdefghjk");
258     edited.setDatasetSequence(seqs[0].getDatasetSequence());
259     e = new EditCommand().new Edit(Action.INSERT_GAP, new SequenceI[]
260     { edited }, 3, 1, al);
261     testee.addEdit(e);
262     assertEquals(1, testee.getSize());
263     assertEquals(Action.INSERT_GAP, testee.getEdit(0).getAction());
264     assertEquals(1, testee.getEdit(0).getPosition());
265     assertEquals(3, testee.getEdit(0).getNumber());
266
267     /*
268      * Add a non-contiguous edit - should not be merged.
269      */
270     e = new EditCommand().new Edit(Action.INSERT_GAP, new SequenceI[]
271     { edited }, 5, 2, al);
272     testee.addEdit(e);
273     assertEquals(2, testee.getSize());
274     assertEquals(5, testee.getEdit(1).getPosition());
275     assertEquals(2, testee.getEdit(1).getNumber());
276
277     /*
278      * Add a Delete after the Insert - should not be merged.
279      */
280     e = new EditCommand().new Edit(Action.DELETE_GAP, new SequenceI[]
281     { edited }, 6, 2, al);
282     testee.addEdit(e);
283     assertEquals(3, testee.getSize());
284     assertEquals(Action.DELETE_GAP, testee.getEdit(2).getAction());
285     assertEquals(6, testee.getEdit(2).getPosition());
286     assertEquals(2, testee.getEdit(2).getNumber());
287   }
288
289   /**
290    * Test that the addEdit command correctly merges delete gap commands when
291    * possible.
292    */
293   @Test(groups ={ "Functional" })
294   public void testAddEdit_multipleDeleteGap()
295   {
296     /*
297      * 3 delete gap in a row (aka mouse drag left):
298      */
299     seqs[0].setSequence("a???bcdefghjk");
300     Edit e = new EditCommand().new Edit(Action.DELETE_GAP, new SequenceI[]
301     { seqs[0] }, 4, 1, al);
302     testee.addEdit(e);
303     assertEquals(1, testee.getSize());
304
305     SequenceI edited = new Sequence("seq0", "a??bcdefghjk");
306     edited.setDatasetSequence(seqs[0].getDatasetSequence());
307     e = new EditCommand().new Edit(Action.DELETE_GAP, new SequenceI[]
308     { edited }, 3, 1, al);
309     testee.addEdit(e);
310     assertEquals(1, testee.getSize());
311
312     edited = new Sequence("seq0", "a?bcdefghjk");
313     edited.setDatasetSequence(seqs[0].getDatasetSequence());
314     e = new EditCommand().new Edit(Action.DELETE_GAP, new SequenceI[]
315     { edited }, 2, 1, al);
316     testee.addEdit(e);
317     assertEquals(1, testee.getSize());
318     assertEquals(Action.DELETE_GAP, testee.getEdit(0).getAction());
319     assertEquals(2, testee.getEdit(0).getPosition());
320     assertEquals(3, testee.getEdit(0).getNumber());
321
322     /*
323      * Add a non-contiguous edit - should not be merged.
324      */
325     e = new EditCommand().new Edit(Action.DELETE_GAP, new SequenceI[]
326     { edited }, 2, 1, al);
327     testee.addEdit(e);
328     assertEquals(2, testee.getSize());
329     assertEquals(Action.DELETE_GAP, testee.getEdit(0).getAction());
330     assertEquals(2, testee.getEdit(1).getPosition());
331     assertEquals(1, testee.getEdit(1).getNumber());
332
333     /*
334      * Add an Insert after the Delete - should not be merged.
335      */
336     e = new EditCommand().new Edit(Action.INSERT_GAP, new SequenceI[]
337     { edited }, 1, 1, al);
338     testee.addEdit(e);
339     assertEquals(3, testee.getSize());
340     assertEquals(Action.INSERT_GAP, testee.getEdit(2).getAction());
341     assertEquals(1, testee.getEdit(2).getPosition());
342     assertEquals(1, testee.getEdit(2).getNumber());
343   }
344
345   /**
346    * Test that the addEdit command correctly handles 'remove gaps' edits for the
347    * case when they appear contiguous but are acting on different sequences.
348    * They should not be merged.
349    */
350   @Test(groups ={ "Functional" })
351   public void testAddEdit_removeAllGaps()
352   {
353     seqs[0].setSequence("a???bcdefghjk");
354     Edit e = new EditCommand().new Edit(Action.DELETE_GAP, new SequenceI[]
355     { seqs[0] }, 4, 1, al);
356     testee.addEdit(e);
357
358     seqs[1].setSequence("f??ghjklmnopq");
359     Edit e2 = new EditCommand().new Edit(Action.DELETE_GAP, new SequenceI[]
360     { seqs[1] }, 3, 1, al);
361     testee.addEdit(e2);
362     assertEquals(2, testee.getSize());
363     assertSame(e, testee.getEdit(0));
364     assertSame(e2, testee.getEdit(1));
365   }
366
367   /**
368    * Test that the addEdit command correctly merges insert gap commands acting
369    * on a multi-sequence selection.
370    */
371   @Test(groups ={ "Functional" })
372   public void testAddEdit_groupInsertGaps()
373   {
374     /*
375      * 2 insert gap in a row (aka mouse drag right), on two sequences:
376      */
377     Edit e = new EditCommand().new Edit(Action.INSERT_GAP, new SequenceI[]
378     { seqs[0], seqs[1] }, 1, 1, al);
379     testee.addEdit(e);
380     SequenceI seq1edited = new Sequence("seq0", "a?bcdefghjk");
381     seq1edited.setDatasetSequence(seqs[0].getDatasetSequence());
382     SequenceI seq2edited = new Sequence("seq1", "f?ghjklmnopq");
383     seq2edited.setDatasetSequence(seqs[1].getDatasetSequence());
384     e = new EditCommand().new Edit(Action.INSERT_GAP, new SequenceI[]
385     { seq1edited, seq2edited }, 2, 1, al);
386     testee.addEdit(e);
387
388     assertEquals(1, testee.getSize());
389     assertEquals(Action.INSERT_GAP, testee.getEdit(0).getAction());
390     assertEquals(1, testee.getEdit(0).getPosition());
391     assertEquals(2, testee.getEdit(0).getNumber());
392     assertEquals(seqs[0].getDatasetSequence(), testee.getEdit(0)
393             .getSequences()[0].getDatasetSequence());
394     assertEquals(seqs[1].getDatasetSequence(), testee.getEdit(0)
395             .getSequences()[1].getDatasetSequence());
396   }
397
398   /**
399    * Test for 'undoing' a series of gap insertions.
400    * <ul>
401    * <li>Start: ABCDEF insert 2 at pos 1</li>
402    * <li>next: A--BCDEF insert 1 at pos 4</li>
403    * <li>next: A--B-CDEF insert 2 at pos 0</li>
404    * <li>last: --A--B-CDEF</li>
405    * </ul>
406    */
407   @Test(groups ={ "Functional" })
408   public void testPriorState_multipleInserts()
409   {
410     EditCommand command = new EditCommand();
411     SequenceI seq = new Sequence("", "--A--B-CDEF");
412     SequenceI ds = new Sequence("", "ABCDEF");
413     seq.setDatasetSequence(ds);
414     SequenceI[] seqs = new SequenceI[]
415     { seq };
416     Edit e = command.new Edit(Action.INSERT_GAP, seqs, 1, 2, '-');
417     command.addEdit(e);
418     e = command.new Edit(Action.INSERT_GAP, seqs, 4, 1, '-');
419     command.addEdit(e);
420     e = command.new Edit(Action.INSERT_GAP, seqs, 0, 2, '-');
421     command.addEdit(e);
422
423     Map<SequenceI, SequenceI> unwound = command.priorState(false);
424     assertEquals("ABCDEF", unwound.get(ds).getSequenceAsString());
425   }
426
427   /**
428    * Test for 'undoing' a series of gap deletions.
429    * <ul>
430    * <li>Start: A-B-C delete 1 at pos 1</li>
431    * <li>Next: AB-C delete 1 at pos 2</li>
432    * <li>End: ABC</li>
433    * </ul>
434    */
435   @Test(groups ={ "Functional" })
436   public void testPriorState_removeAllGaps()
437   {
438     EditCommand command = new EditCommand();
439     SequenceI seq = new Sequence("", "ABC");
440     SequenceI ds = new Sequence("", "ABC");
441     seq.setDatasetSequence(ds);
442     SequenceI[] seqs = new SequenceI[]
443     { seq };
444     Edit e = command.new Edit(Action.DELETE_GAP, seqs, 1, 1, '-');
445     command.addEdit(e);
446     e = command.new Edit(Action.DELETE_GAP, seqs, 2, 1, '-');
447     command.addEdit(e);
448
449     Map<SequenceI, SequenceI> unwound = command.priorState(false);
450     assertEquals("A-B-C", unwound.get(ds).getSequenceAsString());
451   }
452
453   /**
454    * Test for 'undoing' a single delete edit.
455    */
456   @Test(groups ={ "Functional" })
457   public void testPriorState_singleDelete()
458   {
459     EditCommand command = new EditCommand();
460     SequenceI seq = new Sequence("", "ABCDEF");
461     SequenceI ds = new Sequence("", "ABCDEF");
462     seq.setDatasetSequence(ds);
463     SequenceI[] seqs = new SequenceI[]
464     { seq };
465     Edit e = command.new Edit(Action.DELETE_GAP, seqs, 2, 2, '-');
466     command.addEdit(e);
467   
468     Map<SequenceI, SequenceI> unwound = command.priorState(false);
469     assertEquals("AB--CDEF", unwound.get(ds).getSequenceAsString());
470   }
471
472   /**
473    * Test 'undoing' a single gap insertion edit command.
474    */
475   @Test(groups ={ "Functional" })
476   public void testPriorState_singleInsert()
477   {
478     EditCommand command = new EditCommand();
479     SequenceI seq = new Sequence("", "AB---CDEF");
480     SequenceI ds = new Sequence("", "ABCDEF");
481     seq.setDatasetSequence(ds);
482     SequenceI[] seqs = new SequenceI[]
483     { seq };
484     Edit e = command.new Edit(Action.INSERT_GAP, seqs, 2, 3, '-');
485     command.addEdit(e);
486   
487     Map<SequenceI, SequenceI> unwound = command.priorState(false);
488     assertEquals("ABCDEF", unwound.get(ds).getSequenceAsString());
489   }
490
491   /**
492    * Test that mimics 'remove all gaps' action. This generates delete gap edits
493    * for contiguous gaps in each sequence separately.
494    */
495   @Test(groups ={ "Functional" })
496   public void testPriorState_removeGapsMultipleSeqs()
497   {
498     EditCommand command = new EditCommand();
499     String original1 = "--ABC-DEF";
500     String original2 = "FG-HI--J";
501     String original3 = "M-NOPQ";
502
503     /*
504      * Two edits for the first sequence
505      */
506     SequenceI seq = new Sequence("", "ABC-DEF");
507     SequenceI ds1 = new Sequence("", "ABCDEF");
508     seq.setDatasetSequence(ds1);
509     SequenceI[] seqs = new SequenceI[]
510     { seq };
511     Edit e = command.new Edit(Action.DELETE_GAP, seqs, 0, 2, '-');
512     command.addEdit(e);
513     seq = new Sequence("", "ABCDEF");
514     seq.setDatasetSequence(ds1);
515     seqs = new SequenceI[]
516     { seq };
517     e = command.new Edit(Action.DELETE_GAP, seqs, 3, 1, '-');
518     command.addEdit(e);
519   
520     /*
521      * Two edits for the second sequence
522      */
523     seq = new Sequence("", "FGHI--J");
524     SequenceI ds2 = new Sequence("", "FGHIJ");
525     seq.setDatasetSequence(ds2);
526     seqs = new SequenceI[]
527     { seq };
528     e = command.new Edit(Action.DELETE_GAP, seqs, 2, 1, '-');
529     command.addEdit(e);
530     seq = new Sequence("", "FGHIJ");
531     seq.setDatasetSequence(ds2);
532     seqs = new SequenceI[]
533     { seq };
534     e = command.new Edit(Action.DELETE_GAP, seqs, 4, 2, '-');
535     command.addEdit(e);
536
537     /*
538      * One edit for the third sequence.
539      */
540     seq = new Sequence("", "MNOPQ");
541     SequenceI ds3 = new Sequence("", "MNOPQ");
542     seq.setDatasetSequence(ds3);
543     seqs = new SequenceI[]
544     { seq };
545     e = command.new Edit(Action.DELETE_GAP, seqs, 1, 1, '-');
546     command.addEdit(e);
547
548     Map<SequenceI, SequenceI> unwound = command.priorState(false);
549     assertEquals(original1, unwound.get(ds1).getSequenceAsString());
550     assertEquals(original2, unwound.get(ds2).getSequenceAsString());
551     assertEquals(original3, unwound.get(ds3).getSequenceAsString());
552   }
553
554   /**
555    * Test that mimics 'remove all gapped columns' action. This generates a
556    * series Delete Gap edits that each act on all sequences that share a gapped
557    * column region.
558    */
559   @Test(groups ={ "Functional" })
560   public void testPriorState_removeGappedCols()
561   {
562     EditCommand command = new EditCommand();
563     String original1 = "--ABC--DEF";
564     String original2 = "-G-HI--J";
565     String original3 = "-M-NO--PQ";
566
567     /*
568      * First edit deletes the first column.
569      */
570     SequenceI seq1 = new Sequence("", "-ABC--DEF");
571     SequenceI ds1 = new Sequence("", "ABCDEF");
572     seq1.setDatasetSequence(ds1);
573     SequenceI seq2 = new Sequence("", "G-HI--J");
574     SequenceI ds2 = new Sequence("", "GHIJ");
575     seq2.setDatasetSequence(ds2);
576     SequenceI seq3 = new Sequence("", "M-NO--PQ");
577     SequenceI ds3 = new Sequence("", "MNOPQ");
578     seq3.setDatasetSequence(ds3);
579     SequenceI[] seqs = new SequenceI[]
580     { seq1, seq2, seq3 };
581     Edit e = command.new Edit(Action.DELETE_GAP, seqs, 0, 1, '-');
582     command.addEdit(e);
583
584     /*
585      * Second edit deletes what is now columns 4 and 5.
586      */
587     seq1 = new Sequence("", "-ABCDEF");
588     seq1.setDatasetSequence(ds1);
589     seq2 = new Sequence("", "G-HIJ");
590     seq2.setDatasetSequence(ds2);
591     seq3 = new Sequence("", "M-NOPQ");
592     seq3.setDatasetSequence(ds3);
593     seqs = new SequenceI[]
594     { seq1, seq2, seq3 };
595     e = command.new Edit(Action.DELETE_GAP, seqs, 4, 2, '-');
596     command.addEdit(e);
597
598     Map<SequenceI, SequenceI> unwound = command.priorState(false);
599     assertEquals(original1, unwound.get(ds1).getSequenceAsString());
600     assertEquals(original2, unwound.get(ds2).getSequenceAsString());
601     assertEquals(original3, unwound.get(ds3).getSequenceAsString());
602     assertEquals(ds1, unwound.get(ds1).getDatasetSequence());
603     assertEquals(ds2, unwound.get(ds2).getDatasetSequence());
604     assertEquals(ds3, unwound.get(ds3).getDatasetSequence());
605   }
606 }