JAL-4126 failing test - colour scheme appears to be being created and configured...
[jalview.git] / test / jalview / project / Jalview2xmlTests.java
index 3f4ed71..e728ca6 100644 (file)
@@ -27,6 +27,22 @@ import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertSame;
 import static org.testng.Assert.assertTrue;
 
+import java.awt.Color;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.swing.JInternalFrame;
+
+import org.testng.Assert;
+import org.testng.AssertJUnit;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
 import jalview.analysis.scoremodels.SimilarityParams;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
@@ -34,9 +50,14 @@ import jalview.api.FeatureColourI;
 import jalview.api.ViewStyleI;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.GeneLocus;
 import jalview.datamodel.HiddenSequences;
+import jalview.datamodel.Mapping;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.PDBEntry.Type;
+import jalview.datamodel.Sequence.DBModList;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceGroup;
@@ -48,7 +69,6 @@ import jalview.gui.AlignFrame;
 import jalview.gui.AlignViewport;
 import jalview.gui.AlignmentPanel;
 import jalview.gui.Desktop;
-import jalview.gui.FeatureRenderer;
 import jalview.gui.JvOptionPane;
 import jalview.gui.PCAPanel;
 import jalview.gui.PopupMenu;
@@ -68,23 +88,10 @@ import jalview.schemes.RNAHelicesColour;
 import jalview.schemes.StrandColourScheme;
 import jalview.schemes.TCoffeeColourScheme;
 import jalview.structure.StructureImportSettings;
+import jalview.util.MapList;
 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;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.swing.JInternalFrame;
-
-import org.testng.Assert;
-import org.testng.AssertJUnit;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel;
 
 @Test(singleThreaded = true)
 public class Jalview2xmlTests extends Jalview2xmlBase
@@ -109,65 +116,74 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     assertNotNull(af, "Didn't read input file " + inFile);
     int olddsann = countDsAnn(af.getViewport());
     assertTrue(olddsann > 0, "Didn't find any dataset annotations");
-    af.changeColour_actionPerformed(JalviewColourScheme.RNAHelices
-            .toString());
+    af.changeColour_actionPerformed(
+            JalviewColourScheme.RNAHelices.toString());
     assertTrue(
-            af.getViewport().getGlobalColourScheme() instanceof RNAHelicesColour,
+            af.getViewport()
+                    .getGlobalColourScheme() instanceof RNAHelicesColour,
             "Couldn't apply RNA helices colourscheme");
-    assertTrue(af.saveAlignment(tfile, FileFormat.Jalview),
+    af.saveAlignment(tfile, FileFormat.Jalview);
+    assertTrue(af.isSaveAlignmentSuccessful(),
             "Failed to store as a project.");
     af.closeMenuItem_actionPerformed(true);
     af = null;
-    af = new FileLoader()
-            .LoadFileWaitTillLoaded(tfile, DataSourceType.FILE);
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile,
+            DataSourceType.FILE);
     assertNotNull(af, "Failed to import new project");
     int newdsann = countDsAnn(af.getViewport());
     assertEquals(olddsann, newdsann,
             "Differing numbers of dataset sequence annotation\nOriginally "
                     + olddsann + " and now " + newdsann);
-    System.out
-            .println("Read in same number of annotations as originally present ("
+    System.out.println(
+            "Read in same number of annotations as originally present ("
                     + olddsann + ")");
     assertTrue(
 
-    af.getViewport().getGlobalColourScheme() instanceof RNAHelicesColour,
+            af.getViewport()
+                    .getGlobalColourScheme() instanceof RNAHelicesColour,
             "RNA helices colourscheme was not applied on import.");
   }
 
   @Test(groups = { "Functional" })
   public void testTCoffeeScores() throws Exception
   {
-    String inFile = "examples/uniref50.fa", inAnnot = "examples/uniref50.score_ascii";
+    String inFile = "examples/uniref50.fa",
+            inAnnot = "examples/uniref50.score_ascii";
     String tfile = File.createTempFile("JalviewTest", ".jvp")
             .getAbsolutePath();
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
             DataSourceType.FILE);
     assertNotNull(af, "Didn't read input file " + inFile);
     af.loadJalviewDataFile(inAnnot, DataSourceType.FILE, null, null);
-    assertSame(af.getViewport().getGlobalColourScheme().getClass(),
+    AlignViewport viewport = af.getViewport();
+    assertSame(viewport.getGlobalColourScheme().getClass(),
             TCoffeeColourScheme.class, "Didn't set T-coffee colourscheme");
-    assertNotNull(ColourSchemeProperty.getColourScheme(af.getViewport()
-            .getAlignment(), af.getViewport().getGlobalColourScheme()
-            .getSchemeName()), "Recognise T-Coffee score from string");
-
-    assertTrue(af.saveAlignment(tfile, FileFormat.Jalview),
+    assertNotNull(
+            ColourSchemeProperty.getColourScheme(viewport,
+                    viewport.getAlignment(),
+                    viewport.getGlobalColourScheme().getSchemeName()),
+            "Recognise T-Coffee score from string");
+
+    af.saveAlignment(tfile, FileFormat.Jalview);
+    assertTrue(af.isSaveAlignmentSuccessful(),
             "Failed to store as a project.");
     af.closeMenuItem_actionPerformed(true);
     af = null;
-    af = new FileLoader()
-            .LoadFileWaitTillLoaded(tfile, DataSourceType.FILE);
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile,
+            DataSourceType.FILE);
     assertNotNull(af, "Failed to import new project");
     assertSame(af.getViewport().getGlobalColourScheme().getClass(),
             TCoffeeColourScheme.class,
             "Didn't set T-coffee colourscheme for imported project.");
-    System.out
-            .println("T-Coffee score shading successfully recovered from project.");
+    System.out.println(
+            "T-Coffee score shading successfully recovered from project.");
   }
 
   @Test(groups = { "Functional" })
   public void testColourByAnnotScores() throws Exception
   {
-    String inFile = "examples/uniref50.fa", inAnnot = "examples/testdata/uniref50_iupred.jva";
+    String inFile = "examples/uniref50.fa",
+            inAnnot = "examples/testdata/uniref50_iupred.jva";
     String tfile = File.createTempFile("JalviewTest", ".jvp")
             .getAbsolutePath();
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
@@ -178,12 +194,12 @@ public class Jalview2xmlTests extends Jalview2xmlBase
             .getSequenceAt(0).getAnnotation("IUPredWS (Short)");
     assertTrue(
 
-    aa != null && aa.length > 0,
+            aa != null && aa.length > 0,
             "Didn't find any IUPred annotation to use to shade alignment.");
     AnnotationColourGradient cs = new AnnotationColourGradient(aa[0], null,
             AnnotationColourGradient.ABOVE_THRESHOLD);
-    AnnotationColourGradient gcs = new AnnotationColourGradient(aa[0],
-            null, AnnotationColourGradient.BELOW_THRESHOLD);
+    AnnotationColourGradient gcs = new AnnotationColourGradient(aa[0], null,
+            AnnotationColourGradient.BELOW_THRESHOLD);
     cs.setSeqAssociated(true);
     gcs.setSeqAssociated(true);
     af.changeColour(cs);
@@ -195,19 +211,20 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     sg.addSequence(af.getViewport().getAlignment().getSequenceAt(1), false);
     sg.addSequence(af.getViewport().getAlignment().getSequenceAt(2), true);
     af.alignPanel.alignmentChanged();
-    assertTrue(af.saveAlignment(tfile, FileFormat.Jalview),
+    af.saveAlignment(tfile, FileFormat.Jalview);
+    assertTrue(af.isSaveAlignmentSuccessful(),
             "Failed to store as a project.");
     af.closeMenuItem_actionPerformed(true);
     af = null;
-    af = new FileLoader()
-            .LoadFileWaitTillLoaded(tfile, DataSourceType.FILE);
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile,
+            DataSourceType.FILE);
     assertNotNull(af, "Failed to import new project");
 
     // check for group and alignment colourschemes
 
     ColourSchemeI _rcs = af.getViewport().getGlobalColourScheme();
-    ColourSchemeI _rgcs = af.getViewport().getAlignment().getGroups()
-            .get(0).getColourScheme();
+    ColourSchemeI _rgcs = af.getViewport().getAlignment().getGroups().get(0)
+            .getColourScheme();
     assertNotNull(_rcs, "Didn't recover global colourscheme");
     assertTrue(_rcs instanceof AnnotationColourGradient,
             "Didn't recover annotation colour global scheme");
@@ -217,8 +234,9 @@ public class Jalview2xmlTests extends Jalview2xmlBase
 
     boolean diffseqcols = false, diffgseqcols = false;
     SequenceI[] sqs = af.getViewport().getAlignment().getSequencesArray();
-    for (int p = 0, pSize = af.getViewport().getAlignment().getWidth(); p < pSize
-            && (!diffseqcols || !diffgseqcols); p++)
+    for (int p = 0,
+            pSize = af.getViewport().getAlignment().getWidth(); p < pSize
+                    && (!diffseqcols || !diffgseqcols); p++)
     {
       if (_rcs.findColour(sqs[0].getCharAt(p), p, sqs[0], null, 0f) != _rcs
               .findColour(sqs[5].getCharAt(p), p, sqs[5], null, 0f))
@@ -227,8 +245,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase
       }
     }
     assertTrue(diffseqcols, "Got Different sequence colours");
-    System.out
-            .println("Per sequence colourscheme (Background) successfully applied and recovered.");
+    System.out.println(
+            "Per sequence colourscheme (Background) successfully applied and recovered.");
 
     assertNotNull(_rgcs, "Didn't recover group colourscheme");
     assertTrue(_rgcs instanceof AnnotationColourGradient,
@@ -237,25 +255,27 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     assertTrue(__rcs.isSeqAssociated(),
             "Group Annotation colourscheme wasn't sequence associated");
 
-    for (int p = 0, pSize = af.getViewport().getAlignment().getWidth(); p < pSize
-            && (!diffseqcols || !diffgseqcols); p++)
+    for (int p = 0,
+            pSize = af.getViewport().getAlignment().getWidth(); p < pSize
+                    && (!diffseqcols || !diffgseqcols); p++)
     {
-      if (_rgcs.findColour(sqs[1].getCharAt(p), p, sqs[1], null, 0f) != _rgcs
-              .findColour(sqs[2].getCharAt(p), p, sqs[2], null, 0f))
+      if (_rgcs.findColour(sqs[1].getCharAt(p), p, sqs[1], null,
+              0f) != _rgcs.findColour(sqs[2].getCharAt(p), p, sqs[2], null,
+                      0f))
       {
         diffgseqcols = true;
       }
     }
     assertTrue(diffgseqcols, "Got Different group sequence colours");
-    System.out
-            .println("Per sequence (Group) colourscheme successfully applied and recovered.");
+    System.out.println(
+            "Per sequence (Group) colourscheme successfully applied and recovered.");
   }
 
   @Test(groups = { "Functional" })
   public void gatherViewsHere() throws Exception
   {
-    int origCount = Desktop.getAlignFrames() == null ? 0 : Desktop
-            .getAlignFrames().length;
+    int origCount = Desktop.getAlignFrames() == null ? 0
+            : Desktop.getAlignFrames().length;
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/exampleFile_2_7.jar", DataSourceType.FILE);
     assertNotNull(af, "Didn't read in the example file correctly.");
@@ -336,14 +356,14 @@ public class Jalview2xmlTests extends Jalview2xmlBase
           sq.findPosition(p);
           try
           {
-            assertTrue(
-                    (alaa.annotations[p] == null && refan.annotations[p] == null)
-                            || alaa.annotations[p].value == refan.annotations[p].value,
+            assertTrue((alaa.annotations[p] == null
+                    && refan.annotations[p] == null)
+                    || alaa.annotations[p].value == refan.annotations[p].value,
                     "Mismatch at alignment position " + p);
           } catch (NullPointerException q)
           {
-            Assert.fail("Mismatch of alignment annotations at position "
-                    + p + " Ref seq ann: " + refan.annotations[p]
+            Assert.fail("Mismatch of alignment annotations at position " + p
+                    + " Ref seq ann: " + refan.annotations[p]
                     + " alignment " + alaa.annotations[p]);
           }
         }
@@ -378,10 +398,10 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     AssertJUnit.assertFalse(structureStyle.sameStyle(groupStyle));
 
     groups.getAlignViewport().setViewStyle(structureStyle);
-    AssertJUnit.assertFalse(groupStyle.sameStyle(groups.getAlignViewport()
-            .getViewStyle()));
-    Assert.assertTrue(structureStyle.sameStyle(groups.getAlignViewport()
-            .getViewStyle()));
+    AssertJUnit.assertFalse(
+            groupStyle.sameStyle(groups.getAlignViewport().getViewStyle()));
+    Assert.assertTrue(structureStyle
+            .sameStyle(groups.getAlignViewport().getViewStyle()));
 
   }
 
@@ -402,9 +422,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase
 
     // check FileLoader returned a reference to the one alignFrame that is
     // actually on the Desktop
-    assertSame(
-            af,
-            Desktop.getAlignFrameFor(af.getViewport()),
+    assertSame(af, Desktop.getAlignFrameFor(af.getViewport()),
             "Jalview2XML.loadAlignFrame() didn't return correct AlignFrame reference for multiple view window");
 
     Desktop.explodeViews(af);
@@ -431,11 +449,11 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
             DataSourceType.FILE);
     Assert.assertNotNull(af);
-    Assert.assertEquals(
-            Desktop.getAlignFrames().length,
-            Desktop.getAlignmentPanels(af.getViewport().getSequenceSetId()).length);
-    Assert.assertEquals(
-            Desktop.getAlignmentPanels(af.getViewport().getSequenceSetId()).length,
+    Assert.assertEquals(Desktop.getAlignFrames().length,
+            Desktop.getAlignmentPanels(
+                    af.getViewport().getSequenceSetId()).length);
+    Assert.assertEquals(Desktop
+            .getAlignmentPanels(af.getViewport().getSequenceSetId()).length,
             oldviews);
   }
 
@@ -537,8 +555,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     assertTrue(Jalview2XML.isVersionStringLaterThan(null, "Test"));
     assertTrue(Jalview2XML.isVersionStringLaterThan(null, "TEST"));
     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", "Test"));
-    assertTrue(Jalview2XML
-            .isVersionStringLaterThan(null, "Automated Build"));
+    assertTrue(
+            Jalview2XML.isVersionStringLaterThan(null, "Automated Build"));
     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3",
             "Automated Build"));
     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3",
@@ -647,8 +665,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase
 
       n++;
     }
-    File tfile = File
-            .createTempFile("testStoreAndRecoverGroupReps", ".jvp");
+    File tfile = File.createTempFile("testStoreAndRecoverGroupReps",
+            ".jvp");
     try
     {
       new Jalview2XML(false).saveState(tfile);
@@ -687,9 +705,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase
        */
       List<String> hidden = hiddenSeqNames.get(ap.getViewName());
       HiddenSequences hs = alignment.getHiddenSequences();
-      assertEquals(
-              hidden.size(),
-              hs.getSize(),
+      assertEquals(hidden.size(), hs.getSize(),
               "wrong number of restored hidden sequences in "
                       + ap.getViewName());
     }
@@ -731,14 +747,18 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     pdbEntries[1] = new PDBEntry("3W5V", "B", Type.PDB, testFile);
     pdbEntries[2] = new PDBEntry("3W5V", "C", Type.PDB, testFile);
     pdbEntries[3] = new PDBEntry("3W5V", "D", Type.PDB, testFile);
-    Assert.assertEquals(seqs[0].getDatasetSequence().getAllPDBEntries()
-            .get(0), pdbEntries[0]);
-    Assert.assertEquals(seqs[1].getDatasetSequence().getAllPDBEntries()
-            .get(0), pdbEntries[1]);
-    Assert.assertEquals(seqs[2].getDatasetSequence().getAllPDBEntries()
-            .get(0), pdbEntries[2]);
-    Assert.assertEquals(seqs[3].getDatasetSequence().getAllPDBEntries()
-            .get(0), pdbEntries[3]);
+    Assert.assertEquals(
+            seqs[0].getDatasetSequence().getAllPDBEntries().get(0),
+            pdbEntries[0]);
+    Assert.assertEquals(
+            seqs[1].getDatasetSequence().getAllPDBEntries().get(0),
+            pdbEntries[1]);
+    Assert.assertEquals(
+            seqs[2].getDatasetSequence().getAllPDBEntries().get(0),
+            pdbEntries[2]);
+    Assert.assertEquals(
+            seqs[3].getDatasetSequence().getAllPDBEntries().get(0),
+            pdbEntries[3]);
 
     File tfile = File.createTempFile("testStoreAndRecoverPDBEntry", ".jvp");
     try
@@ -786,7 +806,94 @@ public class Jalview2xmlTests extends Jalview2xmlBase
               "Mismatch PDBEntry 'Type'");
       Assert.assertNotNull(recov.getFile(),
               "Recovered PDBEntry should have a non-null file entry");
+      Assert.assertEquals(
+              recov.getFile().toLowerCase(Locale.ENGLISH)
+                      .lastIndexOf("pdb"),
+              recov.getFile().length() - 3,
+              "Recovered PDBEntry file should have PDB suffix");
+    }
+  }
+
+  /**
+   * Configure an alignment and a sub-group each with distinct colour schemes,
+   * Conservation and PID thresholds, and confirm these are restored from the
+   * saved project.
+   * 
+   * @throws IOException
+   */
+  @Test(groups = { "Functional" })
+  public void testStoreAndRecoverAnnotationRowElementColours()
+          throws IOException
+  {
+    Desktop.instance.closeAll_actionPerformed(null);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded("SEQ\tMNQ",
+            DataSourceType.PASTE);
+
+    AlignViewport av = af.getViewport();
+    AlignmentI al = av.getAlignment();
+    SequenceI fsq;
+    fsq = al.getSequenceAt(0);
+    Annotation annots[] = new Annotation[fsq.getLength()];
+    AlignmentAnnotation ala = new AlignmentAnnotation("Colour", "Annots",
+            annots);
+    annots[0] = new Annotation(1.0f);
+    annots[1] = new Annotation(2.0f);
+    annots[2] = new Annotation(3.0f);
+    annots[0].colour = Color.RED;
+    annots[1].colour = Color.GREEN;
+    annots[2].colour = Color.BLUE;
+    ala.validateRangeAndDisplay();
+    al.getSequenceAt(0).addAlignmentAnnotation(ala);
+    al.addAnnotation(ala);
+    /*
+     * and colour by annotation
+     */
+    AnnotationColourGradient acg = new AnnotationColourGradient(ala,
+            af.alignPanel.av.getGlobalColourScheme(), 0);
+    acg.setSeqAssociated(true);
+    acg.setPredefinedColours(true);
+    af.changeColour(acg);
+    Color seqcol[] = new Color[3];
+    for (int iStart=fsq.findIndex(fsq.getStart()),i=0;i<3;i++) {
+      seqcol[i] = af.alignPanel.getSeqPanel().seqCanvas.getSequenceRenderer().getResidueColour(fsq, iStart+i, null);
     }
+    /*
+     * save project, close windows, reload project, verify
+     */
+    File tfile = File.createTempFile(
+            "testStoreAndRecoverAnnotRowElemColors", ".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");
+    /*
+     * verify alignment annotation has colors
+     */
+    av = af.getViewport();
+    
+    ColourSchemeI loadedCscheme = av.getGlobalColourScheme();
+    Assert.assertTrue(loadedCscheme instanceof AnnotationColourGradient,"Didn't apply Annotation colour gradient");
+    acg = (AnnotationColourGradient) loadedCscheme;
+    assertTrue(acg.isSeqAssociated());
+    assertTrue(acg.isPredefinedColours());
+
+    al = av.getAlignment();
+    fsq = al.getSequenceAt(0);
+    ala = fsq.getAnnotation()[0];
+    Assert.assertNotNull(ala, "No annotation row recovered");
+    Assert.assertNotNull(ala.annotations);
+    for (int iStart = al.getSequenceAt(0)
+            .findIndex(al.getSequenceAt(0).getStart()), i = 0; i < 3; i++)
+    {
+      Assert.assertTrue(ala.annotations[i].colour!=null);
+      Assert.assertTrue(ala.annotations[i].colour.equals(annots[i].colour));
+      Color newseqcol = af.alignPanel.getSeqPanel().seqCanvas.getSequenceRenderer().getResidueColour(fsq, iStart+i, null);
+      Assert.assertTrue(seqcol[i].equals(newseqcol),"Sequence shading is different");
+
+    }
+    
   }
 
   /**
@@ -809,6 +916,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     /*
      * Colour alignment by Buried Index, Above 10% PID, By Conservation 20%
      */
+    av.setColourAppliesToAllGroups(false);
     af.changeColour_actionPerformed(JalviewColourScheme.Buried.toString());
     assertTrue(av.getGlobalColourScheme() instanceof BuriedColourScheme);
     af.abovePIDThreshold_actionPerformed(true);
@@ -827,15 +935,18 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     /*
      * create a group with Strand colouring, 30% Conservation
      * and 40% PID threshold
+     * (notice menu action applies to selection group even if mouse click
+     * is at a sequence not in the group)
      */
     SequenceGroup sg = new SequenceGroup();
     sg.addSequence(al.getSequenceAt(0), false);
     sg.setStartRes(15);
     sg.setEndRes(25);
     av.setSelectionGroup(sg);
-    PopupMenu popupMenu = new PopupMenu(af.alignPanel, null, null);
-    popupMenu.changeColour_actionPerformed(JalviewColourScheme.Strand
-            .toString());
+    PopupMenu popupMenu = new PopupMenu(af.alignPanel, al.getSequenceAt(2),
+            null);
+    popupMenu.changeColour_actionPerformed(
+            JalviewColourScheme.Strand.toString());
     assertTrue(sg.getColourScheme() instanceof StrandColourScheme);
     assertEquals(al.getGroups().size(), 1);
     assertSame(al.getGroups().get(0), sg);
@@ -909,7 +1020,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     /*
      * set colour schemes for features
      */
-    FeatureRenderer fr = af.getFeatureRenderer();
+    FeatureRendererModel fr = af.getFeatureRenderer();
     fr.findAllFeatures(true);
 
     // type1: red
@@ -921,8 +1032,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     fr.setColour("type2", byLabel);
 
     // type3: by score above threshold
-    FeatureColourI byScore = new FeatureColour(Color.BLACK, Color.BLUE, 1,
-            10);
+    FeatureColourI byScore = new FeatureColour(null, Color.BLACK,
+            Color.BLUE, null, 1, 10);
     byScore.setAboveThreshold(true);
     byScore.setThreshold(2f);
     fr.setColour("type3", byScore);
@@ -934,8 +1045,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     fr.setColour("type4", byAF);
 
     // type5: by attribute CSQ:PolyPhen below threshold
-    FeatureColourI byPolyPhen = new FeatureColour(Color.BLACK, Color.BLUE,
-            1, 10);
+    FeatureColourI byPolyPhen = new FeatureColour(null, Color.BLACK,
+            Color.BLUE, null, 1, 10);
     byPolyPhen.setBelowThreshold(true);
     byPolyPhen.setThreshold(3f);
     byPolyPhen.setAttributeName("CSQ", "PolyPhen");
@@ -970,7 +1081,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     File tfile = File.createTempFile("JalviewTest", ".jvp");
     tfile.deleteOnExit();
     String filePath = tfile.getAbsolutePath();
-    assertTrue(af.saveAlignment(filePath, FileFormat.Jalview),
+    af.saveAlignment(filePath, FileFormat.Jalview);
+    assertTrue(af.isSaveAlignmentSuccessful(),
             "Failed to store as a project.");
 
     /*
@@ -978,8 +1090,8 @@ public class Jalview2xmlTests extends Jalview2xmlBase
      */
     af.closeMenuItem_actionPerformed(true);
     af = null;
-    af = new FileLoader()
-            .LoadFileWaitTillLoaded(filePath, DataSourceType.FILE);
+    af = new FileLoader().LoadFileWaitTillLoaded(filePath,
+            DataSourceType.FILE);
     assertNotNull(af, "Failed to import new project");
 
     /*
@@ -1012,7 +1124,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     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)");
+            "(AF Contains X) OR (CSQ:PolyPhen NE 0)");
   }
 
   private void addFeature(SequenceI seq, String featureType, int score)
@@ -1168,4 +1280,83 @@ public class Jalview2xmlTests extends Jalview2xmlBase
                     .getAlignViewport(),
             "Didn't restore correct view association for the PCA view");
   }
+
+  /**
+   * Test save and reload of DBRefEntry including GeneLocus in project
+   * 
+   * @throws Exception
+   */
+  @Test(groups = { "Functional" })
+  public void testStoreAndRecoverGeneLocus() throws Exception
+  {
+    Desktop.instance.closeAll_actionPerformed(null);
+    String seqData = ">P30419\nACDE\n>X1235\nGCCTGTGACGAA";
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqData,
+            DataSourceType.PASTE);
+    assertNotNull(af, "Didn't read in the example file correctly.");
+
+    AlignmentViewPanel ap = Desktop.getAlignmentPanels(null)[0];
+    SequenceI pep = ap.getAlignment().getSequenceAt(0);
+    SequenceI cds = ap.getAlignment().getSequenceAt(1);
+
+    /*
+     * give 'protein' a dbref to self, a dbref with map to CDS,
+     * and a dbref with map to gene 'locus'
+     */
+    DBRefEntry dbref1 = new DBRefEntry("Uniprot", "1", "P30419", null);
+    pep.addDBRef(dbref1);
+    Mapping cdsmap = new Mapping(cds,
+            new MapList(new int[]
+            { 1, 4 }, new int[] { 1, 12 }, 1, 3));
+    DBRefEntry dbref2 = new DBRefEntry("EMBLCDS", "2", "X1235", cdsmap);
+    pep.addDBRef(dbref2);
+    Mapping locusmap = new Mapping(null,
+            new MapList(new int[]
+            { 1, 4 }, new int[] { 2674123, 2674135 }, 1, 3));
+    DBRefEntry dbref3 = new GeneLocus("human", "GRCh38", "5", locusmap);
+    pep.addDBRef(dbref3);
+
+    File tfile = File.createTempFile("testStoreAndRecoverGeneLocus",
+            ".jvp");
+    try
+    {
+      new Jalview2XML(false).saveState(tfile);
+    } catch (Throwable e)
+    {
+      Assert.fail("Didn't save the state", e);
+    }
+    Desktop.instance.closeAll_actionPerformed(null);
+
+    new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
+            DataSourceType.FILE);
+    AlignmentViewPanel rap = Desktop.getAlignmentPanels(null)[0];
+    SequenceI rpep = rap.getAlignment().getSequenceAt(0);
+    DBModList<DBRefEntry> dbrefs = rpep.getDBRefs();
+    assertEquals(rpep.getName(), "P30419");
+    assertEquals(dbrefs.size(), 3);
+    DBRefEntry dbRef = dbrefs.get(0);
+    assertFalse(dbRef instanceof GeneLocus);
+    assertNull(dbRef.getMap());
+    assertEquals(dbRef, dbref1);
+
+    /*
+     * restored dbrefs with mapping have a different 'map to'
+     * sequence but otherwise match the original dbrefs
+     */
+    dbRef = dbrefs.get(1);
+    assertFalse(dbRef instanceof GeneLocus);
+    assertTrue(dbRef.equalRef(dbref2));
+    assertNotNull(dbRef.getMap());
+    SequenceI rcds = rap.getAlignment().getSequenceAt(1);
+    assertSame(dbRef.getMap().getTo(), rcds);
+    // compare MapList but not map.to
+    assertEquals(dbRef.getMap().getMap(), dbref2.getMap().getMap());
+
+    /*
+     * GeneLocus map.to is null so can compare Mapping objects
+     */
+    dbRef = dbrefs.get(2);
+    assertTrue(dbRef instanceof GeneLocus);
+    assertEquals(dbRef, dbref3);
+  }
 }