JAL-2089 patch broken merge to master for Release 2.10.0b1
[jalview.git] / test / jalview / datamodel / SequenceTest.java
index 1fed98b..065bed7 100644 (file)
@@ -31,6 +31,7 @@ import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
 import jalview.datamodel.PDBEntry.Type;
 import jalview.util.MapList;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -69,11 +70,11 @@ public class SequenceTest
   public void testIsProtein()
   {
     // test Protein
-    assertTrue(new Sequence("prot","ASDFASDFASDF").isProtein());
+    assertTrue(new Sequence("prot", "ASDFASDFASDF").isProtein());
     // test DNA
-    assertFalse(new Sequence("prot","ACGTACGTACGT").isProtein());
+    assertFalse(new Sequence("prot", "ACGTACGTACGT").isProtein());
     // test RNA
-    SequenceI sq = new Sequence("prot","ACGUACGUACGU");
+    SequenceI sq = new Sequence("prot", "ACGUACGUACGU");
     assertFalse(sq.isProtein());
     // change sequence, should trigger an update of cached result
     sq.setSequence("ASDFASDFADSF");
@@ -110,8 +111,7 @@ public class SequenceTest
   {
     AlignmentAnnotation ann1 = addAnnotation("label1", "desc1", "calcId1",
             1f);
-    AlignmentAnnotation ann2 = addAnnotation("label2", "desc2", "calcId2",
-            1f);
+    addAnnotation("label2", "desc2", "calcId2", 1f);
     AlignmentAnnotation ann3 = addAnnotation("label1", "desc3", "calcId3",
             1f);
     AlignmentAnnotation[] anns = seq.getAnnotation("label1");
@@ -133,16 +133,15 @@ public class SequenceTest
   @Test(groups = { "Functional" })
   public void testGetAlignmentAnnotations_forCalcIdAndLabel()
   {
-    AlignmentAnnotation ann1 = addAnnotation("label1", "desc1", "calcId1",
-            1f);
+    addAnnotation("label1", "desc1", "calcId1", 1f);
     AlignmentAnnotation ann2 = addAnnotation("label2", "desc2", "calcId2",
             1f);
-    AlignmentAnnotation ann3 = addAnnotation("label2", "desc3", "calcId3",
-            1f);
+    addAnnotation("label2", "desc3", "calcId3", 1f);
     AlignmentAnnotation ann4 = addAnnotation("label2", "desc3", "calcId2",
             1f);
-    AlignmentAnnotation ann5 = addAnnotation("label5", "desc3", null, 1f);
-    AlignmentAnnotation ann6 = addAnnotation(null, "desc3", "calcId3", 1f);
+    addAnnotation("label5", "desc3", null, 1f);
+    addAnnotation(null, "desc3", "calcId3", 1f);
+
     List<AlignmentAnnotation> anns = seq.getAlignmentAnnotations("calcId2",
             "label2");
     assertEquals(2, anns.size());
@@ -337,7 +336,6 @@ public class SequenceTest
     assertEquals(1, sfs.length);
     assertSame(sf, sfs[0]);
 
-
     /*
      * SequenceFeature on sequence and dataset sequence; returns that on
      * sequence
@@ -367,7 +365,16 @@ public class SequenceTest
      * is there a usecase for this ? setDatasetSequence should throw an error if
      * this actually occurs.
      */
-    sq.getDatasetSequence().setDatasetSequence(sq); // loop!
+    try
+    {
+      sq.getDatasetSequence().setDatasetSequence(sq); // loop!
+      Assert.fail("Expected Error to be raised when calling setDatasetSequence with self reference");
+    } catch (IllegalArgumentException e)
+    {
+      // TODO Jalview error/exception class for raising implementation errors
+      assertTrue(e.getMessage().toLowerCase()
+              .contains("implementation error"));
+    }
     assertNull(sq.getSequenceFeatures());
   }
 
@@ -417,7 +424,7 @@ public class SequenceTest
   @Test(groups = { "Functional" })
   public void testCreateDatasetSequence()
   {
-    SequenceI sq = new Sequence("my","ASDASD");
+    SequenceI sq = new Sequence("my", "ASDASD");
     assertNull(sq.getDatasetSequence());
     SequenceI rds = sq.createDatasetSequence();
     assertNotNull(rds);
@@ -451,27 +458,29 @@ public class SequenceTest
     sq.addPDBId(new PDBEntry("1PDB", "B", Type.PDB, "filePath/test1"));
     sq.addPDBId(new PDBEntry("2PDB", "A", Type.MMCIF, "filePath/test2"));
     sq.addPDBId(new PDBEntry("2PDB", "B", Type.MMCIF, "filePath/test2"));
-    
+
+    // these are the same as ones already added
     DBRefEntry pdb1pdb = new DBRefEntry("PDB", "version1", "1PDB");
-    DBRefEntry pdb2pdb = new DBRefEntry("PDB", "version1", "2PDB");
+    DBRefEntry pdb2pdb = new DBRefEntry("PDB", "version2", "2PDB");
+
     List<DBRefEntry> primRefs = Arrays.asList(new DBRefEntry[] { pdb1pdb,
         pdb2pdb });
 
-    sq.getDatasetSequence().addDBRef(pdb1pdb);
-    sq.getDatasetSequence().addDBRef(pdb2pdb);
+    sq.getDatasetSequence().addDBRef(pdb1pdb); // should do nothing
+    sq.getDatasetSequence().addDBRef(pdb2pdb); // should do nothing
     sq.getDatasetSequence().addDBRef(
-            new DBRefEntry("PDB", "version3", "3PDB"));
+            new DBRefEntry("PDB", "version3", "3PDB")); // should do nothing
     sq.getDatasetSequence().addDBRef(
-            new DBRefEntry("PDB", "version4", "4PDB"));
-    
-    PDBEntry pdbe1a=new PDBEntry("1PDB", "A", Type.PDB, "filePath/test1");
+            new DBRefEntry("PDB", "version4", "4PDB")); // should do nothing
+
+    PDBEntry pdbe1a = new PDBEntry("1PDB", "A", Type.PDB, "filePath/test1");
     PDBEntry pdbe1b = new PDBEntry("1PDB", "B", Type.PDB, "filePath/test1");
-    PDBEntry pdbe2a=new PDBEntry("2PDB", "A", Type.MMCIF, "filePath/test2");
-    PDBEntry pdbe2b = new PDBEntry("2PDB", "B", Type.MMCIF, "filePath/test2");
-    sq.getDatasetSequence().addPDBId(
-            pdbe1a);
-    sq.getDatasetSequence().addPDBId(
-            pdbe1b);
+    PDBEntry pdbe2a = new PDBEntry("2PDB", "A", Type.MMCIF,
+            "filePath/test2");
+    PDBEntry pdbe2b = new PDBEntry("2PDB", "B", Type.MMCIF,
+            "filePath/test2");
+    sq.getDatasetSequence().addPDBId(pdbe1a);
+    sq.getDatasetSequence().addPDBId(pdbe1b);
     sq.getDatasetSequence().addPDBId(pdbe2a);
     sq.getDatasetSequence().addPDBId(pdbe2b);
 
@@ -499,11 +508,14 @@ public class SequenceTest
             new AlignmentAnnotation("Test annot", "Test annot description",
                     annots));
     Assert.assertEquals(sq.getDescription(), "Test sequence description..");
-    Assert.assertEquals(sq.getDBRefs().length, 4);
+    Assert.assertEquals(sq.getDBRefs().length, 5); // DBRefs are on dataset
+                                                   // sequence
     Assert.assertEquals(sq.getAllPDBEntries().size(), 4);
     Assert.assertNotNull(sq.getAnnotation());
     Assert.assertEquals(sq.getAnnotation()[0].annotations.length, 2);
-    Assert.assertEquals(sq.getDatasetSequence().getDBRefs().length, 4);
+    Assert.assertEquals(sq.getDatasetSequence().getDBRefs().length, 5); // same
+                                                                        // as
+                                                                        // sq.getDBRefs()
     Assert.assertEquals(sq.getDatasetSequence().getAllPDBEntries().size(),
             4);
     Assert.assertNotNull(sq.getDatasetSequence().getAnnotation());
@@ -512,11 +524,11 @@ public class SequenceTest
 
     Assert.assertEquals(derived.getDescription(),
             "Test sequence description..");
-    Assert.assertEquals(derived.getDBRefs().length, 4);
+    Assert.assertEquals(derived.getDBRefs().length, 5); // come from dataset
     Assert.assertEquals(derived.getAllPDBEntries().size(), 4);
     Assert.assertNotNull(derived.getAnnotation());
     Assert.assertEquals(derived.getAnnotation()[0].annotations.length, 2);
-    Assert.assertEquals(derived.getDatasetSequence().getDBRefs().length, 4);
+    Assert.assertEquals(derived.getDatasetSequence().getDBRefs().length, 5);
     Assert.assertEquals(derived.getDatasetSequence().getAllPDBEntries()
             .size(), 4);
     Assert.assertNotNull(derived.getDatasetSequence().getAnnotation());
@@ -530,6 +542,17 @@ public class SequenceTest
     assertNotNull(sq.getSequenceFeatures());
     assertArrayEquals(sq.getSequenceFeatures(),
             derived.getSequenceFeatures());
+
+    /*
+     *  verify we have primary db refs *just* for PDB IDs with associated
+     *  PDBEntry objects
+     */
+
+    assertEquals(primRefs, sq.getPrimaryDBRefs());
+    assertEquals(primRefs, sq.getDatasetSequence().getPrimaryDBRefs());
+
+    assertEquals(sq.getPrimaryDBRefs(), derived.getPrimaryDBRefs());
+
   }
 
   /**
@@ -574,7 +597,7 @@ public class SequenceTest
             12.4f, "group"));
     seq1.addPDBId(new PDBEntry("1A70", "B", Type.PDB, "File"));
     seq1.addDBRef(new DBRefEntry("EMBL", "1.2", "AZ12345"));
-    
+
     SequenceI copy = new Sequence(seq1);
 
     assertNull(copy.getDatasetSequence());
@@ -650,9 +673,13 @@ public class SequenceTest
     // copy has a copy of the sequence feature:
     SequenceFeature[] sfs = copy.getSequenceFeatures();
     assertEquals(1, sfs.length);
-    if (seq1.getDatasetSequence()!=null && copy.getDatasetSequence()==seq1.getDatasetSequence()) {
+    if (seq1.getDatasetSequence() != null
+            && copy.getDatasetSequence() == seq1.getDatasetSequence())
+    {
       assertTrue(sfs[0] == seq1.getSequenceFeatures()[0]);
-    } else {
+    }
+    else
+    {
       assertFalse(sfs[0] == seq1.getSequenceFeatures()[0]);
     }
     assertTrue(sfs[0].equals(seq1.getSequenceFeatures()[0]));
@@ -754,4 +781,223 @@ public class SequenceTest
     assertSame(dbref3, sq.getDBRefs()[2]);
     assertEquals("3", dbref2.getVersion());
   }
+
+  @Test(groups = { "Functional" })
+  public void testGetPrimaryDBRefs_peptide()
+  {
+    SequenceI sq = new Sequence("aseq", "ASDFKYLMQPRST", 10, 22);
+
+    // no dbrefs
+    List<DBRefEntry> primaryDBRefs = sq.getPrimaryDBRefs();
+    assertTrue(primaryDBRefs.isEmpty());
+
+    // empty dbrefs
+    sq.setDBRefs(new DBRefEntry[] {});
+    primaryDBRefs = sq.getPrimaryDBRefs();
+    assertTrue(primaryDBRefs.isEmpty());
+
+    // primary - uniprot
+    DBRefEntry upentry1 = new DBRefEntry("UNIPROT", "0", "Q04760");
+    sq.addDBRef(upentry1);
+
+    // primary - uniprot with congruent map
+    DBRefEntry upentry2 = new DBRefEntry("UNIPROT", "0", "Q04762");
+    upentry2.setMap(new Mapping(null, new MapList(new int[] { 10, 22 },
+            new int[] { 10, 22 }, 1, 1)));
+    sq.addDBRef(upentry2);
+
+    // primary - uniprot with map of enclosing sequence
+    DBRefEntry upentry3 = new DBRefEntry("UNIPROT", "0", "Q04763");
+    upentry3.setMap(new Mapping(null, new MapList(new int[] { 8, 24 },
+            new int[] { 8, 24 }, 1, 1)));
+    sq.addDBRef(upentry3);
+
+    // not primary - uniprot with map of sub-sequence (5')
+    DBRefEntry upentry4 = new DBRefEntry("UNIPROT", "0", "Q04764");
+    upentry4.setMap(new Mapping(null, new MapList(new int[] { 10, 18 },
+            new int[] { 10, 18 }, 1, 1)));
+    sq.addDBRef(upentry4);
+
+    // not primary - uniprot with map that overlaps 3'
+    DBRefEntry upentry5 = new DBRefEntry("UNIPROT", "0", "Q04765");
+    upentry5.setMap(new Mapping(null, new MapList(new int[] { 12, 22 },
+            new int[] { 12, 22 }, 1, 1)));
+    sq.addDBRef(upentry5);
+
+    // not primary - uniprot with map to different coordinates frame
+    DBRefEntry upentry6 = new DBRefEntry("UNIPROT", "0", "Q04766");
+    upentry6.setMap(new Mapping(null, new MapList(new int[] { 12, 18 },
+            new int[] { 112, 118 }, 1, 1)));
+    sq.addDBRef(upentry6);
+
+    // not primary - dbref to 'non-core' database
+    DBRefEntry upentry7 = new DBRefEntry("Pfam", "0", "PF00903");
+    sq.addDBRef(upentry7);
+
+    // primary - type is PDB
+    DBRefEntry pdbentry = new DBRefEntry("PDB", "0", "1qip");
+    sq.addDBRef(pdbentry);
+
+    // not primary - PDBEntry has no file
+    sq.addDBRef(new DBRefEntry("PDB", "0", "1AAA"));
+
+    // not primary - no PDBEntry
+    sq.addDBRef(new DBRefEntry("PDB", "0", "1DDD"));
+
+    // add corroborating PDB entry for primary DBref -
+    // needs to have a file as well as matching ID
+    // note PDB ID is not treated as case sensitive
+    sq.addPDBId(new PDBEntry("1QIP", null, Type.PDB, new File("/blah")
+            .toString()));
+
+    // not valid DBRef - no file..
+    sq.addPDBId(new PDBEntry("1AAA", null, null, null));
+
+    primaryDBRefs = sq.getPrimaryDBRefs();
+    assertEquals(4, primaryDBRefs.size());
+    assertTrue("Couldn't find simple primary reference (UNIPROT)",
+            primaryDBRefs.contains(upentry1));
+    assertTrue("Couldn't find mapped primary reference (UNIPROT)",
+            primaryDBRefs.contains(upentry2));
+    assertTrue("Couldn't find mapped context reference (UNIPROT)",
+            primaryDBRefs.contains(upentry3));
+    assertTrue("Couldn't find expected PDB primary reference",
+            primaryDBRefs.contains(pdbentry));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetPrimaryDBRefs_nucleotide()
+  {
+    SequenceI sq = new Sequence("aseq", "TGATCACTCGACTAGCATCAGCATA", 10, 34);
+
+    // primary - Ensembl
+    DBRefEntry dbr1 = new DBRefEntry("ENSEMBL", "0", "ENSG1234");
+    sq.addDBRef(dbr1);
+
+    // not primary - Ensembl 'transcript' mapping of sub-sequence
+    DBRefEntry dbr2 = new DBRefEntry("ENSEMBL", "0", "ENST1234");
+    dbr2.setMap(new Mapping(null, new MapList(new int[] { 15, 25 },
+            new int[] { 1, 11 }, 1, 1)));
+    sq.addDBRef(dbr2);
+
+    // primary - EMBL with congruent map
+    DBRefEntry dbr3 = new DBRefEntry("EMBL", "0", "J1234");
+    dbr3.setMap(new Mapping(null, new MapList(new int[] { 10, 34 },
+            new int[] { 10, 34 }, 1, 1)));
+    sq.addDBRef(dbr3);
+
+    // not primary - to non-core database
+    DBRefEntry dbr4 = new DBRefEntry("CCDS", "0", "J1234");
+    sq.addDBRef(dbr4);
+
+    // not primary - to protein
+    DBRefEntry dbr5 = new DBRefEntry("UNIPROT", "0", "Q87654");
+    sq.addDBRef(dbr5);
+
+    List<DBRefEntry> primaryDBRefs = sq.getPrimaryDBRefs();
+    assertEquals(2, primaryDBRefs.size());
+    assertTrue(primaryDBRefs.contains(dbr1));
+    assertTrue(primaryDBRefs.contains(dbr3));
+  }
+
+  /**
+   * Test the method that updates the list of PDBEntry from any new DBRefEntry
+   * for PDB
+   */
+  @Test(groups = { "Functional" })
+  public void testUpdatePDBIds()
+  {
+    PDBEntry pdbe1 = new PDBEntry("3A6S", null, null, null);
+    seq.addPDBId(pdbe1);
+    seq.addDBRef(new DBRefEntry("Ensembl", "8", "ENST1234"));
+    seq.addDBRef(new DBRefEntry("PDB", "0", "1A70"));
+    seq.addDBRef(new DBRefEntry("PDB", "0", "4BQGa"));
+    seq.addDBRef(new DBRefEntry("PDB", "0", "3a6sB"));
+    // 7 is not a valid chain code:
+    seq.addDBRef(new DBRefEntry("PDB", "0", "2GIS7"));
+
+    seq.updatePDBIds();
+    List<PDBEntry> pdbIds = seq.getAllPDBEntries();
+    assertEquals(4, pdbIds.size());
+    assertSame(pdbe1, pdbIds.get(0));
+    // chain code got added to 3A6S:
+    assertEquals("B", pdbe1.getChainCode());
+    assertEquals("1A70", pdbIds.get(1).getId());
+    // 4BQGA is parsed into id + chain
+    assertEquals("4BQG", pdbIds.get(2).getId());
+    assertEquals("a", pdbIds.get(2).getChainCode());
+    assertEquals("2GIS7", pdbIds.get(3).getId());
+    assertNull(pdbIds.get(3).getChainCode());
+  }
+
+  /**
+   * Test the method that either adds a pdbid or updates an existing one
+   */
+  @Test(groups = { "Functional" })
+  public void testAddPDBId()
+  {
+    PDBEntry pdbe = new PDBEntry("3A6S", null, null, null);
+    seq.addPDBId(pdbe);
+    assertEquals(1, seq.getAllPDBEntries().size());
+    assertSame(pdbe, seq.getPDBEntry("3A6S"));
+    assertSame(pdbe, seq.getPDBEntry("3a6s")); // case-insensitive
+
+    // add the same entry
+    seq.addPDBId(pdbe);
+    assertEquals(1, seq.getAllPDBEntries().size());
+    assertSame(pdbe, seq.getPDBEntry("3A6S"));
+
+    // add an identical entry
+    seq.addPDBId(new PDBEntry("3A6S", null, null, null));
+    assertEquals(1, seq.getAllPDBEntries().size());
+    assertSame(pdbe, seq.getPDBEntry("3A6S"));
+
+    // add a different entry
+    PDBEntry pdbe2 = new PDBEntry("1A70", null, null, null);
+    seq.addPDBId(pdbe2);
+    assertEquals(2, seq.getAllPDBEntries().size());
+    assertSame(pdbe, seq.getAllPDBEntries().get(0));
+    assertSame(pdbe2, seq.getAllPDBEntries().get(1));
+
+    // update pdbe with chain code, file, type
+    PDBEntry pdbe3 = new PDBEntry("3a6s", "A", Type.PDB, "filepath");
+    seq.addPDBId(pdbe3);
+    assertEquals(2, seq.getAllPDBEntries().size());
+    assertSame(pdbe, seq.getAllPDBEntries().get(0)); // updated in situ
+    assertEquals("3A6S", pdbe.getId()); // unchanged
+    assertEquals("A", pdbe.getChainCode()); // updated
+    assertEquals(Type.PDB.toString(), pdbe.getType()); // updated
+    assertEquals("filepath", pdbe.getFile()); // updated
+    assertSame(pdbe2, seq.getAllPDBEntries().get(1));
+
+    // add with a different file path
+    PDBEntry pdbe4 = new PDBEntry("3a6s", "A", Type.PDB, "filepath2");
+    seq.addPDBId(pdbe4);
+    assertEquals(3, seq.getAllPDBEntries().size());
+    assertSame(pdbe4, seq.getAllPDBEntries().get(2));
+
+    // add with a different chain code
+    PDBEntry pdbe5 = new PDBEntry("3a6s", "B", Type.PDB, "filepath");
+    seq.addPDBId(pdbe5);
+    assertEquals(4, seq.getAllPDBEntries().size());
+    assertSame(pdbe5, seq.getAllPDBEntries().get(3));
+  }
+
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { IllegalArgumentException.class })
+  public void testSetDatasetSequence_toSelf()
+  {
+    seq.setDatasetSequence(seq);
+  }
+
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = { IllegalArgumentException.class })
+  public void testSetDatasetSequence_cascading()
+  {
+    SequenceI seq2 = new Sequence("Seq2", "xyz");
+    seq2.createDatasetSequence();
+    seq.setDatasetSequence(seq2);
+  }
 }