From b5a5b5fa7fe3fb77e55acf930d25d10ddc0e80e2 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Thu, 27 Apr 2017 11:54:45 +0100 Subject: [PATCH] JAL-2492 use SequenceFeatures.getNonPositionalFeatures() --- src/jalview/appletgui/IdPanel.java | 116 ++++++------ .../datamodel/features/SequenceFeatures.java | 32 +++- .../datamodel/features/SequenceFeaturesI.java | 3 +- src/jalview/gui/IdPanel.java | 22 +-- src/jalview/io/SequenceAnnotationReport.java | 186 +++++++++++--------- .../datamodel/features/SequenceFeaturesTest.java | 137 +++++++++++--- test/jalview/io/SequenceAnnotationReportTest.java | 138 +++++++++++++++ 7 files changed, 442 insertions(+), 192 deletions(-) diff --git a/src/jalview/appletgui/IdPanel.java b/src/jalview/appletgui/IdPanel.java index e47c50a..80f03a1 100755 --- a/src/jalview/appletgui/IdPanel.java +++ b/src/jalview/appletgui/IdPanel.java @@ -20,7 +20,6 @@ */ package jalview.appletgui; -import jalview.datamodel.Sequence; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; @@ -105,64 +104,57 @@ public class IdPanel extends Panel implements MouseListener, SequenceI sequence = av.getAlignment().getSequenceAt(seq); - // look for non-pos features StringBuffer tooltiptext = new StringBuffer(); - if (sequence != null) + if (sequence == null) { - if (sequence.getDescription() != null) + return; + } + if (sequence.getDescription() != null) + { + tooltiptext.append(sequence.getDescription()); + tooltiptext.append("\n"); + } + + for (SequenceFeature sf : sequence.getFeatures() + .getNonPositionalFeatures()) + { + boolean nl = false; + if (sf.getFeatureGroup() != null) { - tooltiptext.append(sequence.getDescription()); - tooltiptext.append("\n"); + tooltiptext.append(sf.getFeatureGroup()); + nl = true; } - - SequenceFeature sf[] = sequence.getSequenceFeatures(); - for (int sl = 0; sf != null && sl < sf.length; sl++) + if (sf.getType() != null) { - if (sf[sl].begin == sf[sl].end && sf[sl].begin == 0) - { - boolean nl = false; - if (sf[sl].getFeatureGroup() != null) - { - tooltiptext.append(sf[sl].getFeatureGroup()); - nl = true; - } - ; - if (sf[sl].getType() != null) - { - tooltiptext.append(" "); - tooltiptext.append(sf[sl].getType()); - nl = true; - } - ; - if (sf[sl].getDescription() != null) - { - tooltiptext.append(" "); - tooltiptext.append(sf[sl].getDescription()); - nl = true; - } - ; - if (!Float.isNaN(sf[sl].getScore()) && sf[sl].getScore() != 0f) - { - tooltiptext.append(" Score = "); - tooltiptext.append(sf[sl].getScore()); - nl = true; - } - ; - if (sf[sl].getStatus() != null && sf[sl].getStatus().length() > 0) - { - tooltiptext.append(" ("); - tooltiptext.append(sf[sl].getStatus()); - tooltiptext.append(")"); - nl = true; - } - ; - if (nl) - { - tooltiptext.append("\n"); - } - } + tooltiptext.append(" "); + tooltiptext.append(sf.getType()); + nl = true; + } + if (sf.getDescription() != null) + { + tooltiptext.append(" "); + tooltiptext.append(sf.getDescription()); + nl = true; + } + if (!Float.isNaN(sf.getScore()) && sf.getScore() != 0f) + { + tooltiptext.append(" Score = "); + tooltiptext.append(sf.getScore()); + nl = true; + } + if (sf.getStatus() != null && sf.getStatus().length() > 0) + { + tooltiptext.append(" ("); + tooltiptext.append(sf.getStatus()); + tooltiptext.append(")"); + nl = true; + } + if (nl) + { + tooltiptext.append("\n"); } } + if (tooltiptext.length() == 0) { // nothing to display - so clear tooltip if one is visible @@ -283,23 +275,21 @@ public class IdPanel extends Panel implements MouseListener, if ((e.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) { - Sequence sq = (Sequence) av.getAlignment().getSequenceAt(seq); + SequenceI sq = av.getAlignment().getSequenceAt(seq); - // build a new links menu based on the current links + any non-positional - // features + /* + * build a new links menu based on the current links + * and any non-positional features + */ List nlinks = urlProvider.getLinksForMenu(); - SequenceFeature sf[] = sq == null ? null : sq.getSequenceFeatures(); - for (int sl = 0; sf != null && sl < sf.length; sl++) + for (SequenceFeature sf : sq.getFeatures().getNonPositionalFeatures()) { - if (sf[sl].begin == sf[sl].end && sf[sl].begin == 0) + if (sf.links != null) { - if (sf[sl].links != null && sf[sl].links.size() > 0) + for (String link : sf.links) { - for (int l = 0, lSize = sf[sl].links.size(); l < lSize; l++) - { - nlinks.add(sf[sl].links.elementAt(l)); - } + nlinks.add(link); } } } diff --git a/src/jalview/datamodel/features/SequenceFeatures.java b/src/jalview/datamodel/features/SequenceFeatures.java index c6af3ea..5fa9a3c 100644 --- a/src/jalview/datamodel/features/SequenceFeatures.java +++ b/src/jalview/datamodel/features/SequenceFeatures.java @@ -4,12 +4,13 @@ import jalview.datamodel.SequenceFeature; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.TreeMap; /** * A class that stores sequence features in a way that supports efficient @@ -33,7 +34,12 @@ public class SequenceFeatures implements SequenceFeaturesI */ public SequenceFeatures() { - featureStore = new HashMap(); + /* + * use a TreeMap so that features are returned in alphabetical order of type + * wrap as a synchronized map for add and delete operations + */ + featureStore = Collections + .synchronizedSortedMap(new TreeMap()); } /** @@ -43,6 +49,11 @@ public class SequenceFeatures implements SequenceFeaturesI public boolean add(SequenceFeature sf) { String type = sf.getType(); + if (type == null) + { + System.err.println("Feature type may not be null: " + sf.toString()); + return false; + } if (featureStore.get(type) == null) { @@ -155,8 +166,21 @@ public class SequenceFeatures implements SequenceFeaturesI */ protected Iterable varargToTypes(String... type) { - return type == null || type.length == 0 ? featureStore - .keySet() : Arrays.asList(type); + if (type == null || type.length == 0) + { + /* + * no vararg parameter supplied + */ + return featureStore.keySet(); + } + + /* + * else make a copy of the list, and remove any null value just in case, + * as it would cause errors looking up the features Map + */ + List types = new ArrayList(Arrays.asList(type)); + types.remove(null); + return types; } /** diff --git a/src/jalview/datamodel/features/SequenceFeaturesI.java b/src/jalview/datamodel/features/SequenceFeaturesI.java index fa77532..cfcdc76 100644 --- a/src/jalview/datamodel/features/SequenceFeaturesI.java +++ b/src/jalview/datamodel/features/SequenceFeaturesI.java @@ -12,7 +12,8 @@ public interface SequenceFeaturesI * Adds one sequence feature to the store, and returns true, unless the * feature is already contained in the store, in which case this method * returns false. Containment is determined by SequenceFeature.equals() - * comparison. + * comparison. Answers false, and does not add the feature, if feature type is + * null. * * @param sf */ diff --git a/src/jalview/gui/IdPanel.java b/src/jalview/gui/IdPanel.java index 2074900..32768b7 100755 --- a/src/jalview/gui/IdPanel.java +++ b/src/jalview/gui/IdPanel.java @@ -325,23 +325,19 @@ public class IdPanel extends JPanel implements MouseListener, { int seq2 = alignPanel.getSeqPanel().findSeq(e); Sequence sq = (Sequence) av.getAlignment().getSequenceAt(seq2); - // build a new links menu based on the current links + any non-positional - // features + + /* + * build a new links menu based on the current links + * and any non-positional features + */ List nlinks = Preferences.sequenceUrlLinks.getLinksForMenu(); - SequenceFeature sfs[] = sq == null ? null : sq.getSequenceFeatures(); - if (sfs != null) + for (SequenceFeature sf : sq.getFeatures().getNonPositionalFeatures()) { - for (SequenceFeature sf : sfs) + if (sf.links != null) { - if (sf.begin == sf.end && sf.begin == 0) + for (String link : sf.links) { - if (sf.links != null && sf.links.size() > 0) - { - for (int l = 0, lSize = sf.links.size(); l < lSize; l++) - { - nlinks.add(sf.links.elementAt(l)); - } - } + nlinks.add(link); } } } diff --git a/src/jalview/io/SequenceAnnotationReport.java b/src/jalview/io/SequenceAnnotationReport.java index 6c8f40f..c3b076c 100644 --- a/src/jalview/io/SequenceAnnotationReport.java +++ b/src/jalview/io/SequenceAnnotationReport.java @@ -57,7 +57,8 @@ public class SequenceAnnotationReport final String linkImageURL; /* - * Comparator to order DBRefEntry by Source + accession id (case-insensitive) + * Comparator to order DBRefEntry by Source + accession id (case-insensitive), + * with 'Primary' sources placed before others */ private static Comparator comparator = new Comparator() { @@ -356,100 +357,121 @@ public class SequenceAnnotationReport { ds = ds.getDatasetSequence(); } + + if (showDbRefs) + { + maxWidth = Math.max(maxWidth, appendDbRefs(sb, ds, summary)); + } + + /* + * add non-positional features if wanted + */ + if (showNpFeats) + { + for (SequenceFeature sf : sequence.getFeatures() + .getNonPositionalFeatures()) + { + int sz = -sb.length(); + appendFeature(sb, 0, minmax, sf); + sz += sb.length(); + maxWidth = Math.max(maxWidth, sz); + } + } + sb.append(""); + return maxWidth; + } + + /** + * A helper method that appends any DBRefs, returning the maximum line length + * added + * + * @param sb + * @param ds + * @param summary + * @return + */ + protected int appendDbRefs(final StringBuilder sb, SequenceI ds, + boolean summary) + { DBRefEntry[] dbrefs = ds.getDBRefs(); - if (showDbRefs && dbrefs != null) + if (dbrefs == null) + { + return 0; + } + + // note this sorts the refs held on the sequence! + Arrays.sort(dbrefs, comparator); + boolean ellipsis = false; + String source = null; + String lastSource = null; + int countForSource = 0; + int sourceCount = 0; + boolean moreSources = false; + int maxLineLength = 0; + int lineLength = 0; + + for (DBRefEntry ref : dbrefs) { - // note this sorts the refs held on the sequence! - Arrays.sort(dbrefs, comparator); - boolean ellipsis = false; - String source = null; - String lastSource = null; - int countForSource = 0; - int sourceCount = 0; - boolean moreSources = false; - int lineLength = 0; - - for (DBRefEntry ref : dbrefs) + source = ref.getSource(); + if (source == null) { - source = ref.getSource(); - if (source == null) - { - // shouldn't happen - continue; - } - boolean sourceChanged = !source.equals(lastSource); - if (sourceChanged) - { - lineLength = 0; - countForSource = 0; - sourceCount++; - } - if (sourceCount > MAX_SOURCES && summary) - { - ellipsis = true; - moreSources = true; - break; - } - lastSource = source; - countForSource++; - if (countForSource == 1 || !summary) - { - sb.append("
"); - } - if (countForSource <= MAX_REFS_PER_SOURCE || !summary) - { - String accessionId = ref.getAccessionId(); - lineLength += accessionId.length() + 1; - if (countForSource > 1 && summary) - { - sb.append(", ").append(accessionId); - lineLength++; - } - else - { - sb.append(source).append(" ").append(accessionId); - lineLength += source.length(); - } - maxWidth = Math.max(maxWidth, lineLength); - } - if (countForSource == MAX_REFS_PER_SOURCE && summary) - { - sb.append(COMMA).append(ELLIPSIS); - ellipsis = true; - } + // shouldn't happen + continue; } - if (moreSources) + boolean sourceChanged = !source.equals(lastSource); + if (sourceChanged) { - sb.append("
").append(ELLIPSIS).append(COMMA).append(source) - .append(COMMA).append(ELLIPSIS); + lineLength = 0; + countForSource = 0; + sourceCount++; } - if (ellipsis) + if (sourceCount > MAX_SOURCES && summary) { - sb.append("
("); - sb.append(MessageManager.getString("label.output_seq_details")); - sb.append(")"); + ellipsis = true; + moreSources = true; + break; } - } - - /* - * add non-positional features if wanted - */ - SequenceFeature[] features = sequence.getSequenceFeatures(); - if (showNpFeats && features != null) - { - for (int i = 0; i < features.length; i++) + lastSource = source; + countForSource++; + if (countForSource == 1 || !summary) + { + sb.append("
"); + } + if (countForSource <= MAX_REFS_PER_SOURCE || !summary) { - if (features[i].begin == 0 && features[i].end == 0) + String accessionId = ref.getAccessionId(); + lineLength += accessionId.length() + 1; + if (countForSource > 1 && summary) { - int sz = -sb.length(); - appendFeature(sb, 0, minmax, features[i]); - sz += sb.length(); - maxWidth = Math.max(maxWidth, sz); + sb.append(", ").append(accessionId); + lineLength++; } + else + { + sb.append(source).append(" ").append(accessionId); + lineLength += source.length(); + } + maxLineLength = Math.max(maxLineLength, lineLength); + } + if (countForSource == MAX_REFS_PER_SOURCE && summary) + { + sb.append(COMMA).append(ELLIPSIS); + ellipsis = true; } } - sb.append(""); - return maxWidth; + if (moreSources) + { + sb.append("
").append(source) + .append(COMMA).append(ELLIPSIS); + } + if (ellipsis) + { + sb.append("
("); + sb.append(MessageManager.getString("label.output_seq_details")); + sb.append(")"); + } + + return maxLineLength; } public void createTooltipAnnotationReport(final StringBuilder tip, diff --git a/test/jalview/datamodel/features/SequenceFeaturesTest.java b/test/jalview/datamodel/features/SequenceFeaturesTest.java index bb11a87..0d1d89d 100644 --- a/test/jalview/datamodel/features/SequenceFeaturesTest.java +++ b/test/jalview/datamodel/features/SequenceFeaturesTest.java @@ -6,6 +6,7 @@ import static org.testng.Assert.assertTrue; import jalview.datamodel.SequenceFeature; +import java.util.Iterator; import java.util.List; import java.util.Set; @@ -237,8 +238,6 @@ public class SequenceFeaturesTest SequenceFeature sf10 = addFeature(sf, "Cath", 40, 100); SequenceFeature sf11 = addFeature(sf, "Cath", 60, 100); SequenceFeature sf12 = addFeature(sf, "Cath", 70, 70); - // null type is weird but possible: - SequenceFeature sf13 = addFeature(sf, null, 5, 12); List overlaps = sf.findFeatures(200, 200, "Pfam"); assertTrue(overlaps.isEmpty()); @@ -281,8 +280,7 @@ public class SequenceFeaturesTest assertTrue(sf.findFeatures(0, 1000, "Metal").isEmpty()); overlaps = sf.findFeatures(7, 7, (String) null); - assertEquals(overlaps.size(), 1); - assertTrue(overlaps.contains(sf13)); + assertTrue(overlaps.isEmpty()); } @Test(groups = "Functional") @@ -508,13 +506,13 @@ public class SequenceFeaturesTest assertEquals(types.size(), 1); assertTrue(types.contains("Metal")); - // null type is possible... + // null type is rejected... SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20, Float.NaN, null); - store.add(sf2); + assertFalse(store.add(sf2)); types = store.getFeatureTypes(); - assertEquals(types.size(), 2); - assertTrue(types.contains(null)); + assertEquals(types.size(), 1); + assertFalse(types.contains(null)); assertTrue(types.contains("Metal")); /* @@ -524,7 +522,7 @@ public class SequenceFeaturesTest Float.NaN, null); store.add(sf3); types = store.getFeatureTypes(); - assertEquals(types.size(), 3); + assertEquals(types.size(), 2); assertTrue(types.contains("Pfam")); /* @@ -534,7 +532,7 @@ public class SequenceFeaturesTest 10, 20, Float.NaN, null); store.add(sf4); types = store.getFeatureTypes(); - assertEquals(types.size(), 4); + assertEquals(types.size(), 3); assertTrue(types.contains("Disulphide Bond")); /* @@ -544,14 +542,14 @@ public class SequenceFeaturesTest Float.NaN, null); store.add(sf5); types = store.getFeatureTypes(); - assertEquals(types.size(), 4); // unchanged + assertEquals(types.size(), 3); // unchanged /* * delete first Pfam - still have one */ assertTrue(store.delete(sf3)); types = store.getFeatureTypes(); - assertEquals(types.size(), 4); + assertEquals(types.size(), 3); assertTrue(types.contains("Pfam")); /* @@ -559,7 +557,7 @@ public class SequenceFeaturesTest */ assertTrue(store.delete(sf5)); types = store.getFeatureTypes(); - assertEquals(types.size(), 3); + assertEquals(types.size(), 2); assertFalse(types.contains("Pfam")); } @@ -580,12 +578,12 @@ public class SequenceFeaturesTest assertEquals(store.getFeatureCount(false), 0); /* - * another positional + * null feature type is rejected */ SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20, Float.NaN, null); - store.add(sf2); - assertEquals(store.getFeatureCount(true), 2); + assertFalse(store.add(sf2)); + assertEquals(store.getFeatureCount(true), 1); assertEquals(store.getFeatureCount(false), 0); /* @@ -594,7 +592,7 @@ public class SequenceFeaturesTest SequenceFeature sf3 = new SequenceFeature("Pfam", "desc", 0, 0, Float.NaN, null); store.add(sf3); - assertEquals(store.getFeatureCount(true), 2); + assertEquals(store.getFeatureCount(true), 1); assertEquals(store.getFeatureCount(false), 1); /* @@ -603,39 +601,39 @@ public class SequenceFeaturesTest SequenceFeature sf4 = new SequenceFeature("Disulphide Bond", "desc", 10, 20, Float.NaN, null); store.add(sf4); - assertEquals(store.getFeatureCount(true), 3); + assertEquals(store.getFeatureCount(true), 2); assertEquals(store.getFeatureCount(false), 1); /* - * add another Pfam + * add another Pfam but this time as a positional feature */ SequenceFeature sf5 = new SequenceFeature("Pfam", "desc", 10, 20, Float.NaN, null); store.add(sf5); - assertEquals(store.getFeatureCount(true), 4); - assertEquals(store.getFeatureCount(false), 1); - assertEquals(store.getFeatureCount(true, "Pfam"), 1); - assertEquals(store.getFeatureCount(false, "Pfam"), 1); + assertEquals(store.getFeatureCount(true), 3); // sf1, sf4, sf5 + assertEquals(store.getFeatureCount(false), 1); // sf3 + assertEquals(store.getFeatureCount(true, "Pfam"), 1); // positional + assertEquals(store.getFeatureCount(false, "Pfam"), 1); // non-positional // search for type==null - assertEquals(store.getFeatureCount(true, (String) null), 1); + assertEquals(store.getFeatureCount(true, (String) null), 0); // search with no type specified - assertEquals(store.getFeatureCount(true, (String[]) null), 4); + assertEquals(store.getFeatureCount(true, (String[]) null), 3); assertEquals(store.getFeatureCount(true, "Metal", "Cath"), 1); assertEquals(store.getFeatureCount(true, "Disulphide Bond"), 1); - assertEquals(store.getFeatureCount(true, "Metal", "Pfam", null), 3); + assertEquals(store.getFeatureCount(true, "Metal", "Pfam", null), 2); /* * delete first Pfam (non-positional) */ assertTrue(store.delete(sf3)); - assertEquals(store.getFeatureCount(true), 4); + assertEquals(store.getFeatureCount(true), 3); assertEquals(store.getFeatureCount(false), 0); /* * delete second Pfam (positional) */ assertTrue(store.delete(sf5)); - assertEquals(store.getFeatureCount(true), 3); + assertEquals(store.getFeatureCount(true), 2); assertEquals(store.getFeatureCount(false), 0); } @@ -653,7 +651,7 @@ public class SequenceFeaturesTest assertEquals(features.size(), 1); assertTrue(features.contains(sf1)); - SequenceFeature sf2 = new SequenceFeature(null, "desc", 10, 20, + SequenceFeature sf2 = new SequenceFeature("Metallic", "desc", 10, 20, Float.NaN, null); store.add(sf2); features = store.getAllFeatures(); @@ -830,4 +828,85 @@ public class SequenceFeaturesTest assertEquals(sf.getMinimumScore("Metal", true), Float.NaN); assertEquals(sf.getMaximumScore("Metal", true), Float.NaN); } + + @Test(groups = "Functional") + public void testVarargsToTypes() + { + SequenceFeatures sf = new SequenceFeatures(); + sf.add(new SequenceFeature("Metal", "desc", 0, 0, Float.NaN, "group")); + sf.add(new SequenceFeature("Cath", "desc", 10, 20, Float.NaN, "group")); + + /* + * no type specified - get all types stored + * they are returned in keyset (alphabetical) order + */ + Iterable types = sf.varargToTypes(); + Iterator iterator = types.iterator(); + assertTrue(iterator.hasNext()); + assertEquals(iterator.next(), "Cath"); + assertTrue(iterator.hasNext()); + assertEquals(iterator.next(), "Metal"); + assertFalse(iterator.hasNext()); + + /* + * empty array is the same as no vararg parameter supplied + * so treated as all stored types + */ + types = sf.varargToTypes(new String[] {}); + iterator = types.iterator(); + assertTrue(iterator.hasNext()); + assertEquals(iterator.next(), "Cath"); + assertTrue(iterator.hasNext()); + assertEquals(iterator.next(), "Metal"); + assertFalse(iterator.hasNext()); + + /* + * null type specified; this is passed as vararg + * String[1] {null} + */ + types = sf.varargToTypes((String) null); + assertFalse(types.iterator().hasNext()); + + /* + * null types array specified; this is passed as vararg null + */ + types = sf.varargToTypes((String[]) null); + iterator = types.iterator(); + assertTrue(iterator.hasNext()); + assertEquals(iterator.next(), "Cath"); + assertTrue(iterator.hasNext()); + assertEquals(iterator.next(), "Metal"); + assertFalse(iterator.hasNext()); + + /* + * one type specified + */ + types = sf.varargToTypes("Metal"); + iterator = types.iterator(); + assertTrue(iterator.hasNext()); + assertEquals(iterator.next(), "Metal"); + assertFalse(iterator.hasNext()); + + /* + * two types specified + */ + types = sf.varargToTypes("Metal", "Helix"); + iterator = types.iterator(); + assertTrue(iterator.hasNext()); + assertEquals(iterator.next(), "Metal"); + assertTrue(iterator.hasNext()); + assertEquals(iterator.next(), "Helix"); + assertFalse(iterator.hasNext()); + + /* + * null type included - should get removed + */ + types = sf.varargToTypes("Metal", null, "Helix"); + iterator = types.iterator(); + assertTrue(iterator.hasNext()); + assertEquals(iterator.next(), "Metal"); + assertTrue(iterator.hasNext()); + assertEquals(iterator.next(), "Helix"); + assertFalse(iterator.hasNext()); + } } diff --git a/test/jalview/io/SequenceAnnotationReportTest.java b/test/jalview/io/SequenceAnnotationReportTest.java index 2895874..9e61bec 100644 --- a/test/jalview/io/SequenceAnnotationReportTest.java +++ b/test/jalview/io/SequenceAnnotationReportTest.java @@ -21,13 +21,21 @@ package jalview.io; import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; +import jalview.datamodel.DBRefEntry; +import jalview.datamodel.Sequence; import jalview.datamodel.SequenceFeature; +import jalview.datamodel.SequenceI; import jalview.gui.JvOptionPane; +import jalview.io.gff.GffConstants; +import java.util.HashMap; import java.util.Hashtable; import java.util.Map; +import junit.extensions.PA; + import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -192,4 +200,134 @@ public class SequenceAnnotationReportTest // if no tag, html-encodes > and < (only): assertEquals("METAL 1 3; <br>&kHD>6", sb.toString()); } + + @Test(groups = "Functional") + public void testCreateSequenceAnnotationReport() + { + SequenceAnnotationReport sar = new SequenceAnnotationReport(null); + StringBuilder sb = new StringBuilder(); + + SequenceI seq = new Sequence("s1", "MAKLKRFQSSTLL"); + seq.setDescription("SeqDesc"); + + sar.createSequenceAnnotationReport(sb, seq, true, true, null); + + /* + * positional features are ignored + */ + seq.addSequenceFeature(new SequenceFeature("Domain", "Ferredoxin", 5, + 10, 1f, null)); + assertEquals("
SeqDesc
", sb.toString()); + + /* + * non-positional feature + */ + seq.addSequenceFeature(new SequenceFeature("Type1", "Nonpos", 0, 0, 1f, + null)); + sb.setLength(0); + sar.createSequenceAnnotationReport(sb, seq, true, true, null); + String expected = "
SeqDesc
Type1 ; Nonpos
"; + assertEquals(expected, sb.toString()); + + /* + * non-positional features not wanted + */ + sb.setLength(0); + sar.createSequenceAnnotationReport(sb, seq, true, false, null); + assertEquals("
SeqDesc
", sb.toString()); + + /* + * add non-pos feature with score inside min-max range for feature type + * minmax holds { [positionalMin, positionalMax], [nonPosMin, nonPosMax] } + * score is only appended for positional features so ignored here! + * minMax are not recorded for non-positional features + */ + seq.addSequenceFeature(new SequenceFeature("Metal", "Desc", 0, 0, 5f, + null)); + Map minmax = new HashMap(); + minmax.put("Metal", new float[][] { null, new float[] { 2f, 5f } }); + sb.setLength(0); + sar.createSequenceAnnotationReport(sb, seq, true, true, minmax); + expected = "
SeqDesc
Metal ; Desc
Type1 ; Nonpos
"; + assertEquals(expected, sb.toString()); + + /* + * 'linkonly' features are ignored; this is obsolete, as linkonly + * is only set by DasSequenceFetcher, and DAS is history + */ + SequenceFeature sf = new SequenceFeature("Metal", "Desc", 0, 0, 5f, + null); + sf.setValue("linkonly", Boolean.TRUE); + seq.addSequenceFeature(sf); + sb.setLength(0); + sar.createSequenceAnnotationReport(sb, seq, true, true, minmax); + assertEquals(expected, sb.toString()); // unchanged! + + /* + * 'clinical_significance' currently being specially included + */ + SequenceFeature sf2 = new SequenceFeature("Variant", "Havana", 0, 0, + 5f, null); + sf2.setValue(GffConstants.CLINICAL_SIGNIFICANCE, "benign"); + seq.addSequenceFeature(sf2); + sb.setLength(0); + sar.createSequenceAnnotationReport(sb, seq, true, true, minmax); + expected = "
SeqDesc
Metal ; Desc
Type1 ; Nonpos
Variant ; Havana; benign
"; + assertEquals(expected, sb.toString()); + + /* + * add dbrefs + */ + seq.addDBRef(new DBRefEntry("PDB", "0", "3iu1")); + seq.addDBRef(new DBRefEntry("Uniprot", "1", "P30419")); + // with showDbRefs = false + sb.setLength(0); + sar.createSequenceAnnotationReport(sb, seq, false, true, minmax); + assertEquals(expected, sb.toString()); // unchanged + // with showDbRefs = true + sb.setLength(0); + sar.createSequenceAnnotationReport(sb, seq, true, true, minmax); + expected = "
SeqDesc
UNIPROT P30419
PDB 3iu1
Metal ; Desc
Type1 ; Nonpos
Variant ; Havana; benign
"; + assertEquals(expected, sb.toString()); + // with showNonPositionalFeatures = false + sb.setLength(0); + sar.createSequenceAnnotationReport(sb, seq, true, false, minmax); + expected = "
SeqDesc
UNIPROT P30419
PDB 3iu1
"; + assertEquals(expected, sb.toString()); + + // see other tests for treatment of status and html + } + + /** + * Test that exercises an abbreviated sequence details report, with ellipsis + * where there are more than 40 different sources, or more than 4 dbrefs for a + * single source + */ + @Test(groups = "Functional") + public void testCreateSequenceAnnotationReport_withEllipsis() + { + SequenceAnnotationReport sar = new SequenceAnnotationReport(null); + StringBuilder sb = new StringBuilder(); + + SequenceI seq = new Sequence("s1", "ABC"); + + int maxSources = (int) PA.getValue(sar, "MAX_SOURCES"); + for (int i = 0; i <= maxSources; i++) + { + seq.addDBRef(new DBRefEntry("PDB" + i, "0", "3iu1")); + } + + int maxRefs = (int) PA.getValue(sar, "MAX_REFS_PER_SOURCE"); + for (int i = 0; i <= maxRefs; i++) + { + seq.addDBRef(new DBRefEntry("Uniprot", "0", "P3041" + i)); + } + + sar.createSequenceAnnotationReport(sb, seq, true, true, null, true); + String report = sb.toString(); + assertTrue(report + .startsWith("
UNIPROT P30410, P30411, P30412, P30413,...
PDB0 3iu1")); + assertTrue(report + .endsWith("
PDB7 3iu1
PDB8,...
(Output Sequence Details to list all database references)
")); + } } -- 1.7.10.2