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