JAL-2629 update spike branch to latest
[jalview.git] / test / jalview / io / Jalview2xmlTests.java
index 6abb7e5..3a727b4 100644 (file)
@@ -23,24 +23,32 @@ package jalview.io;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertSame;
 import static org.testng.Assert.assertTrue;
 
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
+import jalview.api.FeatureColourI;
 import jalview.api.ViewStyleI;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.HiddenSequences;
+import jalview.datamodel.Mapping;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.PDBEntry.Type;
 import jalview.datamodel.SequenceCollectionI;
+import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcher;
+import jalview.datamodel.features.FeatureMatcherSet;
+import jalview.datamodel.features.FeatureMatcherSetI;
 import jalview.gui.AlignFrame;
-import jalview.gui.AlignViewport;
 import jalview.gui.AlignmentPanel;
 import jalview.gui.Desktop;
+import jalview.gui.FeatureRenderer;
 import jalview.gui.Jalview2XML;
 import jalview.gui.JvOptionPane;
 import jalview.gui.PopupMenu;
@@ -50,13 +58,16 @@ import jalview.schemes.AnnotationColourGradient;
 import jalview.schemes.BuriedColourScheme;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
+import jalview.schemes.FeatureColour;
 import jalview.schemes.JalviewColourScheme;
 import jalview.schemes.RNAHelicesColour;
 import jalview.schemes.StrandColourScheme;
 import jalview.schemes.TCoffeeColourScheme;
 import jalview.structure.StructureImportSettings;
+import jalview.util.matcher.Condition;
 import jalview.viewmodel.AlignmentViewport;
 
+import java.awt.Color;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -69,6 +80,8 @@ import org.testng.AssertJUnit;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import junit.extensions.PA;
+
 @Test(singleThreaded = true)
 public class Jalview2xmlTests extends Jalview2xmlBase
 {
@@ -247,6 +260,31 @@ public class Jalview2xmlTests extends Jalview2xmlBase
 
   }
 
+  /**
+   * Test for JAL-2223 - multiple mappings in View Mapping report
+   * 
+   * @throws Exception
+   */
+  @Test(groups = { "Functional" })
+  public void noDuplicatePdbMappingsMade() throws Exception
+  {
+    StructureImportSettings.setProcessSecondaryStructure(true);
+    StructureImportSettings.setVisibleChainAnnotation(true);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/exampleFile_2_7.jar", DataSourceType.FILE);
+    assertNotNull(af, "Didn't read in the example file correctly.");
+
+    // locate Jmol viewer
+    // count number of PDB mappings the structure selection manager holds -
+    String pdbFile = af.getCurrentView().getStructureSelectionManager()
+            .findFileForPDBId("1A70");
+    assertEquals(
+            af.getCurrentView().getStructureSelectionManager()
+                    .getMapping(pdbFile).length,
+            2, "Expected only two mappings for 1A70");
+
+  }
+
   @Test(groups = { "Functional" })
   public void viewRefPdbAnnotation() throws Exception
   {
@@ -413,7 +451,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     String afid = af.getViewport().getSequenceSetId();
 
     // remember reference sequence for each panel
-    Map<String, SequenceI> refseqs = new HashMap<String, SequenceI>();
+    Map<String, SequenceI> refseqs = new HashMap<>();
 
     /*
      * mark sequence 2, 3, 4.. in panels 1, 2, 3...
@@ -551,8 +589,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase
      * remember representative and hidden sequences marked 
      * on each panel
      */
-    Map<String, SequenceI> repSeqs = new HashMap<String, SequenceI>();
-    Map<String, List<String>> hiddenSeqNames = new HashMap<String, List<String>>();
+    Map<String, SequenceI> repSeqs = new HashMap<>();
+    Map<String, List<String>> hiddenSeqNames = new HashMap<>();
 
     /*
      * mark sequence 2, 3, 4.. in panels 1, 2, 3...
@@ -568,7 +606,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase
       repIndex = Math.max(repIndex, 1);
       SequenceI repSeq = alignment.getSequenceAt(repIndex);
       repSeqs.put(ap.getViewName(), repSeq);
-      List<String> hiddenNames = new ArrayList<String>();
+      List<String> hiddenNames = new ArrayList<>();
       hiddenSeqNames.put(ap.getViewName(), hiddenNames);
 
       /*
@@ -761,7 +799,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/uniref50.fa", DataSourceType.FILE);
 
-    AlignViewport av = af.getViewport();
+    AlignViewportI av = af.getViewport();
     AlignmentI al = av.getAlignment();
 
     /*
@@ -841,4 +879,217 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     assertTrue(rs.conservationApplied());
     assertEquals(rs.getConservationInc(), 30);
   }
+
+  /**
+   * Test save and reload of feature colour schemes and filter settings
+   * 
+   * @throws IOException
+   */
+  @Test(groups = { "Functional" })
+  public void testStoreAndRecoverFeatureColoursAndFilters()
+          throws IOException
+  {
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            ">Seq1\nACDEFGHIKLM", DataSourceType.PASTE);
+    SequenceI seq1 = af.getViewport().getAlignment().getSequenceAt(0);
+
+    /*
+     * add some features to the sequence
+     */
+    int score = 1;
+    addFeatures(seq1, "type1", score++);
+    addFeatures(seq1, "type2", score++);
+    addFeatures(seq1, "type3", score++);
+    addFeatures(seq1, "type4", score++);
+    addFeatures(seq1, "type5", score++);
+
+    /*
+     * set colour schemes for features
+     */
+    FeatureRenderer fr = af.getFeatureRenderer();
+    fr.findAllFeatures(true);
+
+    // type1: red
+    fr.setColour("type1", new FeatureColour(Color.red));
+
+    // type2: by label
+    FeatureColourI byLabel = new FeatureColour();
+    byLabel.setColourByLabel(true);
+    fr.setColour("type2", byLabel);
+
+    // type3: by score above threshold
+    FeatureColourI byScore = new FeatureColour(Color.BLACK, Color.BLUE, 1,
+            10);
+    byScore.setAboveThreshold(true);
+    byScore.setThreshold(2f);
+    fr.setColour("type3", byScore);
+
+    // type4: by attribute AF
+    FeatureColourI byAF = new FeatureColour();
+    byAF.setColourByLabel(true);
+    byAF.setAttributeName("AF");
+    fr.setColour("type4", byAF);
+
+    // type5: by attribute CSQ:PolyPhen below threshold
+    FeatureColourI byPolyPhen = new FeatureColour(Color.BLACK, Color.BLUE,
+            1, 10);
+    byPolyPhen.setBelowThreshold(true);
+    byPolyPhen.setThreshold(3f);
+    byPolyPhen.setAttributeName("CSQ", "PolyPhen");
+    fr.setColour("type5", byPolyPhen);
+
+    /*
+     * set filters for feature types
+     */
+
+    // filter type1 features by (label contains "x")
+    FeatureMatcherSetI filterByX = new FeatureMatcherSet();
+    filterByX.and(FeatureMatcher.byLabel(Condition.Contains, "x"));
+    fr.setFeatureFilter("type1", filterByX);
+
+    // filter type2 features by (score <= 2.4 and score > 1.1)
+    FeatureMatcherSetI filterByScore = new FeatureMatcherSet();
+    filterByScore.and(FeatureMatcher.byScore(Condition.LE, "2.4"));
+    filterByScore.and(FeatureMatcher.byScore(Condition.GT, "1.1"));
+    fr.setFeatureFilter("type2", filterByScore);
+
+    // filter type3 features by (AF contains X OR CSQ:PolyPhen != 0)
+    FeatureMatcherSetI filterByXY = new FeatureMatcherSet();
+    filterByXY
+            .and(FeatureMatcher.byAttribute(Condition.Contains, "X", "AF"));
+    filterByXY.or(FeatureMatcher.byAttribute(Condition.NE, "0", "CSQ",
+            "PolyPhen"));
+    fr.setFeatureFilter("type3", filterByXY);
+
+    /*
+     * save as Jalview project
+     */
+    File tfile = File.createTempFile("JalviewTest", ".jvp");
+    tfile.deleteOnExit();
+    String filePath = tfile.getAbsolutePath();
+    assertTrue(af.saveAlignment(filePath, FileFormat.Jalview),
+            "Failed to store as a project.");
+
+    /*
+     * close current alignment and load the saved project
+     */
+    af.closeMenuItem_actionPerformed(true);
+    af = null;
+    af = new FileLoader()
+            .LoadFileWaitTillLoaded(filePath, DataSourceType.FILE);
+    assertNotNull(af, "Failed to import new project");
+
+    /*
+     * verify restored feature colour schemes and filters
+     */
+    fr = af.getFeatureRenderer();
+    FeatureColourI fc = fr.getFeatureStyle("type1");
+    assertTrue(fc.isSimpleColour());
+    assertEquals(fc.getColour(), Color.red);
+    fc = fr.getFeatureStyle("type2");
+    assertTrue(fc.isColourByLabel());
+    fc = fr.getFeatureStyle("type3");
+    assertTrue(fc.isGraduatedColour());
+    assertNull(fc.getAttributeName());
+    assertTrue(fc.isAboveThreshold());
+    assertEquals(fc.getThreshold(), 2f);
+    fc = fr.getFeatureStyle("type4");
+    assertTrue(fc.isColourByLabel());
+    assertTrue(fc.isColourByAttribute());
+    assertEquals(fc.getAttributeName(), new String[] { "AF" });
+    fc = fr.getFeatureStyle("type5");
+    assertTrue(fc.isGraduatedColour());
+    assertTrue(fc.isColourByAttribute());
+    assertEquals(fc.getAttributeName(), new String[] { "CSQ", "PolyPhen" });
+    assertTrue(fc.isBelowThreshold());
+    assertEquals(fc.getThreshold(), 3f);
+
+    assertEquals(fr.getFeatureFilter("type1").toStableString(),
+            "Label Contains x");
+    assertEquals(fr.getFeatureFilter("type2").toStableString(),
+            "(Score LE 2.4) AND (Score GT 1.1)");
+    assertEquals(fr.getFeatureFilter("type3").toStableString(),
+            "(AF Contains X) OR (CSQ:PolyPhen NE 0.0)");
+  }
+
+  private void addFeature(SequenceI seq, String featureType, int score)
+  {
+    SequenceFeature sf = new SequenceFeature(featureType, "desc", 1, 2,
+            score, "grp");
+    sf.setValue("AF", score);
+    sf.setValue("CSQ", new HashMap<String, String>()
+    {
+      {
+        put("PolyPhen", Integer.toString(score));
+      }
+    });
+    seq.addSequenceFeature(sf);
+  }
+
+  /**
+   * Adds two features of the given type to the given sequence, also setting the
+   * score as the value of attribute "AF" and sub-attribute "CSQ:PolyPhen"
+   * 
+   * @param seq
+   * @param featureType
+   * @param score
+   */
+  private void addFeatures(SequenceI seq, String featureType, int score)
+  {
+    addFeature(seq, featureType, score++);
+    addFeature(seq, featureType, score);
+  }
+
+  /**
+   * Load an HMM profile to an alignment, and confirm it is correctly restored
+   * when reloaded from project
+   * 
+   * @throws IOException
+   */
+  @Test(groups = { "Functional" })
+  public void testStoreAndRecoverHmmProfile() throws IOException
+  {
+    Desktop.instance.closeAll_actionPerformed(null);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/uniref50.fa", DataSourceType.FILE);
+  
+    AlignViewportI av = af.getViewport();
+    AlignmentI al = av.getAlignment();
+
+    /*
+     * mimic drag and drop of hmm file on to alignment
+     */
+    AlignFrame af2 = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/uniref50.hmm", DataSourceType.FILE);
+    al.insertSequenceAt(0,
+            af2.getViewport().getAlignment().getSequenceAt(0));
+
+    /*
+     * check it loaded in
+     */
+    SequenceI hmmSeq = al.getSequenceAt(0);
+    assertTrue(hmmSeq.hasHMMProfile());
+    HiddenMarkovModel hmm = hmmSeq.getHMM();
+    assertSame(hmm.getConsensusSequence(), hmmSeq);
+
+    /*
+     * save project, close windows, reload project, verify
+     */
+    File tfile = File.createTempFile("testStoreAndRecoverHmmProfile",
+            ".jvp");
+    tfile.deleteOnExit();
+    new Jalview2XML(false).saveState(tfile);
+    Desktop.instance.closeAll_actionPerformed(null);
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
+            DataSourceType.FILE);
+    Assert.assertNotNull(af, "Failed to reload project");
+
+    hmmSeq = al.getSequenceAt(0);
+    assertTrue(hmmSeq.hasHMMProfile());
+    assertSame(hmm.getConsensusSequence(), hmmSeq);
+    Mapping mapToHmmConsensus = (Mapping) PA.getValue(hmm,
+            "mapToHmmConsensus");
+    assertNotNull(mapToHmmConsensus);
+    assertSame(mapToHmmConsensus.getTo(), hmmSeq.getDatasetSequence());
+  }
 }