Merge branch 'bug/JAL-2541cutWithFeatures' into features/JAL-2446NCList
[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.assertNotSame;
27 import static org.testng.AssertJUnit.assertNull;
28 import static org.testng.AssertJUnit.assertSame;
29 import static org.testng.AssertJUnit.assertTrue;
30 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
31
32 import jalview.datamodel.PDBEntry.Type;
33 import jalview.gui.JvOptionPane;
34 import jalview.util.MapList;
35
36 import java.io.File;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.List;
40 import java.util.Vector;
41
42 import junit.extensions.PA;
43
44 import junit.extensions.PA;
45
46 import org.testng.Assert;
47 import org.testng.annotations.BeforeClass;
48 import org.testng.annotations.BeforeMethod;
49 import org.testng.annotations.Test;
50
51 public class SequenceTest
52 {
53
54   @BeforeClass(alwaysRun = true)
55   public void setUpJvOptionPane()
56   {
57     JvOptionPane.setInteractiveMode(false);
58     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
59   }
60
61   Sequence seq;
62
63   @BeforeMethod(alwaysRun = true)
64   public void setUp()
65   {
66     seq = new Sequence("FER1", "AKPNGVL");
67   }
68
69   @Test(groups = { "Functional" })
70   public void testInsertGapsAndGapmaps()
71   {
72     SequenceI aseq = seq.deriveSequence();
73     aseq.insertCharAt(2, 3, '-');
74     aseq.insertCharAt(6, 3, '-');
75     assertEquals("Gap insertions not correct", "AK---P---NGVL",
76             aseq.getSequenceAsString());
77     List<int[]> gapInt = aseq.getInsertions();
78     assertEquals("Gap interval 1 start wrong", 2, gapInt.get(0)[0]);
79     assertEquals("Gap interval 1 end wrong", 4, gapInt.get(0)[1]);
80     assertEquals("Gap interval 2 start wrong", 6, gapInt.get(1)[0]);
81     assertEquals("Gap interval 2 end wrong", 8, gapInt.get(1)[1]);
82   }
83
84   @Test(groups = ("Functional"))
85   public void testIsProtein()
86   {
87     // test Protein
88     assertTrue(new Sequence("prot", "ASDFASDFASDF").isProtein());
89     // test DNA
90     assertFalse(new Sequence("prot", "ACGTACGTACGT").isProtein());
91     // test RNA
92     SequenceI sq = new Sequence("prot", "ACGUACGUACGU");
93     assertFalse(sq.isProtein());
94     // change sequence, should trigger an update of cached result
95     sq.setSequence("ASDFASDFADSF");
96     assertTrue(sq.isProtein());
97     /*
98      * in situ change of sequence doesn't change hashcode :-O
99      * (sequence should not expose internal implementation)
100      */
101     for (int i = 0; i < sq.getSequence().length; i++)
102     {
103       sq.getSequence()[i] = "acgtu".charAt(i % 5);
104     }
105     assertTrue(sq.isProtein()); // but it isn't
106   }
107
108   @Test(groups = { "Functional" })
109   public void testGetAnnotation()
110   {
111     // initial state returns null not an empty array
112     assertNull(seq.getAnnotation());
113     AlignmentAnnotation ann = addAnnotation("label1", "desc1", "calcId1",
114             1f);
115     AlignmentAnnotation[] anns = seq.getAnnotation();
116     assertEquals(1, anns.length);
117     assertSame(ann, anns[0]);
118
119     // removing all annotations reverts array to null
120     seq.removeAlignmentAnnotation(ann);
121     assertNull(seq.getAnnotation());
122   }
123
124   @Test(groups = { "Functional" })
125   public void testGetAnnotation_forLabel()
126   {
127     AlignmentAnnotation ann1 = addAnnotation("label1", "desc1", "calcId1",
128             1f);
129     addAnnotation("label2", "desc2", "calcId2", 1f);
130     AlignmentAnnotation ann3 = addAnnotation("label1", "desc3", "calcId3",
131             1f);
132     AlignmentAnnotation[] anns = seq.getAnnotation("label1");
133     assertEquals(2, anns.length);
134     assertSame(ann1, anns[0]);
135     assertSame(ann3, anns[1]);
136   }
137
138   private AlignmentAnnotation addAnnotation(String label,
139           String description, String calcId, float value)
140   {
141     final AlignmentAnnotation annotation = new AlignmentAnnotation(label,
142             description, value);
143     annotation.setCalcId(calcId);
144     seq.addAlignmentAnnotation(annotation);
145     return annotation;
146   }
147
148   @Test(groups = { "Functional" })
149   public void testGetAlignmentAnnotations_forCalcIdAndLabel()
150   {
151     addAnnotation("label1", "desc1", "calcId1", 1f);
152     AlignmentAnnotation ann2 = addAnnotation("label2", "desc2", "calcId2",
153             1f);
154     addAnnotation("label2", "desc3", "calcId3", 1f);
155     AlignmentAnnotation ann4 = addAnnotation("label2", "desc3", "calcId2",
156             1f);
157     addAnnotation("label5", "desc3", null, 1f);
158     addAnnotation(null, "desc3", "calcId3", 1f);
159
160     List<AlignmentAnnotation> anns = seq.getAlignmentAnnotations("calcId2",
161             "label2");
162     assertEquals(2, anns.size());
163     assertSame(ann2, anns.get(0));
164     assertSame(ann4, anns.get(1));
165
166     assertTrue(seq.getAlignmentAnnotations("calcId2", "label3").isEmpty());
167     assertTrue(seq.getAlignmentAnnotations("calcId3", "label5").isEmpty());
168     assertTrue(seq.getAlignmentAnnotations("calcId2", null).isEmpty());
169     assertTrue(seq.getAlignmentAnnotations(null, "label3").isEmpty());
170     assertTrue(seq.getAlignmentAnnotations(null, null).isEmpty());
171   }
172
173   /**
174    * Tests for addAlignmentAnnotation. Note this method has the side-effect of
175    * setting the sequenceRef on the annotation. Adding the same annotation twice
176    * should be ignored.
177    */
178   @Test(groups = { "Functional" })
179   public void testAddAlignmentAnnotation()
180   {
181     assertNull(seq.getAnnotation());
182     final AlignmentAnnotation annotation = new AlignmentAnnotation("a",
183             "b", 2d);
184     assertNull(annotation.sequenceRef);
185     seq.addAlignmentAnnotation(annotation);
186     assertSame(seq, annotation.sequenceRef);
187     AlignmentAnnotation[] anns = seq.getAnnotation();
188     assertEquals(1, anns.length);
189     assertSame(annotation, anns[0]);
190
191     // re-adding does nothing
192     seq.addAlignmentAnnotation(annotation);
193     anns = seq.getAnnotation();
194     assertEquals(1, anns.length);
195     assertSame(annotation, anns[0]);
196
197     // an identical but different annotation can be added
198     final AlignmentAnnotation annotation2 = new AlignmentAnnotation("a",
199             "b", 2d);
200     seq.addAlignmentAnnotation(annotation2);
201     anns = seq.getAnnotation();
202     assertEquals(2, anns.length);
203     assertSame(annotation, anns[0]);
204     assertSame(annotation2, anns[1]);
205   }
206
207   @Test(groups = { "Functional" })
208   public void testGetStartGetEnd()
209   {
210     SequenceI sq = new Sequence("test", "ABCDEF");
211     assertEquals(1, sq.getStart());
212     assertEquals(6, sq.getEnd());
213
214     sq = new Sequence("test", "--AB-C-DEF--");
215     assertEquals(1, sq.getStart());
216     assertEquals(6, sq.getEnd());
217
218     sq = new Sequence("test", "----");
219     assertEquals(1, sq.getStart());
220     assertEquals(0, sq.getEnd()); // ??
221   }
222
223   /**
224    * Tests for the method that returns an alignment column position (base 1) for
225    * a given sequence position (base 1).
226    */
227   @Test(groups = { "Functional" })
228   public void testFindIndex()
229   {
230     SequenceI sq = new Sequence("test", "ABCDEF");
231     assertEquals(0, sq.findIndex(0));
232     assertEquals(1, sq.findIndex(1));
233     assertEquals(5, sq.findIndex(5));
234     assertEquals(6, sq.findIndex(6));
235     assertEquals(6, sq.findIndex(9));
236
237     sq = new Sequence("test", "-A--B-C-D-E-F--");
238     assertEquals(2, sq.findIndex(1));
239     assertEquals(5, sq.findIndex(2));
240     assertEquals(7, sq.findIndex(3));
241
242     // before start returns 0
243     assertEquals(0, sq.findIndex(0));
244     assertEquals(0, sq.findIndex(-1));
245
246     // beyond end returns last residue column
247     assertEquals(13, sq.findIndex(99));
248
249   }
250
251   /**
252    * Tests for the method that returns a dataset sequence position (base 1) for
253    * an aligned column position (base 0).
254    */
255   @Test(groups = { "Functional" })
256   public void testFindPosition()
257   {
258     SequenceI sq = new Sequence("test", "ABCDEF");
259     assertEquals(1, sq.findPosition(0));
260     assertEquals(6, sq.findPosition(5));
261     // assertEquals(-1, seq.findPosition(6)); // fails
262
263     sq = new Sequence("test", "AB-C-D--");
264     assertEquals(1, sq.findPosition(0));
265     assertEquals(2, sq.findPosition(1));
266     // gap position 'finds' residue to the right (not the left as per javadoc)
267     assertEquals(3, sq.findPosition(2));
268     assertEquals(3, sq.findPosition(3));
269     assertEquals(4, sq.findPosition(4));
270     assertEquals(4, sq.findPosition(5));
271     // returns 1 more than sequence length if off the end ?!?
272     assertEquals(5, sq.findPosition(6));
273     assertEquals(5, sq.findPosition(7));
274
275     sq = new Sequence("test", "--AB-C-DEF--");
276     assertEquals(1, sq.findPosition(0));
277     assertEquals(1, sq.findPosition(1));
278     assertEquals(1, sq.findPosition(2));
279     assertEquals(2, sq.findPosition(3));
280     assertEquals(3, sq.findPosition(4));
281     assertEquals(3, sq.findPosition(5));
282     assertEquals(4, sq.findPosition(6));
283     assertEquals(4, sq.findPosition(7));
284     assertEquals(5, sq.findPosition(8));
285     assertEquals(6, sq.findPosition(9));
286     assertEquals(7, sq.findPosition(10));
287     assertEquals(7, sq.findPosition(11));
288   }
289
290   @Test(groups = { "Functional" })
291   public void testDeleteChars()
292   {
293     /*
294      * internal delete
295      */
296     SequenceI sq = new Sequence("test", "ABCDEF");
297     assertNull(PA.getValue(sq, "datasetSequence"));
298     assertEquals(1, sq.getStart());
299     assertEquals(6, sq.getEnd());
300     sq.deleteChars(2, 3);
301     assertEquals("ABDEF", sq.getSequenceAsString());
302     assertEquals(1, sq.getStart());
303     assertEquals(5, sq.getEnd());
304     assertNull(PA.getValue(sq, "datasetSequence"));
305
306     /*
307      * delete at start
308      */
309     sq = new Sequence("test", "ABCDEF");
310     sq.deleteChars(0, 2);
311     assertEquals("CDEF", sq.getSequenceAsString());
312     assertEquals(3, sq.getStart());
313     assertEquals(6, sq.getEnd());
314     assertNull(PA.getValue(sq, "datasetSequence"));
315
316     /*
317      * delete at end
318      */
319     sq = new Sequence("test", "ABCDEF");
320     sq.deleteChars(4, 6);
321     assertEquals("ABCD", sq.getSequenceAsString());
322     assertEquals(1, sq.getStart());
323     assertEquals(4, sq.getEnd());
324     assertNull(PA.getValue(sq, "datasetSequence"));
325   }
326
327   @Test(groups = { "Functional" })
328   public void testDeleteChars_withDbRefsAndFeatures()
329   {
330     /*
331      * internal delete - new dataset sequence created
332      * gets a copy of any dbrefs
333      */
334     SequenceI sq = new Sequence("test", "ABCDEF");
335     sq.createDatasetSequence();
336     DBRefEntry dbr1 = new DBRefEntry("Uniprot", "0", "a123");
337     sq.addDBRef(dbr1);
338     Object ds = PA.getValue(sq, "datasetSequence");
339     assertNotNull(ds);
340     assertEquals(1, sq.getStart());
341     assertEquals(6, sq.getEnd());
342     sq.deleteChars(2, 3);
343     assertEquals("ABDEF", sq.getSequenceAsString());
344     assertEquals(1, sq.getStart());
345     assertEquals(5, sq.getEnd());
346     Object newDs = PA.getValue(sq, "datasetSequence");
347     assertNotNull(newDs);
348     assertNotSame(ds, newDs);
349     assertNotNull(sq.getDBRefs());
350     assertEquals(1, sq.getDBRefs().length);
351     assertNotSame(dbr1, sq.getDBRefs()[0]);
352     assertEquals(dbr1, sq.getDBRefs()[0]);
353
354     /*
355      * internal delete with sequence features
356      * (failure case for JAL-2541)
357      */
358     sq = new Sequence("test", "ABCDEF");
359     sq.createDatasetSequence();
360     SequenceFeature sf1 = new SequenceFeature("Cath", "desc", 2, 4, 2f,
361             "CathGroup");
362     sq.addSequenceFeature(sf1);
363     ds = PA.getValue(sq, "datasetSequence");
364     assertNotNull(ds);
365     assertEquals(1, sq.getStart());
366     assertEquals(6, sq.getEnd());
367     sq.deleteChars(2, 4);
368     assertEquals("ABEF", sq.getSequenceAsString());
369     assertEquals(1, sq.getStart());
370     assertEquals(4, sq.getEnd());
371     newDs = PA.getValue(sq, "datasetSequence");
372     assertNotNull(newDs);
373     assertNotSame(ds, newDs);
374     SequenceFeature[] sfs = sq.getSequenceFeatures();
375     assertNotNull(sfs);
376     assertEquals(1, sfs.length);
377     assertNotSame(sf1, sfs[0]);
378     assertEquals(sf1, sfs[0]);
379
380     /*
381      * delete at start - no new dataset sequence created
382      * any sequence features remain as before
383      */
384     sq = new Sequence("test", "ABCDEF");
385     sq.createDatasetSequence();
386     ds = PA.getValue(sq, "datasetSequence");
387     sf1 = new SequenceFeature("Cath", "desc", 2, 4, 2f, "CathGroup");
388     sq.addSequenceFeature(sf1);
389     sq.deleteChars(0, 2);
390     assertEquals("CDEF", sq.getSequenceAsString());
391     assertEquals(3, sq.getStart());
392     assertEquals(6, sq.getEnd());
393     assertSame(ds, PA.getValue(sq, "datasetSequence"));
394     sfs = sq.getSequenceFeatures();
395     assertNotNull(sfs);
396     assertEquals(1, sfs.length);
397     assertSame(sf1, sfs[0]);
398
399     /*
400      * delete at end - no new dataset sequence created
401      * any dbrefs remain as before
402      */
403     sq = new Sequence("test", "ABCDEF");
404     sq.createDatasetSequence();
405     ds = PA.getValue(sq, "datasetSequence");
406     dbr1 = new DBRefEntry("Uniprot", "0", "a123");
407     sq.addDBRef(dbr1);
408     sq.deleteChars(4, 6);
409     assertEquals("ABCD", sq.getSequenceAsString());
410     assertEquals(1, sq.getStart());
411     assertEquals(4, sq.getEnd());
412     assertSame(ds, PA.getValue(sq, "datasetSequence"));
413     assertNotNull(sq.getDBRefs());
414     assertEquals(1, sq.getDBRefs().length);
415     assertSame(dbr1, sq.getDBRefs()[0]);
416   }
417
418   @Test(groups = { "Functional" })
419   public void testInsertCharAt()
420   {
421     // non-static methods:
422     SequenceI sq = new Sequence("test", "ABCDEF");
423     sq.insertCharAt(0, 'z');
424     assertEquals("zABCDEF", sq.getSequenceAsString());
425     sq.insertCharAt(2, 2, 'x');
426     assertEquals("zAxxBCDEF", sq.getSequenceAsString());
427
428     // for static method see StringUtilsTest
429   }
430
431   /**
432    * Test the method that returns an array of aligned sequence positions where
433    * the array index is the data sequence position (both base 0).
434    */
435   @Test(groups = { "Functional" })
436   public void testGapMap()
437   {
438     SequenceI sq = new Sequence("test", "-A--B-CD-E--F-");
439     sq.createDatasetSequence();
440     assertEquals("[1, 4, 6, 7, 9, 12]", Arrays.toString(sq.gapMap()));
441   }
442
443   /**
444    * Test the method that gets sequence features, either from the sequence or
445    * its dataset.
446    */
447   @Test(groups = { "Functional" })
448   public void testGetSequenceFeatures()
449   {
450     SequenceI sq = new Sequence("test", "GATCAT");
451     sq.createDatasetSequence();
452
453     assertNull(sq.getSequenceFeatures());
454
455     /*
456      * SequenceFeature on sequence
457      */
458     SequenceFeature sf = new SequenceFeature("Cath", "desc", 2, 4, 2f, null);
459     sq.addSequenceFeature(sf);
460     SequenceFeature[] sfs = sq.getSequenceFeatures();
461     assertEquals(1, sfs.length);
462     assertSame(sf, sfs[0]);
463
464     /*
465      * SequenceFeature on sequence and dataset sequence; returns that on
466      * sequence
467      * 
468      * Note JAL-2046: spurious: we have no use case for this at the moment.
469      * This test also buggy - as sf2.equals(sf), no new feature is added
470      */
471     SequenceFeature sf2 = new SequenceFeature();
472     sq.getDatasetSequence().addSequenceFeature(sf2);
473     sfs = sq.getSequenceFeatures();
474     assertEquals(1, sfs.length);
475     assertSame(sf, sfs[0]);
476
477     /*
478      * SequenceFeature on dataset sequence only
479      * Note JAL-2046: spurious: we have no use case for setting a non-dataset sequence's feature array to null at the moment.
480      */
481     sq.setSequenceFeatures(null);
482     assertNull(sq.getDatasetSequence().getSequenceFeatures());
483
484     /*
485      * Corrupt case - no SequenceFeature, dataset's dataset is the original
486      * sequence. Test shows no infinite loop results.
487      */
488     sq.getDatasetSequence().setSequenceFeatures(null);
489     /**
490      * is there a usecase for this ? setDatasetSequence should throw an error if
491      * this actually occurs.
492      */
493     try
494     {
495       sq.getDatasetSequence().setDatasetSequence(sq); // loop!
496       Assert.fail("Expected Error to be raised when calling setDatasetSequence with self reference");
497     } catch (IllegalArgumentException e)
498     {
499       // TODO Jalview error/exception class for raising implementation errors
500       assertTrue(e.getMessage().toLowerCase()
501               .contains("implementation error"));
502     }
503     assertNull(sq.getSequenceFeatures());
504   }
505
506   /**
507    * Test the method that returns an array, indexed by sequence position, whose
508    * entries are the residue positions at the sequence position (or to the right
509    * if a gap)
510    */
511   @Test(groups = { "Functional" })
512   public void testFindPositionMap()
513   {
514     /*
515      * Note: Javadoc for findPosition says it returns the residue position to
516      * the left of a gapped position; in fact it returns the position to the
517      * right. Also it returns a non-existent residue position for a gap beyond
518      * the sequence.
519      */
520     Sequence sq = new Sequence("TestSeq", "AB.C-D E.");
521     int[] map = sq.findPositionMap();
522     assertEquals(Arrays.toString(new int[] { 1, 2, 3, 3, 4, 4, 5, 5, 6 }),
523             Arrays.toString(map));
524   }
525
526   /**
527    * Test for getSubsequence
528    */
529   @Test(groups = { "Functional" })
530   public void testGetSubsequence()
531   {
532     SequenceI sq = new Sequence("TestSeq", "ABCDEFG");
533     sq.createDatasetSequence();
534
535     // positions are base 0, end position is exclusive
536     SequenceI subseq = sq.getSubSequence(2, 4);
537
538     assertEquals("CD", subseq.getSequenceAsString());
539     // start/end are base 1 positions
540     assertEquals(3, subseq.getStart());
541     assertEquals(4, subseq.getEnd());
542     // subsequence shares the full dataset sequence
543     assertSame(sq.getDatasetSequence(), subseq.getDatasetSequence());
544   }
545
546   /**
547    * test createDatasetSequence behaves to doc
548    */
549   @Test(groups = { "Functional" })
550   public void testCreateDatasetSequence()
551   {
552     SequenceI sq = new Sequence("my", "ASDASD");
553     sq.addSequenceFeature(new SequenceFeature("type", "desc", 1, 10, 1f,
554             "group"));
555     sq.addDBRef(new DBRefEntry("source", "version", "accession"));
556     assertNull(sq.getDatasetSequence());
557     assertNotNull(PA.getValue(sq, "sequenceFeatures")); // to be removed!
558     assertNotNull(PA.getValue(sq, "sequenceFeatureStore"));
559     assertNotNull(PA.getValue(sq, "dbrefs"));
560
561     SequenceI rds = sq.createDatasetSequence();
562     assertNotNull(rds);
563     assertNull(rds.getDatasetSequence());
564     assertSame(sq.getDatasetSequence(), rds);
565
566     // sequence features and dbrefs transferred to dataset sequence
567     assertNull(PA.getValue(sq, "sequenceFeatures"));
568     assertNull(PA.getValue(sq, "sequenceFeatureStore"));
569     assertNull(PA.getValue(sq, "dbrefs"));
570     assertNotNull(PA.getValue(rds, "sequenceFeatures"));
571     assertNotNull(PA.getValue(rds, "sequenceFeatureStore"));
572     assertNotNull(PA.getValue(rds, "dbrefs"));
573   }
574
575   /**
576    * Test for deriveSequence applied to a sequence with a dataset
577    */
578   @Test(groups = { "Functional" })
579   public void testDeriveSequence_existingDataset()
580   {
581     Sequence sq = new Sequence("Seq1", "CD");
582     sq.setDatasetSequence(new Sequence("Seq1", "ABCDEF"));
583     sq.getDatasetSequence().addSequenceFeature(
584             new SequenceFeature("", "", 1, 2, 0f, null));
585     sq.setStart(3);
586     sq.setEnd(4);
587
588     sq.setDescription("Test sequence description..");
589     sq.setVamsasId("TestVamsasId");
590     sq.addDBRef(new DBRefEntry("PDB", "version0", "1TST"));
591
592     sq.addDBRef(new DBRefEntry("PDB", "version1", "1PDB"));
593     sq.addDBRef(new DBRefEntry("PDB", "version2", "2PDB"));
594     sq.addDBRef(new DBRefEntry("PDB", "version3", "3PDB"));
595     sq.addDBRef(new DBRefEntry("PDB", "version4", "4PDB"));
596
597     sq.addPDBId(new PDBEntry("1PDB", "A", Type.PDB, "filePath/test1"));
598     sq.addPDBId(new PDBEntry("1PDB", "B", Type.PDB, "filePath/test1"));
599     sq.addPDBId(new PDBEntry("2PDB", "A", Type.MMCIF, "filePath/test2"));
600     sq.addPDBId(new PDBEntry("2PDB", "B", Type.MMCIF, "filePath/test2"));
601
602     // these are the same as ones already added
603     DBRefEntry pdb1pdb = new DBRefEntry("PDB", "version1", "1PDB");
604     DBRefEntry pdb2pdb = new DBRefEntry("PDB", "version2", "2PDB");
605
606     List<DBRefEntry> primRefs = Arrays.asList(new DBRefEntry[] { pdb1pdb,
607         pdb2pdb });
608
609     sq.getDatasetSequence().addDBRef(pdb1pdb); // should do nothing
610     sq.getDatasetSequence().addDBRef(pdb2pdb); // should do nothing
611     sq.getDatasetSequence().addDBRef(
612             new DBRefEntry("PDB", "version3", "3PDB")); // should do nothing
613     sq.getDatasetSequence().addDBRef(
614             new DBRefEntry("PDB", "version4", "4PDB")); // should do nothing
615
616     PDBEntry pdbe1a = new PDBEntry("1PDB", "A", Type.PDB, "filePath/test1");
617     PDBEntry pdbe1b = new PDBEntry("1PDB", "B", Type.PDB, "filePath/test1");
618     PDBEntry pdbe2a = new PDBEntry("2PDB", "A", Type.MMCIF,
619             "filePath/test2");
620     PDBEntry pdbe2b = new PDBEntry("2PDB", "B", Type.MMCIF,
621             "filePath/test2");
622     sq.getDatasetSequence().addPDBId(pdbe1a);
623     sq.getDatasetSequence().addPDBId(pdbe1b);
624     sq.getDatasetSequence().addPDBId(pdbe2a);
625     sq.getDatasetSequence().addPDBId(pdbe2b);
626
627     /*
628      * test we added pdb entries to the dataset sequence
629      */
630     Assert.assertEquals(sq.getDatasetSequence().getAllPDBEntries(), Arrays
631             .asList(new PDBEntry[] { pdbe1a, pdbe1b, pdbe2a, pdbe2b }),
632             "PDB Entries were not found on dataset sequence.");
633
634     /*
635      * we should recover a pdb entry that is on the dataset sequence via PDBEntry
636      */
637     Assert.assertEquals(pdbe1a,
638             sq.getDatasetSequence().getPDBEntry("1PDB"),
639             "PDB Entry '1PDB' not found on dataset sequence via getPDBEntry.");
640     ArrayList<Annotation> annotsList = new ArrayList<Annotation>();
641     System.out.println(">>>>>> " + sq.getSequenceAsString().length());
642     annotsList.add(new Annotation("A", "A", 'X', 0.1f));
643     annotsList.add(new Annotation("A", "A", 'X', 0.1f));
644     Annotation[] annots = annotsList.toArray(new Annotation[0]);
645     sq.addAlignmentAnnotation(new AlignmentAnnotation("Test annot",
646             "Test annot description", annots));
647     sq.getDatasetSequence().addAlignmentAnnotation(
648             new AlignmentAnnotation("Test annot", "Test annot description",
649                     annots));
650     Assert.assertEquals(sq.getDescription(), "Test sequence description..");
651     Assert.assertEquals(sq.getDBRefs().length, 5); // DBRefs are on dataset
652                                                    // sequence
653     Assert.assertEquals(sq.getAllPDBEntries().size(), 4);
654     Assert.assertNotNull(sq.getAnnotation());
655     Assert.assertEquals(sq.getAnnotation()[0].annotations.length, 2);
656     Assert.assertEquals(sq.getDatasetSequence().getDBRefs().length, 5); // same
657                                                                         // as
658                                                                         // sq.getDBRefs()
659     Assert.assertEquals(sq.getDatasetSequence().getAllPDBEntries().size(),
660             4);
661     Assert.assertNotNull(sq.getDatasetSequence().getAnnotation());
662
663     Sequence derived = (Sequence) sq.deriveSequence();
664
665     Assert.assertEquals(derived.getDescription(),
666             "Test sequence description..");
667     Assert.assertEquals(derived.getDBRefs().length, 5); // come from dataset
668     Assert.assertEquals(derived.getAllPDBEntries().size(), 4);
669     Assert.assertNotNull(derived.getAnnotation());
670     Assert.assertEquals(derived.getAnnotation()[0].annotations.length, 2);
671     Assert.assertEquals(derived.getDatasetSequence().getDBRefs().length, 5);
672     Assert.assertEquals(derived.getDatasetSequence().getAllPDBEntries()
673             .size(), 4);
674     Assert.assertNotNull(derived.getDatasetSequence().getAnnotation());
675
676     assertEquals("CD", derived.getSequenceAsString());
677     assertSame(sq.getDatasetSequence(), derived.getDatasetSequence());
678
679     assertNull(sq.sequenceFeatures);
680     assertNull(derived.sequenceFeatures);
681     // derived sequence should access dataset sequence features
682     assertNotNull(sq.getSequenceFeatures());
683     assertArrayEquals(sq.getSequenceFeatures(),
684             derived.getSequenceFeatures());
685
686     /*
687      *  verify we have primary db refs *just* for PDB IDs with associated
688      *  PDBEntry objects
689      */
690
691     assertEquals(primRefs, sq.getPrimaryDBRefs());
692     assertEquals(primRefs, sq.getDatasetSequence().getPrimaryDBRefs());
693
694     assertEquals(sq.getPrimaryDBRefs(), derived.getPrimaryDBRefs());
695
696   }
697
698   /**
699    * Test for deriveSequence applied to an ungapped sequence with no dataset
700    */
701   @Test(groups = { "Functional" })
702   public void testDeriveSequence_noDatasetUngapped()
703   {
704     SequenceI sq = new Sequence("Seq1", "ABCDEF");
705     assertEquals(1, sq.getStart());
706     assertEquals(6, sq.getEnd());
707     SequenceI derived = sq.deriveSequence();
708     assertEquals("ABCDEF", derived.getSequenceAsString());
709     assertEquals("ABCDEF", derived.getDatasetSequence()
710             .getSequenceAsString());
711   }
712
713   /**
714    * Test for deriveSequence applied to a gapped sequence with no dataset
715    */
716   @Test(groups = { "Functional" })
717   public void testDeriveSequence_noDatasetGapped()
718   {
719     SequenceI sq = new Sequence("Seq1", "AB-C.D EF");
720     assertEquals(1, sq.getStart());
721     assertEquals(6, sq.getEnd());
722     assertNull(sq.getDatasetSequence());
723     SequenceI derived = sq.deriveSequence();
724     assertEquals("AB-C.D EF", derived.getSequenceAsString());
725     assertEquals("ABCDEF", derived.getDatasetSequence()
726             .getSequenceAsString());
727   }
728
729   @Test(groups = { "Functional" })
730   public void testCopyConstructor_noDataset()
731   {
732     SequenceI seq1 = new Sequence("Seq1", "AB-C.D EF");
733     seq1.setDescription("description");
734     seq1.addAlignmentAnnotation(new AlignmentAnnotation("label", "desc",
735             1.3d));
736     seq1.addSequenceFeature(new SequenceFeature("type", "desc", 22, 33,
737             12.4f, "group"));
738     seq1.addPDBId(new PDBEntry("1A70", "B", Type.PDB, "File"));
739     seq1.addDBRef(new DBRefEntry("EMBL", "1.2", "AZ12345"));
740
741     SequenceI copy = new Sequence(seq1);
742
743     assertNull(copy.getDatasetSequence());
744
745     verifyCopiedSequence(seq1, copy);
746
747     // copy has a copy of the DBRefEntry
748     // this is murky - DBrefs are only copied for dataset sequences
749     // where the test for 'dataset sequence' is 'dataset is null'
750     // but that doesn't distinguish it from an aligned sequence
751     // which has not yet generated a dataset sequence
752     // NB getDBRef looks inside dataset sequence if not null
753     DBRefEntry[] dbrefs = copy.getDBRefs();
754     assertEquals(1, dbrefs.length);
755     assertFalse(dbrefs[0] == seq1.getDBRefs()[0]);
756     assertTrue(dbrefs[0].equals(seq1.getDBRefs()[0]));
757   }
758
759   @Test(groups = { "Functional" })
760   public void testCopyConstructor_withDataset()
761   {
762     SequenceI seq1 = new Sequence("Seq1", "AB-C.D EF");
763     seq1.createDatasetSequence();
764     seq1.setDescription("description");
765     seq1.addAlignmentAnnotation(new AlignmentAnnotation("label", "desc",
766             1.3d));
767     // JAL-2046 - what is the contract for using a derived sequence's
768     // addSequenceFeature ?
769     seq1.addSequenceFeature(new SequenceFeature("type", "desc", 22, 33,
770             12.4f, "group"));
771     seq1.addPDBId(new PDBEntry("1A70", "B", Type.PDB, "File"));
772     // here we add DBRef to the dataset sequence:
773     seq1.getDatasetSequence().addDBRef(
774             new DBRefEntry("EMBL", "1.2", "AZ12345"));
775
776     SequenceI copy = new Sequence(seq1);
777
778     assertNotNull(copy.getDatasetSequence());
779     assertSame(copy.getDatasetSequence(), seq1.getDatasetSequence());
780
781     verifyCopiedSequence(seq1, copy);
782
783     // getDBRef looks inside dataset sequence and this is shared,
784     // so holds the same dbref objects
785     DBRefEntry[] dbrefs = copy.getDBRefs();
786     assertEquals(1, dbrefs.length);
787     assertSame(dbrefs[0], seq1.getDBRefs()[0]);
788   }
789
790   /**
791    * Helper to make assertions about a copied sequence
792    * 
793    * @param seq1
794    * @param copy
795    */
796   protected void verifyCopiedSequence(SequenceI seq1, SequenceI copy)
797   {
798     // verify basic properties:
799     assertEquals(copy.getName(), seq1.getName());
800     assertEquals(copy.getDescription(), seq1.getDescription());
801     assertEquals(copy.getStart(), seq1.getStart());
802     assertEquals(copy.getEnd(), seq1.getEnd());
803     assertEquals(copy.getSequenceAsString(), seq1.getSequenceAsString());
804
805     // copy has a copy of the annotation:
806     AlignmentAnnotation[] anns = copy.getAnnotation();
807     assertEquals(1, anns.length);
808     assertFalse(anns[0] == seq1.getAnnotation()[0]);
809     assertEquals(anns[0].label, seq1.getAnnotation()[0].label);
810     assertEquals(anns[0].description, seq1.getAnnotation()[0].description);
811     assertEquals(anns[0].score, seq1.getAnnotation()[0].score);
812
813     // copy has a copy of the sequence feature:
814     SequenceFeature[] sfs = copy.getSequenceFeatures();
815     assertEquals(1, sfs.length);
816     if (seq1.getDatasetSequence() != null
817             && copy.getDatasetSequence() == seq1.getDatasetSequence())
818     {
819       assertTrue(sfs[0] == seq1.getSequenceFeatures()[0]);
820     }
821     else
822     {
823       assertFalse(sfs[0] == seq1.getSequenceFeatures()[0]);
824     }
825     assertTrue(sfs[0].equals(seq1.getSequenceFeatures()[0]));
826
827     // copy has a copy of the PDB entry
828     Vector<PDBEntry> pdbs = copy.getAllPDBEntries();
829     assertEquals(1, pdbs.size());
830     assertFalse(pdbs.get(0) == seq1.getAllPDBEntries().get(0));
831     assertTrue(pdbs.get(0).equals(seq1.getAllPDBEntries().get(0)));
832   }
833
834   @Test(groups = "Functional")
835   public void testGetCharAt()
836   {
837     SequenceI sq = new Sequence("", "abcde");
838     assertEquals('a', sq.getCharAt(0));
839     assertEquals('e', sq.getCharAt(4));
840     assertEquals(' ', sq.getCharAt(5));
841     assertEquals(' ', sq.getCharAt(-1));
842   }
843
844   @Test(groups = { "Functional" })
845   public void testAddSequenceFeatures()
846   {
847     SequenceI sq = new Sequence("", "abcde");
848     // type may not be null
849     assertFalse(sq.addSequenceFeature(new SequenceFeature(null, "desc", 4,
850             8, 0f, null)));
851     assertTrue(sq.addSequenceFeature(new SequenceFeature("Cath", "desc", 4,
852             8, 0f, null)));
853     // can't add a duplicate feature
854     assertFalse(sq.addSequenceFeature(new SequenceFeature("Cath", "desc",
855             4, 8, 0f, null)));
856     // can add a different feature
857     assertTrue(sq.addSequenceFeature(new SequenceFeature("Scop", "desc", 4,
858             8, 0f, null))); // different type
859     assertTrue(sq.addSequenceFeature(new SequenceFeature("Cath",
860             "description", 4, 8, 0f, null)));// different description
861     assertTrue(sq.addSequenceFeature(new SequenceFeature("Cath", "desc", 3,
862             8, 0f, null))); // different start position
863     assertTrue(sq.addSequenceFeature(new SequenceFeature("Cath", "desc", 4,
864             9, 0f, null))); // different end position
865     assertTrue(sq.addSequenceFeature(new SequenceFeature("Cath", "desc", 4,
866             8, 1f, null))); // different score
867     assertTrue(sq.addSequenceFeature(new SequenceFeature("Cath", "desc", 4,
868             8, Float.NaN, null))); // score NaN
869     assertTrue(sq.addSequenceFeature(new SequenceFeature("Cath", "desc", 4,
870             8, 0f, "Metal"))); // different group
871     assertEquals(8, sq.getFeatures().getAllFeatures().size());
872   }
873
874   /**
875    * Tests for adding (or updating) dbrefs
876    * 
877    * @see DBRefEntry#updateFrom(DBRefEntry)
878    */
879   @Test(groups = { "Functional" })
880   public void testAddDBRef()
881   {
882     SequenceI sq = new Sequence("", "abcde");
883     assertNull(sq.getDBRefs());
884     DBRefEntry dbref = new DBRefEntry("Uniprot", "1", "P00340");
885     sq.addDBRef(dbref);
886     assertEquals(1, sq.getDBRefs().length);
887     assertSame(dbref, sq.getDBRefs()[0]);
888
889     /*
890      * change of version - new entry
891      */
892     DBRefEntry dbref2 = new DBRefEntry("Uniprot", "2", "P00340");
893     sq.addDBRef(dbref2);
894     assertEquals(2, sq.getDBRefs().length);
895     assertSame(dbref, sq.getDBRefs()[0]);
896     assertSame(dbref2, sq.getDBRefs()[1]);
897
898     /*
899      * matches existing entry - not added
900      */
901     sq.addDBRef(new DBRefEntry("UNIPROT", "1", "p00340"));
902     assertEquals(2, sq.getDBRefs().length);
903
904     /*
905      * different source = new entry
906      */
907     DBRefEntry dbref3 = new DBRefEntry("UniRef", "1", "p00340");
908     sq.addDBRef(dbref3);
909     assertEquals(3, sq.getDBRefs().length);
910     assertSame(dbref3, sq.getDBRefs()[2]);
911
912     /*
913      * different ref = new entry
914      */
915     DBRefEntry dbref4 = new DBRefEntry("UniRef", "1", "p00341");
916     sq.addDBRef(dbref4);
917     assertEquals(4, sq.getDBRefs().length);
918     assertSame(dbref4, sq.getDBRefs()[3]);
919
920     /*
921      * matching ref with a mapping - map updated
922      */
923     DBRefEntry dbref5 = new DBRefEntry("UniRef", "1", "p00341");
924     Mapping map = new Mapping(new MapList(new int[] { 1, 3 }, new int[] {
925         1, 1 }, 3, 1));
926     dbref5.setMap(map);
927     sq.addDBRef(dbref5);
928     assertEquals(4, sq.getDBRefs().length);
929     assertSame(dbref4, sq.getDBRefs()[3]);
930     assertSame(map, dbref4.getMap());
931
932     /*
933      * 'real' version replaces "0" version
934      */
935     dbref2.setVersion("0");
936     DBRefEntry dbref6 = new DBRefEntry(dbref2.getSource(), "3",
937             dbref2.getAccessionId());
938     sq.addDBRef(dbref6);
939     assertEquals(4, sq.getDBRefs().length);
940     assertSame(dbref2, sq.getDBRefs()[1]);
941     assertEquals("3", dbref2.getVersion());
942
943     /*
944      * 'real' version replaces "source:0" version
945      */
946     dbref3.setVersion("Uniprot:0");
947     DBRefEntry dbref7 = new DBRefEntry(dbref3.getSource(), "3",
948             dbref3.getAccessionId());
949     sq.addDBRef(dbref7);
950     assertEquals(4, sq.getDBRefs().length);
951     assertSame(dbref3, sq.getDBRefs()[2]);
952     assertEquals("3", dbref2.getVersion());
953   }
954
955   @Test(groups = { "Functional" })
956   public void testGetPrimaryDBRefs_peptide()
957   {
958     SequenceI sq = new Sequence("aseq", "ASDFKYLMQPRST", 10, 22);
959
960     // no dbrefs
961     List<DBRefEntry> primaryDBRefs = sq.getPrimaryDBRefs();
962     assertTrue(primaryDBRefs.isEmpty());
963
964     // empty dbrefs
965     sq.setDBRefs(new DBRefEntry[] {});
966     primaryDBRefs = sq.getPrimaryDBRefs();
967     assertTrue(primaryDBRefs.isEmpty());
968
969     // primary - uniprot
970     DBRefEntry upentry1 = new DBRefEntry("UNIPROT", "0", "Q04760");
971     sq.addDBRef(upentry1);
972
973     // primary - uniprot with congruent map
974     DBRefEntry upentry2 = new DBRefEntry("UNIPROT", "0", "Q04762");
975     upentry2.setMap(new Mapping(null, new MapList(new int[] { 10, 22 },
976             new int[] { 10, 22 }, 1, 1)));
977     sq.addDBRef(upentry2);
978
979     // primary - uniprot with map of enclosing sequence
980     DBRefEntry upentry3 = new DBRefEntry("UNIPROT", "0", "Q04763");
981     upentry3.setMap(new Mapping(null, new MapList(new int[] { 8, 24 },
982             new int[] { 8, 24 }, 1, 1)));
983     sq.addDBRef(upentry3);
984
985     // not primary - uniprot with map of sub-sequence (5')
986     DBRefEntry upentry4 = new DBRefEntry("UNIPROT", "0", "Q04764");
987     upentry4.setMap(new Mapping(null, new MapList(new int[] { 10, 18 },
988             new int[] { 10, 18 }, 1, 1)));
989     sq.addDBRef(upentry4);
990
991     // not primary - uniprot with map that overlaps 3'
992     DBRefEntry upentry5 = new DBRefEntry("UNIPROT", "0", "Q04765");
993     upentry5.setMap(new Mapping(null, new MapList(new int[] { 12, 22 },
994             new int[] { 12, 22 }, 1, 1)));
995     sq.addDBRef(upentry5);
996
997     // not primary - uniprot with map to different coordinates frame
998     DBRefEntry upentry6 = new DBRefEntry("UNIPROT", "0", "Q04766");
999     upentry6.setMap(new Mapping(null, new MapList(new int[] { 12, 18 },
1000             new int[] { 112, 118 }, 1, 1)));
1001     sq.addDBRef(upentry6);
1002
1003     // not primary - dbref to 'non-core' database
1004     DBRefEntry upentry7 = new DBRefEntry("Pfam", "0", "PF00903");
1005     sq.addDBRef(upentry7);
1006
1007     // primary - type is PDB
1008     DBRefEntry pdbentry = new DBRefEntry("PDB", "0", "1qip");
1009     sq.addDBRef(pdbentry);
1010
1011     // not primary - PDBEntry has no file
1012     sq.addDBRef(new DBRefEntry("PDB", "0", "1AAA"));
1013
1014     // not primary - no PDBEntry
1015     sq.addDBRef(new DBRefEntry("PDB", "0", "1DDD"));
1016
1017     // add corroborating PDB entry for primary DBref -
1018     // needs to have a file as well as matching ID
1019     // note PDB ID is not treated as case sensitive
1020     sq.addPDBId(new PDBEntry("1QIP", null, Type.PDB, new File("/blah")
1021             .toString()));
1022
1023     // not valid DBRef - no file..
1024     sq.addPDBId(new PDBEntry("1AAA", null, null, null));
1025
1026     primaryDBRefs = sq.getPrimaryDBRefs();
1027     assertEquals(4, primaryDBRefs.size());
1028     assertTrue("Couldn't find simple primary reference (UNIPROT)",
1029             primaryDBRefs.contains(upentry1));
1030     assertTrue("Couldn't find mapped primary reference (UNIPROT)",
1031             primaryDBRefs.contains(upentry2));
1032     assertTrue("Couldn't find mapped context reference (UNIPROT)",
1033             primaryDBRefs.contains(upentry3));
1034     assertTrue("Couldn't find expected PDB primary reference",
1035             primaryDBRefs.contains(pdbentry));
1036   }
1037
1038   @Test(groups = { "Functional" })
1039   public void testGetPrimaryDBRefs_nucleotide()
1040   {
1041     SequenceI sq = new Sequence("aseq", "TGATCACTCGACTAGCATCAGCATA", 10, 34);
1042
1043     // primary - Ensembl
1044     DBRefEntry dbr1 = new DBRefEntry("ENSEMBL", "0", "ENSG1234");
1045     sq.addDBRef(dbr1);
1046
1047     // not primary - Ensembl 'transcript' mapping of sub-sequence
1048     DBRefEntry dbr2 = new DBRefEntry("ENSEMBL", "0", "ENST1234");
1049     dbr2.setMap(new Mapping(null, new MapList(new int[] { 15, 25 },
1050             new int[] { 1, 11 }, 1, 1)));
1051     sq.addDBRef(dbr2);
1052
1053     // primary - EMBL with congruent map
1054     DBRefEntry dbr3 = new DBRefEntry("EMBL", "0", "J1234");
1055     dbr3.setMap(new Mapping(null, new MapList(new int[] { 10, 34 },
1056             new int[] { 10, 34 }, 1, 1)));
1057     sq.addDBRef(dbr3);
1058
1059     // not primary - to non-core database
1060     DBRefEntry dbr4 = new DBRefEntry("CCDS", "0", "J1234");
1061     sq.addDBRef(dbr4);
1062
1063     // not primary - to protein
1064     DBRefEntry dbr5 = new DBRefEntry("UNIPROT", "0", "Q87654");
1065     sq.addDBRef(dbr5);
1066
1067     List<DBRefEntry> primaryDBRefs = sq.getPrimaryDBRefs();
1068     assertEquals(2, primaryDBRefs.size());
1069     assertTrue(primaryDBRefs.contains(dbr1));
1070     assertTrue(primaryDBRefs.contains(dbr3));
1071   }
1072
1073   /**
1074    * Test the method that updates the list of PDBEntry from any new DBRefEntry
1075    * for PDB
1076    */
1077   @Test(groups = { "Functional" })
1078   public void testUpdatePDBIds()
1079   {
1080     PDBEntry pdbe1 = new PDBEntry("3A6S", null, null, null);
1081     seq.addPDBId(pdbe1);
1082     seq.addDBRef(new DBRefEntry("Ensembl", "8", "ENST1234"));
1083     seq.addDBRef(new DBRefEntry("PDB", "0", "1A70"));
1084     seq.addDBRef(new DBRefEntry("PDB", "0", "4BQGa"));
1085     seq.addDBRef(new DBRefEntry("PDB", "0", "3a6sB"));
1086     // 7 is not a valid chain code:
1087     seq.addDBRef(new DBRefEntry("PDB", "0", "2GIS7"));
1088
1089     seq.updatePDBIds();
1090     List<PDBEntry> pdbIds = seq.getAllPDBEntries();
1091     assertEquals(4, pdbIds.size());
1092     assertSame(pdbe1, pdbIds.get(0));
1093     // chain code got added to 3A6S:
1094     assertEquals("B", pdbe1.getChainCode());
1095     assertEquals("1A70", pdbIds.get(1).getId());
1096     // 4BQGA is parsed into id + chain
1097     assertEquals("4BQG", pdbIds.get(2).getId());
1098     assertEquals("a", pdbIds.get(2).getChainCode());
1099     assertEquals("2GIS7", pdbIds.get(3).getId());
1100     assertNull(pdbIds.get(3).getChainCode());
1101   }
1102
1103   /**
1104    * Test the method that either adds a pdbid or updates an existing one
1105    */
1106   @Test(groups = { "Functional" })
1107   public void testAddPDBId()
1108   {
1109     PDBEntry pdbe = new PDBEntry("3A6S", null, null, null);
1110     seq.addPDBId(pdbe);
1111     assertEquals(1, seq.getAllPDBEntries().size());
1112     assertSame(pdbe, seq.getPDBEntry("3A6S"));
1113     assertSame(pdbe, seq.getPDBEntry("3a6s")); // case-insensitive
1114
1115     // add the same entry
1116     seq.addPDBId(pdbe);
1117     assertEquals(1, seq.getAllPDBEntries().size());
1118     assertSame(pdbe, seq.getPDBEntry("3A6S"));
1119
1120     // add an identical entry
1121     seq.addPDBId(new PDBEntry("3A6S", null, null, null));
1122     assertEquals(1, seq.getAllPDBEntries().size());
1123     assertSame(pdbe, seq.getPDBEntry("3A6S"));
1124
1125     // add a different entry
1126     PDBEntry pdbe2 = new PDBEntry("1A70", null, null, null);
1127     seq.addPDBId(pdbe2);
1128     assertEquals(2, seq.getAllPDBEntries().size());
1129     assertSame(pdbe, seq.getAllPDBEntries().get(0));
1130     assertSame(pdbe2, seq.getAllPDBEntries().get(1));
1131
1132     // update pdbe with chain code, file, type
1133     PDBEntry pdbe3 = new PDBEntry("3a6s", "A", Type.PDB, "filepath");
1134     seq.addPDBId(pdbe3);
1135     assertEquals(2, seq.getAllPDBEntries().size());
1136     assertSame(pdbe, seq.getAllPDBEntries().get(0)); // updated in situ
1137     assertEquals("3A6S", pdbe.getId()); // unchanged
1138     assertEquals("A", pdbe.getChainCode()); // updated
1139     assertEquals(Type.PDB.toString(), pdbe.getType()); // updated
1140     assertEquals("filepath", pdbe.getFile()); // updated
1141     assertSame(pdbe2, seq.getAllPDBEntries().get(1));
1142
1143     // add with a different file path
1144     PDBEntry pdbe4 = new PDBEntry("3a6s", "A", Type.PDB, "filepath2");
1145     seq.addPDBId(pdbe4);
1146     assertEquals(3, seq.getAllPDBEntries().size());
1147     assertSame(pdbe4, seq.getAllPDBEntries().get(2));
1148
1149     // add with a different chain code
1150     PDBEntry pdbe5 = new PDBEntry("3a6s", "B", Type.PDB, "filepath");
1151     seq.addPDBId(pdbe5);
1152     assertEquals(4, seq.getAllPDBEntries().size());
1153     assertSame(pdbe5, seq.getAllPDBEntries().get(3));
1154   }
1155
1156   @Test(
1157     groups = { "Functional" },
1158     expectedExceptions = { IllegalArgumentException.class })
1159   public void testSetDatasetSequence_toSelf()
1160   {
1161     seq.setDatasetSequence(seq);
1162   }
1163
1164   @Test(
1165     groups = { "Functional" },
1166     expectedExceptions = { IllegalArgumentException.class })
1167   public void testSetDatasetSequence_cascading()
1168   {
1169     SequenceI seq2 = new Sequence("Seq2", "xyz");
1170     seq2.createDatasetSequence();
1171     seq.setDatasetSequence(seq2);
1172   }
1173 }