JAL-4343 patch for JAL-4347 uniprot non-pos feature parsing
[jalview.git] / test / jalview / ws / dbsources / UniprotTest.java
index ec637fe..a95d520 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9)
- * Copyright (C) 2015 The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
  * This file is part of Jalview.
  * 
  */
 package jalview.ws.dbsources;
 
+import static org.testng.Assert.assertFalse;
 import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertTrue;
 
-import jalview.datamodel.PDBEntry;
-import jalview.datamodel.SequenceFeature;
-import jalview.datamodel.UniprotEntry;
-
-import java.io.Reader;
-import java.io.StringReader;
-import java.util.Vector;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.util.List;
 
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.gui.JvOptionPane;
+import jalview.util.DBRefUtils;
+import jalview.xml.binding.uniprot.DbReferenceType;
+import jalview.xml.binding.uniprot.Entry;
+import jalview.xml.binding.uniprot.FeatureType;
+import jalview.xml.binding.uniprot.LocationType;
+import jalview.xml.binding.uniprot.PositionType;
+
 public class UniprotTest
 {
+
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+  }
+
   // adapted from http://www.uniprot.org/uniprot/A9CKP4.xml
   private static final String UNIPROT_XML = "<?xml version='1.0' encoding='UTF-8'?>"
-          + "<uniprot>"
+          + "<uniprot xmlns=\"http://uniprot.org/uniprot\">"
           + "<entry dataset=\"TrEMBL\" created=\"2008-01-15\" modified=\"2015-03-04\" version=\"38\">"
           + "<accession>A9CKP4</accession>"
-          + "<accession>A9CKP5</accession>"
-          + "<name>A9CKP4_AGRT5</name>"
+          + "<accession>A9CKP5</accession>" + "<name>A9CKP4_AGRT5</name>"
           + "<name>A9CKP4_AGRT6</name>"
-          + "<protein><recommendedName><fullName>Mitogen-activated protein kinase 13</fullName><fullName>Henry</fullName></recommendedName></protein>"
+          + "<protein><recommendedName><fullName>Mitogen-activated protein kinase 13</fullName></recommendedName></protein>"
           + "<dbReference type=\"PDB\" id=\"2FSQ\"><property type=\"method\" value=\"X-ray\"/><property type=\"resolution\" value=\"1.40\"/></dbReference>"
           + "<dbReference type=\"PDBsum\" id=\"2FSR\"/>"
+          + "<dbReference type=\"EMBL\" id=\"AE007869\"><property type=\"protein sequence ID\" value=\"AAK85932.1\"/><property type=\"molecule type\" value=\"Genomic_DNA\"/></dbReference>"
           + "<feature type=\"signal peptide\" evidence=\"7\"><location><begin position=\"1\"/><end position=\"18\"/></location></feature>"
           + "<feature type=\"propeptide\" description=\"Activation peptide\" id=\"PRO_0000027399\" evidence=\"9 16 17 18\"><location><begin position=\"19\"/><end position=\"20\"/></location></feature>"
           + "<feature type=\"chain\" description=\"Granzyme B\" id=\"PRO_0000027400\"><location><begin position=\"21\"/><end position=\"247\"/></location></feature>"
+          + "<feature type=\"sequence variant\"><original>M</original><variation>L</variation><location><position position=\"41\"/></location></feature>"
+          + "<feature type=\"sequence variant\" description=\"Pathogenic\"><original>M</original><variation>L</variation><location><position position=\"41\"/></location></feature>"
+          + "<feature type=\"sequence variant\" description=\"Pathogenic\"><original>M</original><location><position position=\"41\"/></location></feature>"
+          + "<feature type=\"sequence variant\" description=\"Foo\"><variation>L</variation><variation>LMV</variation><original>M</original><location><position position=\"42\"/></location></feature>"
+          + "<feature type=\"sequence variant\" description=\"Foo\"><variation>LL</variation><variation>LMV</variation><original>ML</original><location><begin position=\"42\"/><end position=\"43\"/></location></feature>"
+          + "<feature type=\"sequence variant\" description=\"Foo Too\"><variation>LL</variation><variation>LMVK</variation><original>MLML</original><location><begin position=\"42\"/><end position=\"45\"/></location></feature>"
           + "<sequence length=\"10\" mass=\"27410\" checksum=\"8CB760AACF88FE6C\" modified=\"2008-01-15\" version=\"1\">MHAPL VSKDL</sequence></entry>"
           + "</uniprot>";
 
   /**
    * Test the method that unmarshals XML to a Uniprot model
+   * 
+   * @throws UnsupportedEncodingException
    */
   @Test(groups = { "Functional" })
-  public void testGetUniprotEntries()
+  public void testGetUniprotEntries() throws UnsupportedEncodingException
   {
     Uniprot u = new Uniprot();
-    Reader reader = new StringReader(UNIPROT_XML);
-    Vector<UniprotEntry> entries = u.getUniprotEntries(reader);
+    InputStream is = new ByteArrayInputStream(UNIPROT_XML.getBytes());
+    List<Entry> entries = u.getUniprotEntries(is);
     assertEquals(1, entries.size());
-    UniprotEntry entry = entries.get(0);
+    Entry entry = entries.get(0);
     assertEquals(2, entry.getName().size());
     assertEquals("A9CKP4_AGRT5", entry.getName().get(0));
     assertEquals("A9CKP4_AGRT6", entry.getName().get(1));
@@ -70,74 +102,560 @@ public class UniprotTest
     assertEquals("A9CKP4", entry.getAccession().get(0));
     assertEquals("A9CKP5", entry.getAccession().get(1));
 
-    /*
-     * UniprotSequence drops any space characters
-     */
-    assertEquals("MHAPLVSKDL", entry.getUniprotSequence().getContent());
+    assertEquals("MHAPL VSKDL", entry.getSequence().getValue());
 
-    assertEquals(2, entry.getProtein().getName().size());
     assertEquals("Mitogen-activated protein kinase 13", entry.getProtein()
-            .getName().get(0));
-    assertEquals("Henry", entry.getProtein().getName().get(1));
+            .getRecommendedName().getFullName().getValue());
 
     /*
      * Check sequence features
      */
-    Vector<SequenceFeature> features = entry.getFeature();
-    assertEquals(3, features.size());
-    SequenceFeature sf = features.get(0);
+    List<FeatureType> features = entry.getFeature();
+    assertEquals(9, features.size());
+    FeatureType sf = features.get(0);
     assertEquals("signal peptide", sf.getType());
     assertNull(sf.getDescription());
     assertNull(sf.getStatus());
-    assertEquals(1, sf.getPosition()); // wrong - Castor bug??
-    assertEquals(1, sf.getBegin());
-    assertEquals(18, sf.getEnd());
+    assertNull(sf.getLocation().getPosition());
+    assertEquals(1, sf.getLocation().getBegin().getPosition().intValue());
+    assertEquals(18, sf.getLocation().getEnd().getPosition().intValue());
     sf = features.get(1);
     assertEquals("propeptide", sf.getType());
     assertEquals("Activation peptide", sf.getDescription());
-    assertEquals(19, sf.getPosition()); // wrong - Castor bug??
-    assertEquals(19, sf.getBegin());
-    assertEquals(20, sf.getEnd());
+    assertNull(sf.getLocation().getPosition());
+    assertEquals(19, sf.getLocation().getBegin().getPosition().intValue());
+    assertEquals(20, sf.getLocation().getEnd().getPosition().intValue());
     sf = features.get(2);
     assertEquals("chain", sf.getType());
     assertEquals("Granzyme B", sf.getDescription());
-    assertEquals(21, sf.getPosition()); // wrong - Castor bug??
-    assertEquals(21, sf.getBegin());
-    assertEquals(247, sf.getEnd());
+    assertNull(sf.getLocation().getPosition());
+    assertEquals(21, sf.getLocation().getBegin().getPosition().intValue());
+    assertEquals(247, sf.getLocation().getEnd().getPosition().intValue());
+
+    sf = features.get(3);
+    assertEquals("sequence variant", sf.getType());
+    assertNull(sf.getDescription());
+    assertEquals(41,
+            sf.getLocation().getPosition().getPosition().intValue());
+    assertNull(sf.getLocation().getBegin());
+    assertNull(sf.getLocation().getEnd());
+
+    sf = features.get(4);
+    assertEquals("sequence variant", sf.getType());
+    assertEquals("Pathogenic", sf.getDescription());
+    assertEquals(41,
+            sf.getLocation().getPosition().getPosition().intValue());
+    assertNull(sf.getLocation().getBegin());
+    assertNull(sf.getLocation().getEnd());
+
+    sf = features.get(5);
+    assertEquals("sequence variant", sf.getType());
+    assertEquals("Pathogenic", sf.getDescription());
+    assertEquals(41,
+            sf.getLocation().getPosition().getPosition().intValue());
+    assertNull(sf.getLocation().getBegin());
+    assertNull(sf.getLocation().getEnd());
+
+    sf = features.get(6);
+    assertEquals("sequence variant", sf.getType());
+    assertEquals("Foo", sf.getDescription());
+    assertEquals(42,
+            sf.getLocation().getPosition().getPosition().intValue());
+    assertNull(sf.getLocation().getBegin());
+    assertNull(sf.getLocation().getEnd());
+    Assert.assertEquals(Uniprot.getDescription(sf), "<html>p.Met42Leu"
+            + "<br/>&nbsp;&nbsp;" + "p.Met42LeuMetVal Foo</html>");
+
+    sf = features.get(7);
+    assertNull(sf.getLocation().getPosition());
+    assertEquals(42, sf.getLocation().getBegin().getPosition().intValue());
+    assertEquals(43, sf.getLocation().getEnd().getPosition().intValue());
+    Assert.assertEquals(Uniprot.getDescription(sf), "<html>p.MetLeu42LeuLeu"
+            + "<br/>&nbsp;&nbsp;" + "p.MetLeu42LeuMetVal Foo</html>");
+
+    sf = features.get(8);
+    assertNull(sf.getLocation().getPosition());
+    assertEquals(42, sf.getLocation().getBegin().getPosition().intValue());
+    assertEquals(45, sf.getLocation().getEnd().getPosition().intValue());
+    Assert.assertEquals(Uniprot.getDescription(sf), "<html>p.MLML42LeuLeu"
+            + "<br/>&nbsp;&nbsp;" + "p.MLML42LMVK Foo Too</html>");
 
     /*
      * Check cross-references
      */
-    Vector<PDBEntry> xrefs = entry.getDbReference();
-    assertEquals(2, xrefs.size());
+    List<DbReferenceType> xrefs = entry.getDbReference();
+    assertEquals(3, xrefs.size());
 
-    PDBEntry xref = xrefs.get(0);
+    DbReferenceType xref = xrefs.get(0);
     assertEquals("2FSQ", xref.getId());
     assertEquals("PDB", xref.getType());
-    assertEquals(2, xref.getProperty().size());
-    assertEquals("X-ray", xref.getProperty().get("method"));
-    assertEquals("1.40", xref.getProperty().get("resolution"));
+    assertEquals("X-ray",
+            Uniprot.getProperty(xref.getProperty(), "method"));
+    assertEquals("1.40",
+            Uniprot.getProperty(xref.getProperty(), "resolution"));
 
     xref = xrefs.get(1);
     assertEquals("2FSR", xref.getId());
     assertEquals("PDBsum", xref.getType());
-    assertNull(xref.getProperty());
+    assertTrue(xref.getProperty().isEmpty());
+
+    xref = xrefs.get(2);
+    assertEquals("AE007869", xref.getId());
+    assertEquals("EMBL", xref.getType());
+    assertEquals("AAK85932.1",
+            Uniprot.getProperty(xref.getProperty(), "protein sequence ID"));
+    assertEquals("Genomic_DNA",
+            Uniprot.getProperty(xref.getProperty(), "molecule type"));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetUniprotSequence() throws UnsupportedEncodingException
+  {
+    InputStream is = new ByteArrayInputStream(UNIPROT_XML.getBytes());
+    Entry entry = new Uniprot().getUniprotEntries(is).get(0);
+    SequenceI seq = new Uniprot().uniprotEntryToSequence(entry);
+    assertNotNull(seq);
+    assertEquals(6, seq.getDBRefs().size()); // 2*Uniprot, PDB, PDBsum, 2*EMBL
+    assertEquals(seq.getSequenceAsString(),
+            seq.createDatasetSequence().getSequenceAsString());
+    assertEquals(2, seq.getPrimaryDBRefs().size());
+    List<DBRefEntry> res = DBRefUtils.searchRefs(seq.getPrimaryDBRefs(),
+            "A9CKP4");
+    assertEquals(1, res.size());
+    assertTrue(res.get(0).isCanonical());
+    res = DBRefUtils.searchRefsForSource(seq.getDBRefs(),
+            DBRefSource.UNIPROT);
+    assertEquals(2, res.size());
+    /*
+     * NB this test fragile - relies on ordering being preserved
+     */
+    assertTrue(res.get(0).isCanonical());
+    assertFalse(res.get(1).isCanonical());
+
+    // check version is preserved for EMBLCDS
+    res = DBRefUtils.searchRefs(seq.getDBRefs(), "AAK85932");
+    assertEquals(1, res.size());
+    // Ideally we would expect AAK85932.1 -> AAK85932
+    // assertTrue("1".equals(res.get(0).getVersion()));
+    // but it also passes through DBrefUtils.ensurePrimaries which adds
+    // (promoted) to the version string
+    // FIXME: Jim needs to specify what (promoted) means !! - or perhaps we just
+    // ignore it !
+    assertEquals("1 (promoted)", (res.get(0).getVersion()));
+
+    List<SequenceFeature> features = seq.getFeatures().findFeatures(41, 41,
+            "sequence variant");
+    // verify single position features are parsed correctly JAL-4347
+    assertNotNull(features);
+    assertEquals(3, features.size());
+
+  }
+
+  /**
+   * Test the method that formats the sequence id
+   * 
+   * @throws UnsupportedEncodingException
+   */
+  @Test(groups = { "Functional" })
+  public void testGetUniprotEntryId() throws UnsupportedEncodingException
+  {
+    InputStream is = new ByteArrayInputStream(UNIPROT_XML.getBytes());
+    Entry entry = new Uniprot().getUniprotEntries(is).get(0);
+
+    /*
+     * name formatted with Uniprot Entry name
+     */
+    String expectedName = "A9CKP4_AGRT5|A9CKP4_AGRT6";
+    assertEquals(expectedName, Uniprot.getUniprotEntryId(entry));
   }
 
   /**
-   * Test the method that formats the sequence name in Fasta style
+   * Test the method that formats the sequence description
+   * 
+   * @throws UnsupportedEncodingException
    */
   @Test(groups = { "Functional" })
-  public void testConstructSequenceFastaHeader()
+  public void testGetUniprotEntryDescription()
+          throws UnsupportedEncodingException
+  {
+    InputStream is = new ByteArrayInputStream(UNIPROT_XML.getBytes());
+    Entry entry = new Uniprot().getUniprotEntries(is).get(0);
+
+    assertEquals("Mitogen-activated protein kinase 13",
+            Uniprot.getUniprotEntryDescription(entry));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetDescription()
+  {
+    FeatureType ft = new FeatureType();
+    assertEquals("", Uniprot.getDescription(ft));
+
+    ft.setDescription("Hello");
+    assertEquals("Hello", Uniprot.getDescription(ft));
+
+    ft.setLocation(new LocationType());
+    ft.getLocation().setPosition(new PositionType());
+    ft.getLocation().getPosition().setPosition(BigInteger.valueOf(23));
+    ft.setOriginal("K");
+    ft.getVariation().add("y");
+    assertEquals("p.Lys23Tyr Hello", Uniprot.getDescription(ft));
+
+    // multiple variants generate an html description over more than one line
+    ft.getVariation().add("W");
+    assertEquals("<html>p.Lys23Tyr<br/>&nbsp;&nbsp;p.Lys23Trp Hello</html>",
+            Uniprot.getDescription(ft));
+
+    /*
+     * indel cases
+     * up to 3 bases (original or variant) are shown using 3 letter code
+     */
+    ft.getVariation().clear();
+    ft.getVariation().add("KWE");
+    ft.setOriginal("KLS");
+    assertEquals("p.LysLeuSer23LysTrpGlu Hello",
+            Uniprot.getDescription(ft));
+
+    // adding a fourth original base switches to single letter code
+    ft.setOriginal("KLST");
+    assertEquals("p.KLST23LysTrpGlu Hello", Uniprot.getDescription(ft));
+
+    // adding a fourth variant switches to single letter code
+    ft.getVariation().clear();
+    ft.getVariation().add("KWES");
+    assertEquals("p.KLST23KWES Hello", Uniprot.getDescription(ft));
+
+    ft.getVariation().clear();
+    ft.getVariation().add("z"); // unknown variant - fails gracefully
+    ft.setOriginal("K");
+    assertEquals("p.Lys23z Hello", Uniprot.getDescription(ft));
+
+    ft.getVariation().clear(); // variant missing - is ignored
+    assertEquals("Hello", Uniprot.getDescription(ft));
+  }
+
+  public static String Q29079 = Q29079 = new String(
+          "<uniprot xmlns=\"http://uniprot.org/uniprot\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://uniprot.org/uniprot http://www.uniprot.org/docs/uniprot.xsd\">\n"
+                  + "<entry xmlns=\"http://uniprot.org/uniprot\" dataset=\"Swiss-Prot\" created=\"1997-11-01\" modified=\"2023-09-13\" version=\"103\">\n"
+                  + "<accession>Q29079</accession>\n"
+                  + "<accession>Q29017</accession>\n"
+                  + "<name>PAG2_PIG</name>\n" + "<protein>\n"
+                  + "<recommendedName>\n"
+                  + "<fullName>Pregnancy-associated glycoprotein 2</fullName>\n"
+                  + "<shortName>PAG 2</shortName>\n"
+                  + "<ecNumber>3.4.23.-</ecNumber>\n"
+                  + "</recommendedName>\n" + "</protein>\n" + "<gene>\n"
+                  + "<name type=\"primary\">PAG2</name>\n" + "</gene>\n"
+                  + "<organism>\n"
+                  + "<name type=\"scientific\">Sus scrofa</name>\n"
+                  + "<name type=\"common\">Pig</name>\n"
+                  + "<dbReference type=\"NCBI Taxonomy\" id=\"9823\"/>\n"
+                  + "<lineage>\n" + "<taxon>Eukaryota</taxon>\n"
+                  + "<taxon>Metazoa</taxon>\n" + "<taxon>Chordata</taxon>\n"
+                  + "<taxon>Craniata</taxon>\n"
+                  + "<taxon>Vertebrata</taxon>\n"
+                  + "<taxon>Euteleostomi</taxon>\n"
+                  + "<taxon>Mammalia</taxon>\n"
+                  + "<taxon>Eutheria</taxon>\n"
+                  + "<taxon>Laurasiatheria</taxon>\n"
+                  + "<taxon>Artiodactyla</taxon>\n"
+                  + "<taxon>Suina</taxon>\n" + "<taxon>Suidae</taxon>\n"
+                  + "<taxon>Sus</taxon>\n" + "</lineage>\n"
+                  + "</organism>\n" + "<reference key=\"1\">\n"
+                  + "<citation type=\"journal article\" date=\"1995\" name=\"Biol. Reprod.\" volume=\"53\" first=\"21\" last=\"28\">\n"
+                  + "<title>Porcine pregnancy-associated glycoproteins: new members of the aspartic proteinase gene family expressed in trophectoderm.</title>\n"
+                  + "<authorList>\n" + "<person name=\"Szafranska B.\"/>\n"
+                  + "<person name=\"Xie S.\"/>\n"
+                  + "<person name=\"Green J.\"/>\n"
+                  + "<person name=\"Roberts R.M.\"/>\n" + "</authorList>\n"
+                  + "<dbReference type=\"PubMed\" id=\"7669851\"/>\n"
+                  + "<dbReference type=\"DOI\" id=\"10.1095/biolreprod53.1.21\"/>\n"
+                  + "</citation>\n"
+                  + "<scope>NUCLEOTIDE SEQUENCE [GENOMIC DNA]</scope>\n"
+                  + "</reference>\n" + "<reference key=\"2\">\n"
+                  + "<citation type=\"journal article\" date=\"2001\" name=\"Mol. Reprod. Dev.\" volume=\"60\" first=\"137\" last=\"146\">\n"
+                  + "<title>Gene for porcine pregnancy-associated glycoprotein 2 (poPAG2): its structural organization and analysis of its promoter.</title>\n"
+                  + "<authorList>\n" + "<person name=\"Szafranska B.\"/>\n"
+                  + "<person name=\"Miura R.\"/>\n"
+                  + "<person name=\"Ghosh D.\"/>\n"
+                  + "<person name=\"Ezashi T.\"/>\n"
+                  + "<person name=\"Xie S.\"/>\n"
+                  + "<person name=\"Roberts R.M.\"/>\n"
+                  + "<person name=\"Green J.A.\"/>\n" + "</authorList>\n"
+                  + "<dbReference type=\"PubMed\" id=\"11553911\"/>\n"
+                  + "<dbReference type=\"DOI\" id=\"10.1002/mrd.1070\"/>\n"
+                  + "</citation>\n"
+                  + "<scope>NUCLEOTIDE SEQUENCE [GENOMIC DNA]</scope>\n"
+                  + "<source>\n" + "<tissue>Placenta</tissue>\n"
+                  + "</source>\n" + "</reference>\n"
+                  + "<comment type=\"subcellular location\">\n"
+                  + "<subcellularLocation>\n"
+                  + "<location>Secreted</location>\n"
+                  + "<location>Extracellular space</location>\n"
+                  + "</subcellularLocation>\n" + "</comment>\n"
+                  + "<comment type=\"tissue specificity\">\n"
+                  + "<text>Expressed throughout the chorion, with the signal localized exclusively over the trophectoderm.</text>\n"
+                  + "</comment>\n"
+                  + "<comment type=\"developmental stage\">\n"
+                  + "<text>Expression was detected at day 15, coinciding with the beginning of implantation, and continued throughout gestation.</text>\n"
+                  + "</comment>\n" + "<comment type=\"similarity\">\n"
+                  + "<text evidence=\"5\">Belongs to the peptidase A1 family.</text>\n"
+                  + "</comment>\n"
+                  + "<dbReference type=\"EC\" id=\"3.4.23.-\"/>\n"
+                  + "<dbReference type=\"EMBL\" id=\"U39763\">\n"
+                  + "<property type=\"protein sequence ID\" value=\"AAA92055.1\"/>\n"
+                  + "<property type=\"molecule type\" value=\"Genomic_DNA\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"EMBL\" id=\"U41421\">\n"
+                  + "<property type=\"protein sequence ID\" value=\"AAA92055.1\"/>\n"
+                  + "<property type=\"status\" value=\"JOINED\"/>\n"
+                  + "<property type=\"molecule type\" value=\"Genomic_DNA\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"EMBL\" id=\"U41422\">\n"
+                  + "<property type=\"protein sequence ID\" value=\"AAA92055.1\"/>\n"
+                  + "<property type=\"status\" value=\"JOINED\"/>\n"
+                  + "<property type=\"molecule type\" value=\"Genomic_DNA\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"EMBL\" id=\"U39199\">\n"
+                  + "<property type=\"protein sequence ID\" value=\"AAA92055.1\"/>\n"
+                  + "<property type=\"status\" value=\"JOINED\"/>\n"
+                  + "<property type=\"molecule type\" value=\"Genomic_DNA\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"EMBL\" id=\"U41423\">\n"
+                  + "<property type=\"protein sequence ID\" value=\"AAA92055.1\"/>\n"
+                  + "<property type=\"status\" value=\"JOINED\"/>\n"
+                  + "<property type=\"molecule type\" value=\"Genomic_DNA\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"EMBL\" id=\"U41424\">\n"
+                  + "<property type=\"protein sequence ID\" value=\"AAA92055.1\"/>\n"
+                  + "<property type=\"status\" value=\"JOINED\"/>\n"
+                  + "<property type=\"molecule type\" value=\"Genomic_DNA\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"EMBL\" id=\"U39762\">\n"
+                  + "<property type=\"protein sequence ID\" value=\"AAA92055.1\"/>\n"
+                  + "<property type=\"status\" value=\"JOINED\"/>\n"
+                  + "<property type=\"molecule type\" value=\"Genomic_DNA\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"EMBL\" id=\"L34361\">\n"
+                  + "<property type=\"protein sequence ID\" value=\"AAA81531.1\"/>\n"
+                  + "<property type=\"molecule type\" value=\"Genomic_DNA\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"PIR\" id=\"I46617\">\n"
+                  + "<property type=\"entry name\" value=\"I46617\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"AlphaFoldDB\" id=\"Q29079\"/>\n"
+                  + "<dbReference type=\"SMR\" id=\"Q29079\"/>\n"
+                  + "<dbReference type=\"MEROPS\" id=\"A01.051\"/>\n"
+                  + "<dbReference type=\"GlyCosmos\" id=\"Q29079\">\n"
+                  + "<property type=\"glycosylation\" value=\"2 sites, No reported glycans\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"InParanoid\" id=\"Q29079\"/>\n"
+                  + "<dbReference type=\"Proteomes\" id=\"UP000008227\">\n"
+                  + "<property type=\"component\" value=\"Unplaced\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"Proteomes\" id=\"UP000314985\">\n"
+                  + "<property type=\"component\" value=\"Unplaced\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"Proteomes\" id=\"UP000694570\">\n"
+                  + "<property type=\"component\" value=\"Unplaced\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"Proteomes\" id=\"UP000694571\">\n"
+                  + "<property type=\"component\" value=\"Unplaced\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"Proteomes\" id=\"UP000694720\">\n"
+                  + "<property type=\"component\" value=\"Unplaced\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"Proteomes\" id=\"UP000694722\">\n"
+                  + "<property type=\"component\" value=\"Unplaced\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"Proteomes\" id=\"UP000694723\">\n"
+                  + "<property type=\"component\" value=\"Unplaced\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"Proteomes\" id=\"UP000694724\">\n"
+                  + "<property type=\"component\" value=\"Unplaced\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"Proteomes\" id=\"UP000694725\">\n"
+                  + "<property type=\"component\" value=\"Unplaced\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"Proteomes\" id=\"UP000694726\">\n"
+                  + "<property type=\"component\" value=\"Unplaced\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"Proteomes\" id=\"UP000694727\">\n"
+                  + "<property type=\"component\" value=\"Unplaced\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"Proteomes\" id=\"UP000694728\">\n"
+                  + "<property type=\"component\" value=\"Unplaced\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"GO\" id=\"GO:0005615\">\n"
+                  + "<property type=\"term\" value=\"C:extracellular space\"/>\n"
+                  + "<property type=\"evidence\" value=\"ECO:0007669\"/>\n"
+                  + "<property type=\"project\" value=\"UniProtKB-SubCell\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"GO\" id=\"GO:0004190\">\n"
+                  + "<property type=\"term\" value=\"F:aspartic-type endopeptidase activity\"/>\n"
+                  + "<property type=\"evidence\" value=\"ECO:0000318\"/>\n"
+                  + "<property type=\"project\" value=\"GO_Central\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"GO\" id=\"GO:0006508\">\n"
+                  + "<property type=\"term\" value=\"P:proteolysis\"/>\n"
+                  + "<property type=\"evidence\" value=\"ECO:0000318\"/>\n"
+                  + "<property type=\"project\" value=\"GO_Central\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"Gene3D\" id=\"6.10.140.60\">\n"
+                  + "<property type=\"match status\" value=\"1\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"Gene3D\" id=\"2.40.70.10\">\n"
+                  + "<property type=\"entry name\" value=\"Acid Proteases\"/>\n"
+                  + "<property type=\"match status\" value=\"3\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"InterPro\" id=\"IPR001461\">\n"
+                  + "<property type=\"entry name\" value=\"Aspartic_peptidase_A1\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"InterPro\" id=\"IPR001969\">\n"
+                  + "<property type=\"entry name\" value=\"Aspartic_peptidase_AS\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"InterPro\" id=\"IPR012848\">\n"
+                  + "<property type=\"entry name\" value=\"Aspartic_peptidase_N\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"InterPro\" id=\"IPR033121\">\n"
+                  + "<property type=\"entry name\" value=\"PEPTIDASE_A1\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"InterPro\" id=\"IPR021109\">\n"
+                  + "<property type=\"entry name\" value=\"Peptidase_aspartic_dom_sf\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"PANTHER\" id=\"PTHR47966\">\n"
+                  + "<property type=\"entry name\" value=\"BETA-SITE APP-CLEAVING ENZYME, ISOFORM A-RELATED\"/>\n"
+                  + "<property type=\"match status\" value=\"1\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"PANTHER\" id=\"PTHR47966:SF49\">\n"
+                  + "<property type=\"entry name\" value=\"PEPSIN A-5\"/>\n"
+                  + "<property type=\"match status\" value=\"1\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"Pfam\" id=\"PF07966\">\n"
+                  + "<property type=\"entry name\" value=\"A1_Propeptide\"/>\n"
+                  + "<property type=\"match status\" value=\"1\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"Pfam\" id=\"PF00026\">\n"
+                  + "<property type=\"entry name\" value=\"Asp\"/>\n"
+                  + "<property type=\"match status\" value=\"2\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"PRINTS\" id=\"PR00792\">\n"
+                  + "<property type=\"entry name\" value=\"PEPSIN\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"SUPFAM\" id=\"SSF50630\">\n"
+                  + "<property type=\"entry name\" value=\"Acid proteases\"/>\n"
+                  + "<property type=\"match status\" value=\"2\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"PROSITE\" id=\"PS00141\">\n"
+                  + "<property type=\"entry name\" value=\"ASP_PROTEASE\"/>\n"
+                  + "<property type=\"match status\" value=\"2\"/>\n"
+                  + "</dbReference>\n"
+                  + "<dbReference type=\"PROSITE\" id=\"PS51767\">\n"
+                  + "<property type=\"entry name\" value=\"PEPTIDASE_A1\"/>\n"
+                  + "<property type=\"match status\" value=\"1\"/>\n"
+                  + "</dbReference>\n"
+                  + "<proteinExistence type=\"evidence at transcript level\"/>\n"
+                  + "<keyword id=\"KW-0064\">Aspartyl protease</keyword>\n"
+                  + "<keyword id=\"KW-1015\">Disulfide bond</keyword>\n"
+                  + "<keyword id=\"KW-0325\">Glycoprotein</keyword>\n"
+                  + "<keyword id=\"KW-0378\">Hydrolase</keyword>\n"
+                  + "<keyword id=\"KW-0645\">Protease</keyword>\n"
+                  + "<keyword id=\"KW-1185\">Reference proteome</keyword>\n"
+                  + "<keyword id=\"KW-0964\">Secreted</keyword>\n"
+                  + "<keyword id=\"KW-0732\">Signal</keyword>\n"
+                  + "<keyword id=\"KW-0865\">Zymogen</keyword>\n"
+                  + "<feature type=\"signal peptide\" evidence=\"2\">\n"
+                  + "<location>\n" + "<begin position=\"1\"/>\n"
+                  + "<end position=\"15\"/>\n" + "</location>\n"
+                  + "</feature>\n"
+                  + "<feature type=\"propeptide\" id=\"PRO_0000026107\" description=\"Activation peptide\" evidence=\"2\">\n"
+                  + "<location>\n" + "<begin position=\"16\"/>\n"
+                  + "<end status=\"unknown\"/>\n" + "</location>\n"
+                  + "</feature>\n"
+                  + "<feature type=\"chain\" id=\"PRO_0000026108\" description=\"Pregnancy-associated glycoprotein 2\">\n"
+                  + "<location>\n" + "<begin status=\"unknown\"/>\n"
+                  + "<end position=\"420\"/>\n" + "</location>\n"
+                  + "</feature>\n"
+                  + "<feature type=\"domain\" description=\"Peptidase A1\" evidence=\"3\">\n"
+                  + "<location>\n" + "<begin position=\"76\"/>\n"
+                  + "<end position=\"417\"/>\n" + "</location>\n"
+                  + "</feature>\n"
+                  + "<feature type=\"active site\" evidence=\"4\">\n"
+                  + "<location>\n" + "<position position=\"94\"/>\n"
+                  + "</location>\n" + "</feature>\n"
+                  + "<feature type=\"active site\" evidence=\"4\">\n"
+                  + "<location>\n" + "<position position=\"277\"/>\n"
+                  + "</location>\n" + "</feature>\n"
+                  + "<feature type=\"glycosylation site\" description=\"N-linked (GlcNAc...) asparagine\" evidence=\"2\">\n"
+                  + "<location>\n" + "<position position=\"56\"/>\n"
+                  + "</location>\n" + "</feature>\n"
+                  + "<feature type=\"glycosylation site\" description=\"N-linked (GlcNAc...) asparagine\" evidence=\"2\">\n"
+                  + "<location>\n" + "<position position=\"79\"/>\n"
+                  + "</location>\n" + "</feature>\n"
+                  + "<feature type=\"disulfide bond\" evidence=\"1\">\n"
+                  + "<location>\n" + "<begin position=\"107\"/>\n"
+                  + "<end position=\"112\"/>\n" + "</location>\n"
+                  + "</feature>\n"
+                  + "<feature type=\"disulfide bond\" evidence=\"1\">\n"
+                  + "<location>\n" + "<begin position=\"268\"/>\n"
+                  + "<end position=\"272\"/>\n" + "</location>\n"
+                  + "</feature>\n"
+                  + "<feature type=\"disulfide bond\" evidence=\"1\">\n"
+                  + "<location>\n" + "<begin position=\"341\"/>\n"
+                  + "<end position=\"376\"/>\n" + "</location>\n"
+                  + "</feature>\n"
+                  + "<feature type=\"sequence conflict\" description=\"In Ref. 1.\" evidence=\"5\" ref=\"1\">\n"
+                  + "<location>\n" + "<begin position=\"335\"/>\n"
+                  + "<end position=\"367\"/>\n" + "</location>\n"
+                  + "</feature>\n"
+                  + "<evidence type=\"ECO:0000250\" key=\"1\"/>\n"
+                  + "<evidence type=\"ECO:0000255\" key=\"2\"/>\n"
+                  + "<evidence type=\"ECO:0000255\" key=\"3\">\n"
+                  + "<source>\n"
+                  + "<dbReference type=\"PROSITE-ProRule\" id=\"PRU01103\"/>\n"
+                  + "</source>\n" + "</evidence>\n"
+                  + "<evidence type=\"ECO:0000255\" key=\"4\">\n"
+                  + "<source>\n"
+                  + "<dbReference type=\"PROSITE-ProRule\" id=\"PRU10094\"/>\n"
+                  + "</source>\n" + "</evidence>\n"
+                  + "<evidence type=\"ECO:0000305\" key=\"5\"/>\n"
+                  + "<sequence length=\"420\" mass=\"47132\" checksum=\"094153B6C1B1FCDB\" modified=\"1997-11-01\" version=\"1\" precursor=\"true\">MKWLVILGLVALSDCLVMIPLTKVKSVRESLREKGLLKNFLKEHPYNMIQNLLSKNSSHVQKFSYQPLRNYLDMVYVGNISIGTPPQQFSVVFDTGSSDLWVPSIYCKSKACVTHRSFNPSHSSTFHDRGKSIKLEYGSGKMSGFLGQDTVRIGQLTSTGQAFGLSKEETGKAFEHAIFDGILGLAYPSIAIKGTTTVIDNLKKQDQISEPVFAFYLSSDKEEGSVVMFGGVDKKYYKGDLKWVPLTQTSYWQIALDRITCRGRVIGCPRGCQAIVDTGTSMLHGPSKAVAKIHSLIKHFEKEYVVPCNARKALPDIVFTINNVDYPVPAQAYIRKYVVPCNARKALPDIVFTINNVDYPVPAQAYIRKNANNNRCYSTFEDIMDTLNQREIWILGDVFLRLYFTVYDEGQNRIGLAQAT</sequence>\n"
+                  + "</entry>\n"
+                  + "<copyright> Copyrighted by the UniProt Consortium, see https://www.uniprot.org/terms Distributed under the Creative Commons Attribution (CC BY 4.0) License </copyright>\n"
+                  + "</uniprot>");
+
+  @DataProvider
+  public Object[][] problemEntries()
+  {
+    return new Object[][] { new Object[] { Q29079 } };
+  }
+
+  @Test(groups = "Functional", dataProvider = "problemEntries")
+  public SequenceI testimportOfProblemEntries(String entry)
   {
     Uniprot u = new Uniprot();
-    Reader reader = new StringReader(UNIPROT_XML);
-    Vector<UniprotEntry> entries = u.getUniprotEntries(reader);
-    UniprotEntry entry = entries.get(0);
-
-    // source + accession ids + names + protein names
-    String expectedName = ">UniProt/Swiss-Prot|A9CKP4|A9CKP5|A9CKP4_AGRT5|A9CKP4_AGRT6 Mitogen-activated protein kinase 13 Henry";
-    assertEquals(expectedName, Uniprot.constructSequenceFastaHeader(entry)
-            .toString());
+    InputStream is = new ByteArrayInputStream(entry.getBytes());
+    List<Entry> entries = u.getUniprotEntries(is);
+    assertEquals(1, entries.size());
+    SequenceI sq = u.uniprotEntryToSequence(entries.get(0));
+    assertNotNull(sq);
+    return sq;
+  }
+
+  @Test(groups = "Functional")
+  public void checkIndefiniteSequenceFeatures()
+  {
+    SequenceI upseq = testimportOfProblemEntries(Q29079);
+    List<SequenceFeature> sf = upseq.getFeatures()
+            .getPositionalFeatures("chain");
+    assertNotNull(sf);
+    assertTrue(sf.size() == 1);
+    SequenceFeature chainFeaure = sf.get(0);
+    assertTrue(chainFeaure.getBegin() == 1);
+    assertTrue(chainFeaure.getEnd() == upseq.getEnd());
+    assertNotNull(chainFeaure.getValueAsString("start_status"));
+    assertNull(chainFeaure.getValueAsString("end_status"));
+    assertTrue(
+            "unknown".equals(chainFeaure.getValueAsString("start_status")));
   }
 }