JAL-1270 Fixed anntatedPDBFileInputTest and updated implementation for testDeriveSequ...
[jalview.git] / test / jalview / datamodel / SequenceTest.java
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 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
30
31 import jalview.datamodel.PDBEntry.Type;
32
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.List;
36 import java.util.Vector;
37
38 import org.testng.Assert;
39 import org.testng.annotations.BeforeMethod;
40 import org.testng.annotations.Test;
41
42 public class SequenceTest
43 {
44   Sequence seq;
45
46   @BeforeMethod(alwaysRun = true)
47   public void setUp()
48   {
49     seq = new Sequence("FER1", "AKPNGVL");
50   }
51
52   @Test(groups = { "Functional" })
53   public void testInsertGapsAndGapmaps()
54   {
55     SequenceI aseq = seq.deriveSequence();
56     aseq.insertCharAt(2, 3, '-');
57     aseq.insertCharAt(6, 3, '-');
58     assertEquals("Gap insertions not correct", "AK---P---NGVL",
59             aseq.getSequenceAsString());
60     List<int[]> gapInt = aseq.getInsertions();
61     assertEquals("Gap interval 1 start wrong", 2, gapInt.get(0)[0]);
62     assertEquals("Gap interval 1 end wrong", 4, gapInt.get(0)[1]);
63     assertEquals("Gap interval 2 start wrong", 6, gapInt.get(1)[0]);
64     assertEquals("Gap interval 2 end wrong", 8, gapInt.get(1)[1]);
65   }
66
67   @Test(groups = { "Functional" })
68   public void testGetAnnotation()
69   {
70     // initial state returns null not an empty array
71     assertNull(seq.getAnnotation());
72     AlignmentAnnotation ann = addAnnotation("label1", "desc1", "calcId1",
73             1f);
74     AlignmentAnnotation[] anns = seq.getAnnotation();
75     assertEquals(1, anns.length);
76     assertSame(ann, anns[0]);
77
78     // removing all annotations reverts array to null
79     seq.removeAlignmentAnnotation(ann);
80     assertNull(seq.getAnnotation());
81   }
82
83   @Test(groups = { "Functional" })
84   public void testGetAnnotation_forLabel()
85   {
86     AlignmentAnnotation ann1 = addAnnotation("label1", "desc1", "calcId1",
87             1f);
88     AlignmentAnnotation ann2 = addAnnotation("label2", "desc2", "calcId2",
89             1f);
90     AlignmentAnnotation ann3 = addAnnotation("label1", "desc3", "calcId3",
91             1f);
92     AlignmentAnnotation[] anns = seq.getAnnotation("label1");
93     assertEquals(2, anns.length);
94     assertSame(ann1, anns[0]);
95     assertSame(ann3, anns[1]);
96   }
97
98   private AlignmentAnnotation addAnnotation(String label,
99           String description, String calcId, float value)
100   {
101     final AlignmentAnnotation annotation = new AlignmentAnnotation(label,
102             description, value);
103     annotation.setCalcId(calcId);
104     seq.addAlignmentAnnotation(annotation);
105     return annotation;
106   }
107
108   @Test(groups = { "Functional" })
109   public void testGetAlignmentAnnotations_forCalcIdAndLabel()
110   {
111     AlignmentAnnotation ann1 = addAnnotation("label1", "desc1", "calcId1",
112             1f);
113     AlignmentAnnotation ann2 = addAnnotation("label2", "desc2", "calcId2",
114             1f);
115     AlignmentAnnotation ann3 = addAnnotation("label2", "desc3", "calcId3",
116             1f);
117     AlignmentAnnotation ann4 = addAnnotation("label2", "desc3", "calcId2",
118             1f);
119     AlignmentAnnotation ann5 = addAnnotation("label5", "desc3", null, 1f);
120     AlignmentAnnotation ann6 = addAnnotation(null, "desc3", "calcId3", 1f);
121     List<AlignmentAnnotation> anns = seq.getAlignmentAnnotations("calcId2",
122             "label2");
123     assertEquals(2, anns.size());
124     assertSame(ann2, anns.get(0));
125     assertSame(ann4, anns.get(1));
126
127     assertTrue(seq.getAlignmentAnnotations("calcId2", "label3").isEmpty());
128     assertTrue(seq.getAlignmentAnnotations("calcId3", "label5").isEmpty());
129     assertTrue(seq.getAlignmentAnnotations("calcId2", null).isEmpty());
130     assertTrue(seq.getAlignmentAnnotations(null, "label3").isEmpty());
131     assertTrue(seq.getAlignmentAnnotations(null, null).isEmpty());
132   }
133
134   /**
135    * Tests for addAlignmentAnnotation. Note this method has the side-effect of
136    * setting the sequenceRef on the annotation. Adding the same annotation twice
137    * should be ignored.
138    */
139   @Test(groups = { "Functional" })
140   public void testAddAlignmentAnnotation()
141   {
142     assertNull(seq.getAnnotation());
143     final AlignmentAnnotation annotation = new AlignmentAnnotation("a",
144             "b", 2d);
145     assertNull(annotation.sequenceRef);
146     seq.addAlignmentAnnotation(annotation);
147     assertSame(seq, annotation.sequenceRef);
148     AlignmentAnnotation[] anns = seq.getAnnotation();
149     assertEquals(1, anns.length);
150     assertSame(annotation, anns[0]);
151
152     // re-adding does nothing
153     seq.addAlignmentAnnotation(annotation);
154     anns = seq.getAnnotation();
155     assertEquals(1, anns.length);
156     assertSame(annotation, anns[0]);
157
158     // an identical but different annotation can be added
159     final AlignmentAnnotation annotation2 = new AlignmentAnnotation("a",
160             "b", 2d);
161     seq.addAlignmentAnnotation(annotation2);
162     anns = seq.getAnnotation();
163     assertEquals(2, anns.length);
164     assertSame(annotation, anns[0]);
165     assertSame(annotation2, anns[1]);
166   }
167
168   @Test(groups = { "Functional" })
169   public void testGetStartGetEnd()
170   {
171     SequenceI sq = new Sequence("test", "ABCDEF");
172     assertEquals(1, sq.getStart());
173     assertEquals(6, sq.getEnd());
174
175     sq = new Sequence("test", "--AB-C-DEF--");
176     assertEquals(1, sq.getStart());
177     assertEquals(6, sq.getEnd());
178
179     sq = new Sequence("test", "----");
180     assertEquals(1, sq.getStart());
181     assertEquals(0, sq.getEnd()); // ??
182   }
183
184   /**
185    * Tests for the method that returns an alignment column position (base 1) for
186    * a given sequence position (base 1).
187    */
188   @Test(groups = { "Functional" })
189   public void testFindIndex()
190   {
191     SequenceI sq = new Sequence("test", "ABCDEF");
192     assertEquals(0, sq.findIndex(0));
193     assertEquals(1, sq.findIndex(1));
194     assertEquals(5, sq.findIndex(5));
195     assertEquals(6, sq.findIndex(6));
196     assertEquals(6, sq.findIndex(9));
197
198     sq = new Sequence("test", "-A--B-C-D-E-F--");
199     assertEquals(2, sq.findIndex(1));
200     assertEquals(5, sq.findIndex(2));
201     assertEquals(7, sq.findIndex(3));
202
203     // before start returns 0
204     assertEquals(0, sq.findIndex(0));
205     assertEquals(0, sq.findIndex(-1));
206
207     // beyond end returns last residue column
208     assertEquals(13, sq.findIndex(99));
209
210   }
211
212   /**
213    * Tests for the method that returns a dataset sequence position (base 1) for
214    * an aligned column position (base 0).
215    */
216   @Test(groups = { "Functional" })
217   public void testFindPosition()
218   {
219     SequenceI sq = new Sequence("test", "ABCDEF");
220     assertEquals(1, sq.findPosition(0));
221     assertEquals(6, sq.findPosition(5));
222     // assertEquals(-1, seq.findPosition(6)); // fails
223
224     sq = new Sequence("test", "AB-C-D--");
225     assertEquals(1, sq.findPosition(0));
226     assertEquals(2, sq.findPosition(1));
227     // gap position 'finds' residue to the right (not the left as per javadoc)
228     assertEquals(3, sq.findPosition(2));
229     assertEquals(3, sq.findPosition(3));
230     assertEquals(4, sq.findPosition(4));
231     assertEquals(4, sq.findPosition(5));
232     // returns 1 more than sequence length if off the end ?!?
233     assertEquals(5, sq.findPosition(6));
234     assertEquals(5, sq.findPosition(7));
235
236     sq = new Sequence("test", "--AB-C-DEF--");
237     assertEquals(1, sq.findPosition(0));
238     assertEquals(1, sq.findPosition(1));
239     assertEquals(1, sq.findPosition(2));
240     assertEquals(2, sq.findPosition(3));
241     assertEquals(3, sq.findPosition(4));
242     assertEquals(3, sq.findPosition(5));
243     assertEquals(4, sq.findPosition(6));
244     assertEquals(4, sq.findPosition(7));
245     assertEquals(5, sq.findPosition(8));
246     assertEquals(6, sq.findPosition(9));
247     assertEquals(7, sq.findPosition(10));
248     assertEquals(7, sq.findPosition(11));
249   }
250
251   @Test(groups = { "Functional" })
252   public void testDeleteChars()
253   {
254     SequenceI sq = new Sequence("test", "ABCDEF");
255     assertEquals(1, sq.getStart());
256     assertEquals(6, sq.getEnd());
257     sq.deleteChars(2, 3);
258     assertEquals("ABDEF", sq.getSequenceAsString());
259     assertEquals(1, sq.getStart());
260     assertEquals(5, sq.getEnd());
261
262     sq = new Sequence("test", "ABCDEF");
263     sq.deleteChars(0, 2);
264     assertEquals("CDEF", sq.getSequenceAsString());
265     assertEquals(3, sq.getStart());
266     assertEquals(6, sq.getEnd());
267   }
268
269   @Test(groups = { "Functional" })
270   public void testInsertCharAt()
271   {
272     // non-static methods:
273     SequenceI sq = new Sequence("test", "ABCDEF");
274     sq.insertCharAt(0, 'z');
275     assertEquals("zABCDEF", sq.getSequenceAsString());
276     sq.insertCharAt(2, 2, 'x');
277     assertEquals("zAxxBCDEF", sq.getSequenceAsString());
278
279     // for static method see StringUtilsTest
280   }
281
282   /**
283    * Test the method that returns an array of aligned sequence positions where
284    * the array index is the data sequence position (both base 0).
285    */
286   @Test(groups = { "Functional" })
287   public void testGapMap()
288   {
289     SequenceI sq = new Sequence("test", "-A--B-CD-E--F-");
290     sq.createDatasetSequence();
291     assertEquals("[1, 4, 6, 7, 9, 12]", Arrays.toString(sq.gapMap()));
292   }
293
294   /**
295    * Test the method that gets sequence features, either from the sequence or
296    * its dataset.
297    */
298   @Test(groups = { "Functional" })
299   public void testGetSequenceFeatures()
300   {
301     SequenceI sq = new Sequence("test", "GATCAT");
302     sq.createDatasetSequence();
303
304     assertNull(sq.getSequenceFeatures());
305
306     /*
307      * SequenceFeature on sequence
308      */
309     SequenceFeature sf = new SequenceFeature();
310     sq.addSequenceFeature(sf);
311     SequenceFeature[] sfs = sq.getSequenceFeatures();
312     assertEquals(1, sfs.length);
313     assertSame(sf, sfs[0]);
314
315
316     /*
317      * SequenceFeature on sequence and dataset sequence; returns that on
318      * sequence
319      * 
320      * Note JAL-2046: spurious: we have no use case for this at the moment.
321      * This test also buggy - as sf2.equals(sf), no new feature is added
322      */
323     SequenceFeature sf2 = new SequenceFeature();
324     sq.getDatasetSequence().addSequenceFeature(sf2);
325     sfs = sq.getSequenceFeatures();
326     assertEquals(1, sfs.length);
327     assertSame(sf, sfs[0]);
328
329     /*
330      * SequenceFeature on dataset sequence only
331      * Note JAL-2046: spurious: we have no use case for setting a non-dataset sequence's feature array to null at the moment.
332      */
333     sq.setSequenceFeatures(null);
334     assertNull(sq.getDatasetSequence().getSequenceFeatures());
335
336     /*
337      * Corrupt case - no SequenceFeature, dataset's dataset is the original
338      * sequence. Test shows no infinite loop results.
339      */
340     sq.getDatasetSequence().setSequenceFeatures(null);
341     /**
342      * is there a usecase for this ? setDatasetSequence should throw an error if
343      * this actually occurs.
344      */
345     sq.getDatasetSequence().setDatasetSequence(sq); // loop!
346     assertNull(sq.getSequenceFeatures());
347   }
348
349   /**
350    * Test the method that returns an array, indexed by sequence position, whose
351    * entries are the residue positions at the sequence position (or to the right
352    * if a gap)
353    */
354   @Test(groups = { "Functional" })
355   public void testFindPositionMap()
356   {
357     /*
358      * Note: Javadoc for findPosition says it returns the residue position to
359      * the left of a gapped position; in fact it returns the position to the
360      * right. Also it returns a non-existent residue position for a gap beyond
361      * the sequence.
362      */
363     Sequence sq = new Sequence("TestSeq", "AB.C-D E.");
364     int[] map = sq.findPositionMap();
365     assertEquals(Arrays.toString(new int[] { 1, 2, 3, 3, 4, 4, 5, 5, 6 }),
366             Arrays.toString(map));
367   }
368
369   /**
370    * Test for getSubsequence
371    */
372   @Test(groups = { "Functional" })
373   public void testGetSubsequence()
374   {
375     SequenceI sq = new Sequence("TestSeq", "ABCDEFG");
376     sq.createDatasetSequence();
377
378     // positions are base 0, end position is exclusive
379     SequenceI subseq = sq.getSubSequence(2, 4);
380
381     assertEquals("CD", subseq.getSequenceAsString());
382     // start/end are base 1 positions
383     assertEquals(3, subseq.getStart());
384     assertEquals(4, subseq.getEnd());
385     // subsequence shares the full dataset sequence
386     assertSame(sq.getDatasetSequence(), subseq.getDatasetSequence());
387   }
388
389   /**
390    * Test for deriveSequence applied to a sequence with a dataset
391    */
392   @Test(groups = { "Functional" })
393   public void testDeriveSequence_existingDataset()
394   {
395     Sequence sq = new Sequence("Seq1", "CD");
396     sq.setDatasetSequence(new Sequence("Seq1", "ABCDEF"));
397     sq.getDatasetSequence().addSequenceFeature(
398             new SequenceFeature("", "", 1, 2, 0f, null));
399     sq.setStart(3);
400     sq.setEnd(4);
401
402     sq.setDescription("Test sequence description..");
403     sq.setVamsasId("TestVamsasId");
404     sq.setSourceDBRef(new DBRefEntry("PDB", "version0", "1TST"));
405
406     sq.addDBRef(new DBRefEntry("PDB", "version1", "1Tst"));
407     sq.addDBRef(new DBRefEntry("PDB", "version2", "2Tst"));
408     sq.addDBRef(new DBRefEntry("PDB", "version3", "3Tst"));
409     sq.addDBRef(new DBRefEntry("PDB", "version4", "4Tst"));
410
411     sq.addPDBId(new PDBEntry("1PDB", "A", Type.PDB, "filePath/test1"));
412     sq.addPDBId(new PDBEntry("1PDB", "B", Type.PDB, "filePath/test1"));
413     sq.addPDBId(new PDBEntry("2PDB", "A", Type.MMCIF, "filePath/test2"));
414     sq.addPDBId(new PDBEntry("2PDB", "B", Type.MMCIF, "filePath/test2"));
415
416     sq.getDatasetSequence().addDBRef(
417             new DBRefEntry("PDB", "version1", "1Tst"));
418     sq.getDatasetSequence().addDBRef(
419             new DBRefEntry("PDB", "version2", "2Tst"));
420     sq.getDatasetSequence().addDBRef(
421             new DBRefEntry("PDB", "version3", "3Tst"));
422     sq.getDatasetSequence().addDBRef(
423             new DBRefEntry("PDB", "version4", "4Tst"));
424
425     sq.getDatasetSequence().addPDBId(
426             new PDBEntry("1PDB", "A", Type.PDB, "filePath/test1"));
427     sq.getDatasetSequence().addPDBId(
428             new PDBEntry("1PDB", "B", Type.PDB, "filePath/test1"));
429     sq.getDatasetSequence().addPDBId(
430             new PDBEntry("2PDB", "A", Type.MMCIF, "filePath/test2"));
431     sq.getDatasetSequence().addPDBId(
432             new PDBEntry("2PDB", "B", Type.MMCIF, "filePath/test2"));
433
434     ArrayList<Annotation> annotsList = new ArrayList<Annotation>();
435     System.out.println(">>>>>> " + sq.getSequenceAsString().length());
436     annotsList.add(new Annotation("A", "A", 'X', 0.1f));
437     annotsList.add(new Annotation("A", "A", 'X', 0.1f));
438     Annotation[] annots = annotsList.toArray(new Annotation[0]);
439     sq.addAlignmentAnnotation(new AlignmentAnnotation("Test annot",
440             "Test annot description", annots));
441     sq.getDatasetSequence().addAlignmentAnnotation(
442             new AlignmentAnnotation("Test annot", "Test annot description",
443                     annots));
444     Assert.assertEquals(sq.getDescription(), "Test sequence description..");
445     Assert.assertEquals(sq.getDBRefs().length, 4);
446     Assert.assertEquals(sq.getAllPDBEntries().size(), 4);
447     Assert.assertNotNull(sq.getAnnotation());
448     Assert.assertEquals(sq.getAnnotation()[0].annotations.length, 2);
449     Assert.assertEquals(sq.getDatasetSequence().getDBRefs().length, 4);
450     Assert.assertEquals(sq.getDatasetSequence().getAllPDBEntries().size(),
451             4);
452     Assert.assertNotNull(sq.getDatasetSequence().getAnnotation());
453
454     Sequence derived = (Sequence) sq.deriveSequence();
455
456     Assert.assertEquals(derived.getDescription(),
457             "Test sequence description..");
458     Assert.assertEquals(derived.getDBRefs().length, 4);
459     Assert.assertEquals(derived.getAllPDBEntries().size(), 4);
460     Assert.assertNotNull(derived.getAnnotation());
461     Assert.assertEquals(derived.getAnnotation()[0].annotations.length, 2);
462     Assert.assertEquals(derived.getDatasetSequence().getDBRefs().length, 4);
463     Assert.assertEquals(derived.getDatasetSequence().getAllPDBEntries()
464             .size(), 4);
465     Assert.assertNotNull(derived.getDatasetSequence().getAnnotation());
466
467     assertEquals("CD", derived.getSequenceAsString());
468     assertSame(sq.getDatasetSequence(), derived.getDatasetSequence());
469
470     assertNull(sq.sequenceFeatures);
471     assertNull(derived.sequenceFeatures);
472     // derived sequence should access dataset sequence features
473     assertNotNull(sq.getSequenceFeatures());
474     assertArrayEquals(sq.getSequenceFeatures(),
475             derived.getSequenceFeatures());
476   }
477
478   /**
479    * Test for deriveSequence applied to an ungapped sequence with no dataset
480    */
481   @Test(groups = { "Functional" })
482   public void testDeriveSequence_noDatasetUngapped()
483   {
484     SequenceI sq = new Sequence("Seq1", "ABCDEF");
485     assertEquals(1, sq.getStart());
486     assertEquals(6, sq.getEnd());
487     SequenceI derived = sq.deriveSequence();
488     assertEquals("ABCDEF", derived.getSequenceAsString());
489     assertEquals("ABCDEF", derived.getDatasetSequence()
490             .getSequenceAsString());
491   }
492
493   /**
494    * Test for deriveSequence applied to a gapped sequence with no dataset
495    */
496   @Test(groups = { "Functional" })
497   public void testDeriveSequence_noDatasetGapped()
498   {
499     SequenceI sq = new Sequence("Seq1", "AB-C.D EF");
500     assertEquals(1, sq.getStart());
501     assertEquals(6, sq.getEnd());
502     assertNull(sq.getDatasetSequence());
503     SequenceI derived = sq.deriveSequence();
504     assertEquals("AB-C.D EF", derived.getSequenceAsString());
505     assertEquals("ABCDEF", derived.getDatasetSequence()
506             .getSequenceAsString());
507   }
508
509   @Test(groups = { "Functional" })
510   public void testCopyConstructor_noDataset()
511   {
512     SequenceI seq1 = new Sequence("Seq1", "AB-C.D EF");
513     seq1.setDescription("description");
514     seq1.addAlignmentAnnotation(new AlignmentAnnotation("label", "desc",
515             1.3d));
516     seq1.addSequenceFeature(new SequenceFeature("type", "desc", 22, 33,
517             12.4f, "group"));
518     seq1.addPDBId(new PDBEntry("1A70", "B", Type.PDB, "File"));
519     seq1.addDBRef(new DBRefEntry("EMBL", "1.2", "AZ12345"));
520     
521     SequenceI copy = new Sequence(seq1);
522
523     assertNull(copy.getDatasetSequence());
524
525     verifyCopiedSequence(seq1, copy);
526
527     // copy has a copy of the DBRefEntry
528     // this is murky - DBrefs are only copied for dataset sequences
529     // where the test for 'dataset sequence' is 'dataset is null'
530     // but that doesn't distinguish it from an aligned sequence
531     // which has not yet generated a dataset sequence
532     // NB getDBRef looks inside dataset sequence if not null
533     DBRefEntry[] dbrefs = copy.getDBRefs();
534     assertEquals(1, dbrefs.length);
535     assertFalse(dbrefs[0] == seq1.getDBRefs()[0]);
536     assertTrue(dbrefs[0].equals(seq1.getDBRefs()[0]));
537   }
538
539   @Test(groups = { "Functional" })
540   public void testCopyConstructor_withDataset()
541   {
542     SequenceI seq1 = new Sequence("Seq1", "AB-C.D EF");
543     seq1.createDatasetSequence();
544     seq1.setDescription("description");
545     seq1.addAlignmentAnnotation(new AlignmentAnnotation("label", "desc",
546             1.3d));
547     // JAL-2046 - what is the contract for using a derived sequence's
548     // addSequenceFeature ?
549     seq1.addSequenceFeature(new SequenceFeature("type", "desc", 22, 33,
550             12.4f, "group"));
551     seq1.addPDBId(new PDBEntry("1A70", "B", Type.PDB, "File"));
552     // here we add DBRef to the dataset sequence:
553     seq1.getDatasetSequence().addDBRef(
554             new DBRefEntry("EMBL", "1.2", "AZ12345"));
555
556     SequenceI copy = new Sequence(seq1);
557
558     assertNotNull(copy.getDatasetSequence());
559     assertSame(copy.getDatasetSequence(), seq1.getDatasetSequence());
560
561     verifyCopiedSequence(seq1, copy);
562
563     // getDBRef looks inside dataset sequence and this is shared,
564     // so holds the same dbref objects
565     DBRefEntry[] dbrefs = copy.getDBRefs();
566     assertEquals(1, dbrefs.length);
567     assertSame(dbrefs[0], seq1.getDBRefs()[0]);
568   }
569
570   /**
571    * Helper to make assertions about a copied sequence
572    * 
573    * @param seq1
574    * @param copy
575    */
576   protected void verifyCopiedSequence(SequenceI seq1, SequenceI copy)
577   {
578     // verify basic properties:
579     assertEquals(copy.getName(), seq1.getName());
580     assertEquals(copy.getDescription(), seq1.getDescription());
581     assertEquals(copy.getStart(), seq1.getStart());
582     assertEquals(copy.getEnd(), seq1.getEnd());
583     assertEquals(copy.getSequenceAsString(), seq1.getSequenceAsString());
584
585     // copy has a copy of the annotation:
586     AlignmentAnnotation[] anns = copy.getAnnotation();
587     assertEquals(1, anns.length);
588     assertFalse(anns[0] == seq1.getAnnotation()[0]);
589     assertEquals(anns[0].label, seq1.getAnnotation()[0].label);
590     assertEquals(anns[0].description, seq1.getAnnotation()[0].description);
591     assertEquals(anns[0].score, seq1.getAnnotation()[0].score);
592
593     // copy has a copy of the sequence feature:
594     SequenceFeature[] sfs = copy.getSequenceFeatures();
595     assertEquals(1, sfs.length);
596     if (seq1.getDatasetSequence()!=null && copy.getDatasetSequence()==seq1.getDatasetSequence()) {
597       assertTrue(sfs[0] == seq1.getSequenceFeatures()[0]);
598     } else {
599       assertFalse(sfs[0] == seq1.getSequenceFeatures()[0]);
600     }
601     assertTrue(sfs[0].equals(seq1.getSequenceFeatures()[0]));
602
603     // copy has a copy of the PDB entry
604     Vector<PDBEntry> pdbs = copy.getAllPDBEntries();
605     assertEquals(1, pdbs.size());
606     assertFalse(pdbs.get(0) == seq1.getAllPDBEntries().get(0));
607     assertTrue(pdbs.get(0).equals(seq1.getAllPDBEntries().get(0)));
608   }
609
610   @Test(groups = "Functional")
611   public void testGetCharAt()
612   {
613     SequenceI sq = new Sequence("", "abcde");
614     assertEquals('a', sq.getCharAt(0));
615     assertEquals('e', sq.getCharAt(4));
616     assertEquals(' ', sq.getCharAt(5));
617     assertEquals(' ', sq.getCharAt(-1));
618   }
619 }