Merge branch 'develop' into features/JAL-4134_use_annotation_row_for_colours_and_groups
[jalview.git] / test / jalview / analysis / AlignmentUtilsTests.java
index e231e7f..f017662 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.analysis;
 
+import static org.testng.Assert.assertNotEquals;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertNotNull;
@@ -27,21 +28,35 @@ import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
-import jalview.analysis.AlignmentUtils.DnaVariant;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.GeneLociI;
 import jalview.datamodel.Mapping;
 import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResultsI;
+import jalview.datamodel.SeqDistanceContactMatrix;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
-import jalview.datamodel.features.SequenceFeatures;
 import jalview.gui.JvOptionPane;
 import jalview.io.AppletFormatAdapter;
 import jalview.io.DataSourceType;
@@ -49,20 +64,9 @@ import jalview.io.FileFormat;
 import jalview.io.FileFormatI;
 import jalview.io.FormatAdapter;
 import jalview.io.gff.SequenceOntologyI;
+import jalview.util.Comparison;
 import jalview.util.MapList;
 import jalview.util.MappingUtils;
-import jalview.ws.params.InvalidArgumentException;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
 
 public class AlignmentUtilsTests
 {
@@ -2457,7 +2461,7 @@ public class AlignmentUtilsTests
    * the given protein. That is, given a transcript-to-peptide mapping, find the
    * cds-to-peptide mapping that relates to both, and return the CDS sequence.
    */
-  @Test
+  @Test(groups = "Functional")
   public void testFindCdsForProtein()
   {
     List<AlignedCodonFrame> mappings = new ArrayList<>();
@@ -2527,7 +2531,7 @@ public class AlignmentUtilsTests
    * cds-to-peptide mapping that relates to both, and return the CDS sequence.
    * This test is for the case where transcript and CDS are the same length.
    */
-  @Test
+  @Test(groups = "Functional")
   public void testFindCdsForProtein_noUTR()
   {
     List<AlignedCodonFrame> mappings = new ArrayList<>();
@@ -2600,4 +2604,151 @@ public class AlignmentUtilsTests
             dnaToPeptide);
     assertSame(seq, cds1.getDatasetSequence());
   }
+
+  @Test(groups = "Functional")
+  public void testAddReferenceAnnotations()
+  {
+    SequenceI longseq = new Sequence("longA", "ASDASDASDASDAASDASDASDASDA");
+    Annotation[] aa = new Annotation[longseq.getLength()];
+
+    for (int p = 0; p < aa.length; p++)
+    {
+      aa[p] = new Annotation("P", "pos " + (p + 1), (char) 0,
+              (float) p + 1);
+    }
+    AlignmentAnnotation refAnnot = new AlignmentAnnotation("LongSeqAnnot",
+            "Annotations", aa);
+    refAnnot.setCalcId("Test");
+    longseq.addAlignmentAnnotation(refAnnot);
+    verifyExpectedSequenceAnnotation(refAnnot);
+
+    Alignment ourAl = new Alignment(
+            new SequenceI[]
+            { longseq.getSubSequence(5, 10),
+                longseq.getSubSequence(7, 12) });
+    ourAl.createDatasetAlignment();
+
+    // transfer annotation
+    SortedMap<String, String> tipEntries = new TreeMap<>();
+    Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
+
+    AlignmentUtils.findAddableReferenceAnnotations(ourAl.getSequences(),
+            tipEntries, candidates, ourAl);
+    AlignmentUtils.addReferenceAnnotations(candidates, ourAl, null);
+
+    assertNotNull(ourAl.getAlignmentAnnotation());
+    assertEquals(ourAl.getAlignmentAnnotation().length, 2);
+
+    for (AlignmentAnnotation alan : ourAl.getAlignmentAnnotation())
+    {
+      verifyExpectedSequenceAnnotation(alan);
+    }
+    // Everything above works for 2.11.3 and 2.11.2.x.
+    // now simulate copy/paste to new alignment
+    SequenceI[] newSeqAl = new SequenceI[2];
+    // copy sequences but no annotation
+    newSeqAl[0] = new Sequence(ourAl.getSequenceAt(0),
+            ourAl.getSequenceAt(0).getAnnotation());
+    newSeqAl[1] = new Sequence(ourAl.getSequenceAt(1),
+            ourAl.getSequenceAt(1).getAnnotation());
+
+    Alignment newAl = new Alignment(newSeqAl);
+    // delete annotation
+    for (SequenceI sq : newAl.getSequences())
+    {
+      sq.setAlignmentAnnotation(new AlignmentAnnotation[0]);
+    }
+    // JAL-4182 scenario test
+    SequenceGroup sg = new SequenceGroup(Arrays.asList(newSeqAl));
+    sg.setStartRes(0);
+    sg.setEndRes(newAl.getWidth());
+    AlignmentUtils.addReferenceAnnotationTo(newAl, newSeqAl[0],
+            newSeqAl[0].getDatasetSequence().getAnnotation()[0], sg);
+    AlignmentUtils.addReferenceAnnotationTo(newAl, newSeqAl[1],
+            newSeqAl[1].getDatasetSequence().getAnnotation()[0], sg);
+    for (AlignmentAnnotation alan : newAl.getAlignmentAnnotation())
+    {
+      verifyExpectedSequenceAnnotation(alan);
+    }
+  }
+
+  /**
+   * helper - tests annotation is mapped to position it was originally created
+   * for
+   * 
+   * @param alan
+   */
+  private void verifyExpectedSequenceAnnotation(AlignmentAnnotation alan)
+  {
+    for (int c = 0; c < alan.annotations.length; c++)
+    {
+      Annotation a = alan.annotations[c];
+      if (a != null)
+      {
+        assertEquals("Misaligned annotation at " + c,
+                (float) alan.sequenceRef.findPosition(c), a.value);
+      }
+      else
+      {
+        assertTrue("Unexpected Null at position " + c,
+                c >= alan.sequenceRef.getLength()
+                        || Comparison.isGap(alan.sequenceRef.getCharAt(c)));
+      }
+    }
+  }
+
+  @Test(groups = "Functional")
+  public void testAddReferenceContactMap()
+  {
+    SequenceI sq = new Sequence("a", "SSSQ");
+    ContactMatrixI cm = new SeqDistanceContactMatrix(4);
+    AlignmentAnnotation cm_aan = sq.addContactList(cm);
+    cm_aan.description = cm_aan.description + " cm1";
+    SequenceI dssq = sq.createDatasetSequence();
+
+    // remove annotation on our non-dataset sequence
+    sq.removeAlignmentAnnotation(sq.getAnnotation()[0]);
+    // test transfer
+    Alignment al = new Alignment(new SequenceI[] { sq });
+    SortedMap<String, String> tipEntries = new TreeMap<>();
+    Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
+
+    AlignmentUtils.findAddableReferenceAnnotations(al.getSequences(),
+            tipEntries, candidates, al);
+    AlignmentUtils.addReferenceAnnotations(candidates, al, null);
+    assertTrue("No contact map annotation transferred",
+            al.getAlignmentAnnotation() != null
+                    && al.getAlignmentAnnotation().length == 1);
+    AlignmentAnnotation alan = al.findAnnotations(sq, null, cm_aan.label)
+            .iterator().next();
+    ContactMatrixI t_cm = al.getContactMatrixFor(alan);
+    assertNotNull("No contact map for the transferred annotation row.",
+            t_cm);
+    assertTrue(t_cm instanceof SeqDistanceContactMatrix);
+    assertTrue(((SeqDistanceContactMatrix) t_cm).hasReferenceSeq());
+
+    ContactListI cl = al.getContactListFor(alan, 1);
+    assertNotNull(
+            "No contact matrix recovered after reference annotation transfer",
+            cl);
+    // semantics of sequence associated contact list is slightly tricky - column
+    // 3 in alignment should have data
+    cl = al.getContactListFor(alan, 3);
+    assertNotNull(
+            "Contact matrix should have data for last position in sequence",
+            cl);
+
+    ContactMatrixI cm2 = new SeqDistanceContactMatrix(4);
+    dssq.addContactList(cm2);
+    tipEntries = new TreeMap<>();
+    candidates = new LinkedHashMap<>();
+
+    AlignmentUtils.findAddableReferenceAnnotations(al.getSequences(),
+            tipEntries, candidates, al);
+    AlignmentUtils.addReferenceAnnotations(candidates, al, null);
+    assertTrue("Expected two contact map annotation transferred",
+            al.getAlignmentAnnotation() != null
+                    && al.getAlignmentAnnotation().length == 2);
+
+  }
 }