From: gmungoc Date: Fri, 16 Sep 2016 11:19:17 +0000 (+0100) Subject: JAL-2157 JAL-1803 refactored Sequence.updatePDBIds, parse DBRefs with X-Git-Tag: Release_2_10_0~41^2~1 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=b9012154b256ce7dc7125072706e918ab97ffe87;p=jalview.git JAL-2157 JAL-1803 refactored Sequence.updatePDBIds, parse DBRefs with chain appended --- diff --git a/src/jalview/datamodel/PDBEntry.java b/src/jalview/datamodel/PDBEntry.java index 198b4a6..1403595 100755 --- a/src/jalview/datamodel/PDBEntry.java +++ b/src/jalview/datamodel/PDBEntry.java @@ -26,6 +26,8 @@ import java.util.Hashtable; public class PDBEntry { + private static final int PDB_ID_LENGTH = 4; + private String file; private String type; @@ -72,10 +74,9 @@ public class PDBEntry Hashtable properties; - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) + /** + * Answers true if obj is a PDBEntry with the same id and chain code (both + * ignoring case), file, type and properties */ @Override public boolean equals(Object obj) @@ -89,14 +90,24 @@ public class PDBEntry return true; } PDBEntry o = (PDBEntry) obj; - return (type == o.type || (type != null && o.type != null && o.type - .equals(type))) - && (id == o.id || (id != null && o.id != null && o.id - .equalsIgnoreCase(id))) - && (properties == o.properties || (properties != null - && o.properties != null && properties - .equals(o.properties))); + /* + * note that chain code is stored as a property wrapped by a + * CaseInsensitiveString, so we are in effect doing a + * case-insensitive comparison of chain codes + */ + boolean idMatches = id == o.id + || (id != null && id.equalsIgnoreCase(o.id)); + boolean fileMatches = file == o.file + || (file != null && file.equals(o.file)); + boolean typeMatches = type == o.type + || (type != null && type.equals(o.type)); + if (idMatches && fileMatches && typeMatches) + { + return properties == o.properties + || (properties != null && properties.equals(o.properties)); + } + return false; } /** @@ -120,6 +131,17 @@ public class PDBEntry public PDBEntry(String pdbId, String chain, PDBEntry.Type type, String filePath) { + init(pdbId, chain, type, filePath); + } + + /** + * @param pdbId + * @param chain + * @param type + * @param filePath + */ + void init(String pdbId, String chain, PDBEntry.Type type, String filePath) + { this.id = pdbId; this.type = type == null ? null : type.toString(); this.file = filePath; @@ -142,6 +164,35 @@ public class PDBEntry } } + /** + * Make a PDBEntry from a DBRefEntry. The accession code is used for the PDB + * id, but if it is 5 characters in length, the last character is removed and + * set as the chain code instead. + * + * @param dbr + */ + public PDBEntry(DBRefEntry dbr) + { + if (!DBRefSource.PDB.equals(dbr.getSource())) + { + throw new IllegalArgumentException("Invalid source: " + + dbr.getSource()); + } + + String pdbId = dbr.getAccessionId(); + String chainCode = null; + if (pdbId.length() == PDB_ID_LENGTH + 1) + { + char chain = pdbId.charAt(PDB_ID_LENGTH); + if (('a' <= chain && chain <= 'z') || ('A' <= chain && chain <= 'Z')) + { + pdbId = pdbId.substring(0, PDB_ID_LENGTH); + chainCode = String.valueOf(chain); + } + } + init(pdbId, chainCode, null, null); + } + public void setFile(String file) { this.file = file; @@ -224,52 +275,109 @@ public class PDBEntry } /** - * update entry with details from another entry concerning the same PDB - * ID/file spec. + * Answers true if this object is either equivalent to, or can be 'improved' + * by, the given entry. + *

+ * If newEntry has the same id (ignoring case), and doesn't have a conflicting + * file spec or chain code, then update this entry from its file and/or chain + * code. * * @param newEntry * @return true if modifications were made */ - public boolean updateFrom(PDBEntry newEntry) + protected boolean updateFrom(PDBEntry newEntry) { - boolean modified = false; + if (this.equals(newEntry)) + { + return true; + } + + String newId = newEntry.getId(); + if (newId == null || getId() == null) + { + return false; // shouldn't happen + } + + /* + * id (less any chain code) has to match (ignoring case) + */ + if (!getId().equalsIgnoreCase(newId)) + { + return false; + } + + /* + * Don't update if associated with different structure files + */ + String newFile = newEntry.getFile(); + if (newFile != null && getFile() != null && !newFile.equals(getFile())) + { + return false; + } - if (getFile() == null) + /* + * Don't update if associated with different chains (ignoring case) + */ + String newChain = newEntry.getChainCode(); + if (newChain != null && newChain.length() > 0 && getChainCode() != null + && getChainCode().length() > 0 + && !getChainCode().equalsIgnoreCase(newChain)) { - // update file and type of file - modified |= newEntry.getFile() != null; - setFile(newEntry.getFile()); + return false; } - if (newEntry.getType() != null && newEntry.getFile() != null - && newEntry.getFile().equals(getFile())) + + /* + * set file path if not already set + */ + String newType = newEntry.getType(); + if (getFile() == null && newFile != null) { - setType(newEntry.getType()); + setFile(newFile); + setType(newType); } - if (getChainCode() == null - || (getChainCode() != null && getChainCode().length() == 0 && newEntry - .getChainCode() != null)) + + /* + * set file type if new entry has it and we don't + * (for the case where file was not updated) + */ + if (getType() == null && newType != null) { - modified |= getChainCode() == null - || !newEntry.getChainCode().equals(getChainCode()); - setChainCode(newEntry.getChainCode()); + setType(newType); } + + /* + * set chain if not already set (we excluded differing + * chains earlier) (ignoring case change only) + */ + if (newChain != null && newChain.length() > 0 + && !newChain.equalsIgnoreCase(getChainCode())) + { + setChainCode(newChain); + } + + /* + * copy any new properties; notice this may include chain_code, + * but we excluded differing chain codes earlier + */ if (newEntry.getProperty() != null) { if (properties == null) { properties = new Hashtable(); } - // TODO: getProperty -> Map for (Object p : newEntry.getProperty().keySet()) { - if (properties.get(p) == null - || !properties.get(p).equals(newEntry.getProperty().get(p))) + /* + * copy properties unless value matches; this defends against changing + * the case of chain_code which is wrapped in a CaseInsensitiveString + */ + Object value = newEntry.getProperty().get(p); + if (!value.equals(properties.get(p))) { - modified = true; + properties.put(p, newEntry.getProperty().get(p)); } - properties.put(p, newEntry.getProperty().get(p)); } } - return modified; + return true; } } diff --git a/src/jalview/datamodel/Sequence.java b/src/jalview/datamodel/Sequence.java index 4f626a4..44522a8 100755 --- a/src/jalview/datamodel/Sequence.java +++ b/src/jalview/datamodel/Sequence.java @@ -412,72 +412,24 @@ public class Sequence extends ASequence implements SequenceI } @Override - public void addPDBId(PDBEntry entry) + public boolean addPDBId(PDBEntry entry) { if (pdbIds == null) { pdbIds = new Vector(); + pdbIds.add(entry); + return true; } - if (!updatedPDBEntry(pdbIds, entry)) - { - pdbIds.addElement(entry); - } - } - private static boolean updatedPDBEntry(List entries, - PDBEntry newEntry) - { - for (PDBEntry xtant : entries) + for (PDBEntry pdbe : pdbIds) { - if (xtant.getFile() != null && newEntry.getFile() != null - && !xtant.getFile().equals(newEntry.getFile())) - { - // different structure data, so leave alone. - continue; - } - // loop through to check whether we can find a matching ID - - // either exact - if (!xtant.getId().equals(newEntry.getId())) - { - /* TODO: support stemming to group PDB IDs. - // or stemming, with exactly one alphanumeric character difference - if (xtant.getId().length() < newEntry.getId().length()) - { - if (!newEntry.getId().startsWith(xtant.getId())) - { - continue; - } - // newEntry may be chain specific PDBEntry - // TODO: copy/update details from newEntry to xtant - } - else - { - if (!xtant.getId().startsWith(newEntry.getId())) - { - continue; - } - // xtant may be chain specific PDBEntry - // TODO: copy/update missing details from newEntry - }*/ - continue; - } - if (xtant.getChainCode() != null && xtant.getChainCode().length() > 0 - && newEntry.getChainCode() != null - && !newEntry.getChainCode().equals(xtant.getChainCode())) + if (pdbe.updateFrom(entry)) { - // don't overwrite - multiple chain mappings for a sequence yield - // multiple PDBEntries - // each with different chaincode - continue; + return false; } - - xtant.updateFrom(newEntry); - - return true; } - // if we got to the end of the loop, nothing was updated. - return false; + pdbIds.addElement(entry); + return true; } /** @@ -1269,46 +1221,22 @@ public class Sequence extends ASequence implements SequenceI { return false; } - Vector newpdb = new Vector(); - for (int i = 0; i < dbrefs.length; i++) + boolean added = false; + for (DBRefEntry dbr : dbrefs) { - if (DBRefSource.PDB.equals(dbrefs[i].getSource())) + if (DBRefSource.PDB.equals(dbr.getSource())) { - PDBEntry pdbe = new PDBEntry(); - pdbe.setId(dbrefs[i].getAccessionId()); - if (pdbIds == null || pdbIds.size() == 0) - { - newpdb.addElement(pdbe); - } - else - { - Enumeration en = pdbIds.elements(); - boolean matched = false; - while (!matched && en.hasMoreElements()) - { - PDBEntry anentry = (PDBEntry) en.nextElement(); - if (anentry.getId().equals(pdbe.getId())) - { - matched = true; - } - } - if (!matched) - { - newpdb.addElement(pdbe); - } - } - } - } - if (newpdb.size() > 0) - { - Enumeration en = newpdb.elements(); - while (en.hasMoreElements()) - { - addPDBId((PDBEntry) en.nextElement()); + /* + * 'Add' any PDB dbrefs as a PDBEntry - add is only performed if the + * PDB id is not already present in a 'matching' PDBEntry + * Constructor parses out a chain code if appended to the accession id + * (a fudge used to 'store' the chain code in the DBRef) + */ + PDBEntry pdbe = new PDBEntry(dbr); + added |= addPDBId(pdbe); } - return true; } - return false; + return added; } @Override diff --git a/src/jalview/datamodel/SequenceI.java b/src/jalview/datamodel/SequenceI.java index 55c59db..b7a291e 100755 --- a/src/jalview/datamodel/SequenceI.java +++ b/src/jalview/datamodel/SequenceI.java @@ -289,16 +289,18 @@ public interface SequenceI extends ASequenceI public Vector getAllPDBEntries(); /** - * add entry to the *normalised* vector of PDBIds. + * Adds the entry to the *normalised* list of PDBIds. * - * If a PDBEntry is passed with an entry.getID() string, as one already in the - * list, or one is added that appears to be the same but has a chain ID + * If a PDBEntry is passed with the same entry.getID() string as one already + * in the list, or one is added that appears to be the same but has a chain ID * appended, then the existing PDBEntry will be updated with the new - * attributes. + * attributes instead, unless the entries have distinct chain codes or + * associated structure files. * * @param entry + * @return true if the entry was added, false if updated */ - public void addPDBId(PDBEntry entry); + public boolean addPDBId(PDBEntry entry); /** * update the list of PDBEntrys to include any DBRefEntrys citing structural diff --git a/test/jalview/datamodel/PDBEntryTest.java b/test/jalview/datamodel/PDBEntryTest.java index cf944b2..979fee4 100644 --- a/test/jalview/datamodel/PDBEntryTest.java +++ b/test/jalview/datamodel/PDBEntryTest.java @@ -1,4 +1,5 @@ /* + assertEquals(case7, case9); * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) * Copyright (C) $$Year-Rel$$ The Jalview Authors * @@ -27,6 +28,11 @@ import static org.testng.Assert.assertNotSame; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import jalview.datamodel.PDBEntry.Type; + +import java.util.Hashtable; //import org.testng.Assert; import org.testng.annotations.AfterMethod; @@ -52,23 +58,34 @@ public class PDBEntryTest PDBEntry pdbEntry = new PDBEntry("1xyz", "A", PDBEntry.Type.PDB, "x/y/z/File"); + // id comparison is not case sensitive PDBEntry case1 = new PDBEntry("1XYZ", "A", PDBEntry.Type.PDB, "x/y/z/File"); + // chain code comparison is not case sensitive PDBEntry case2 = new PDBEntry("1xyz", "a", PDBEntry.Type.PDB, "x/y/z/File"); + // different type PDBEntry case3 = new PDBEntry("1xyz", "A", PDBEntry.Type.FILE, "x/y/z/File"); + // different everything PDBEntry case4 = new PDBEntry(null, null, null, null); + // null id PDBEntry case5 = new PDBEntry(null, "A", PDBEntry.Type.PDB, "x/y/z/File"); + // null chain PDBEntry case6 = new PDBEntry("1xyz", null, PDBEntry.Type.PDB, "x/y/z/File"); + // null type PDBEntry case7 = new PDBEntry("1xyz", "A", null, "x/y/z/File"); + // null file PDBEntry case8 = new PDBEntry("1xyz", "A", PDBEntry.Type.PDB, null); + // identical to case7 PDBEntry case9 = new PDBEntry("1xyz", "A", null, "x/y/z/File"); + // different file only + PDBEntry case10 = new PDBEntry("1xyz", "A", null, "a/b/c/File"); /* - * assertions will invoke PDBEntry.equals() + * assertEquals will invoke PDBEntry.equals() */ assertFalse(pdbEntry.equals(null)); assertFalse(pdbEntry.equals("a")); @@ -79,8 +96,17 @@ public class PDBEntryTest assertNotEquals(case5, pdbEntry); assertNotEquals(case6, pdbEntry); assertNotEquals(case7, pdbEntry); - assertEquals(case8, pdbEntry); + assertNotEquals(case8, pdbEntry); + assertEquals(case7, case9); + assertNotEquals(case9, case10); + + // add properties + case7.getProperty().put("hello", "world"); + assertNotEquals(case7, case9); + case9.getProperty().put("hello", "world"); assertEquals(case7, case9); + case9.getProperty().put("hello", "WORLD"); + assertNotEquals(case7, case9); /* * change string wrapper property to string... @@ -122,4 +148,161 @@ public class PDBEntryTest assertTrue(PDBEntry.Type.FILE.matches("file")); assertFalse(PDBEntry.Type.FILE.matches("FILE ")); } + + @Test(groups = { "Functional" }) + public void testUpdateFrom() + { + PDBEntry pdb1 = new PDBEntry("3A6S", null, null, null); + PDBEntry pdb2 = new PDBEntry("3A6S", null, null, null); + assertTrue(pdb1.updateFrom(pdb2)); + + /* + * mismatch of pdb id not allowed + */ + pdb2 = new PDBEntry("1A70", "A", null, null); + assertFalse(pdb1.updateFrom(pdb2)); + assertNull(pdb1.getChainCode()); + + /* + * match of pdb id is not case sensitive + */ + pdb2 = new PDBEntry("3a6s", "A", null, null); + assertTrue(pdb1.updateFrom(pdb2)); + assertEquals(pdb1.getChainCode(), "A"); + assertEquals(pdb1.getId(), "3A6S"); + + /* + * add chain - with differing case for id + */ + pdb1 = new PDBEntry("3A6S", null, null, null); + pdb2 = new PDBEntry("3a6s", "A", null, null); + assertTrue(pdb1.updateFrom(pdb2)); + assertEquals(pdb1.getChainCode(), "A"); + + /* + * change of chain is not allowed + */ + pdb2 = new PDBEntry("3A6S", "B", null, null); + assertFalse(pdb1.updateFrom(pdb2)); + assertEquals(pdb1.getChainCode(), "A"); + + /* + * change chain from null + */ + pdb1 = new PDBEntry("3A6S", null, null, null); + pdb2 = new PDBEntry("3A6S", "B", null, null); + assertTrue(pdb1.updateFrom(pdb2)); + assertEquals(pdb1.getChainCode(), "B"); + + /* + * set file and type + */ + pdb2 = new PDBEntry("3A6S", "B", Type.FILE, "filePath"); + assertTrue(pdb1.updateFrom(pdb2)); + assertEquals(pdb1.getFile(), "filePath"); + assertEquals(pdb1.getType(), Type.FILE.toString()); + + /* + * change of file is not allowed + */ + pdb1 = new PDBEntry("3A6S", null, null, "file1"); + pdb2 = new PDBEntry("3A6S", "A", null, "file2"); + assertFalse(pdb1.updateFrom(pdb2)); + assertNull(pdb1.getChainCode()); + assertEquals(pdb1.getFile(), "file1"); + + /* + * set type without change of file + */ + pdb1 = new PDBEntry("3A6S", null, null, "file1"); + pdb2 = new PDBEntry("3A6S", null, Type.PDB, "file1"); + assertTrue(pdb1.updateFrom(pdb2)); + assertEquals(pdb1.getType(), Type.PDB.toString()); + + /* + * set file with differing case of id and chain code + */ + pdb1 = new PDBEntry("3A6S", "A", null, null); + pdb2 = new PDBEntry("3a6s", "a", Type.PDB, "file1"); + assertTrue(pdb1.updateFrom(pdb2)); + assertEquals(pdb1.getType(), Type.PDB.toString()); + assertEquals(pdb1.getId(), "3A6S"); // unchanged + assertEquals(pdb1.getFile(), "file1"); // updated + assertEquals(pdb1.getChainCode(), "A"); // unchanged + + /* + * changing nothing returns true + */ + pdb1 = new PDBEntry("3A6S", "A", Type.PDB, "file1"); + pdb2 = new PDBEntry("3A6S", null, null, null); + assertTrue(pdb1.updateFrom(pdb2)); + assertEquals(pdb1.getChainCode(), "A"); + assertEquals(pdb1.getType(), Type.PDB.toString()); + assertEquals(pdb1.getFile(), "file1"); + + /* + * add and update properties only + */ + pdb1 = new PDBEntry("3A6S", null, null, null); + pdb2 = new PDBEntry("3A6S", null, null, null); + // ughh properties not null if chain code has been set... + // JAL-2196 addresses this + pdb1.properties = new Hashtable(); + pdb2.properties = new Hashtable(); + pdb1.properties.put("destination", "mars"); + pdb1.properties.put("hello", "world"); + pdb2.properties.put("hello", "moon"); + pdb2.properties.put("goodbye", "world"); + assertTrue(pdb1.updateFrom(pdb2)); + assertEquals(pdb1.properties.get("destination"), "mars"); + assertEquals(pdb1.properties.get("hello"), "moon"); + assertEquals(pdb1.properties.get("goodbye"), "world"); + + /* + * add properties only + */ + pdb1 = new PDBEntry("3A6S", null, null, null); + pdb2 = new PDBEntry("3A6S", null, null, null); + pdb2.properties = new Hashtable(); + pdb2.properties.put("hello", "moon"); + assertTrue(pdb1.updateFrom(pdb2)); + assertEquals(pdb1.properties.get("hello"), "moon"); + } + + @Test(groups = { "Functional" }) + public void testConstructor_fromDbref() + { + PDBEntry pdb = new PDBEntry(new DBRefEntry("PDB", "0", "1A70")); + assertEquals(pdb.getId(), "1A70"); + assertNull(pdb.getChainCode()); + assertNull(pdb.getType()); + assertNull(pdb.getFile()); + + /* + * from dbref with chain code appended + */ + pdb = new PDBEntry(new DBRefEntry("PDB", "0", "1A70B")); + assertEquals(pdb.getId(), "1A70"); + assertEquals(pdb.getChainCode(), "B"); + + /* + * from dbref with overlong accession + */ + pdb = new PDBEntry(new DBRefEntry("PDB", "0", "1A70BC")); + assertEquals(pdb.getId(), "1A70BC"); + assertNull(pdb.getChainCode()); + + /* + * from dbref which is not for PDB + */ + try + { + pdb = new PDBEntry(new DBRefEntry("PDBe", "0", "1A70")); + fail("Expected exception"); + } catch (IllegalArgumentException e) + { + // expected; + } + } + } diff --git a/test/jalview/datamodel/SequenceTest.java b/test/jalview/datamodel/SequenceTest.java index c7e53a9..8c5073b 100644 --- a/test/jalview/datamodel/SequenceTest.java +++ b/test/jalview/datamodel/SequenceTest.java @@ -884,4 +884,87 @@ public class SequenceTest 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 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)); + } } diff --git a/test/jalview/ext/jmol/JmolParserTest.java b/test/jalview/ext/jmol/JmolParserTest.java index 8788609..a014ef8 100644 --- a/test/jalview/ext/jmol/JmolParserTest.java +++ b/test/jalview/ext/jmol/JmolParserTest.java @@ -162,7 +162,8 @@ public class JmolParserTest private void checkFirstAAIsAssoc(SequenceI sq) { - assertTrue("No secondary structure assigned for protein sequence.", + assertTrue("No secondary structure assigned for protein sequence for " + + sq.getName(), sq.getAnnotation() != null && sq.getAnnotation().length >= 1 && sq.getAnnotation()[0].hasIcons); assertTrue(