Clover icon

Coverage Report

  1. Project Clover database Wed Nov 13 2024 16:12:26 GMT
  2. Package jalview.io

File SequenceAnnotationReportTest.java

 

Code metrics

4
201
13
1
498
321
15
0.07
15.46
13
1.15

Classes

Class Line # Actions
SequenceAnnotationReportTest 49 201 15
1.0100%
 

Contributing tests

This file is covered by 12 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.io;
22   
23    import static org.testng.AssertJUnit.assertEquals;
24    import static org.testng.AssertJUnit.assertTrue;
25   
26    import java.awt.Color;
27    import java.util.ArrayList;
28    import java.util.List;
29    import java.util.Map;
30   
31    import org.testng.annotations.BeforeClass;
32    import org.testng.annotations.Test;
33   
34    import jalview.api.FeatureColourI;
35    import jalview.datamodel.DBRefEntry;
36    import jalview.datamodel.MappedFeatures;
37    import jalview.datamodel.Mapping;
38    import jalview.datamodel.Sequence;
39    import jalview.datamodel.SequenceFeature;
40    import jalview.datamodel.SequenceI;
41    import jalview.gui.JvOptionPane;
42    import jalview.io.gff.GffConstants;
43    import jalview.renderer.seqfeatures.FeatureRenderer;
44    import jalview.schemes.FeatureColour;
45    import jalview.util.MapList;
46    import jalview.viewmodel.seqfeatures.FeatureRendererModel;
47    import junit.extensions.PA;
48   
 
49    public class SequenceAnnotationReportTest
50    {
51   
 
52  1 toggle @BeforeClass(alwaysRun = true)
53    public void setUpJvOptionPane()
54    {
55  1 JvOptionPane.setInteractiveMode(false);
56  1 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
57    }
58   
 
59  1 toggle @Test(groups = "Functional")
60    public void testAppendFeature_disulfideBond()
61    {
62  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
63  1 StringBuilder sb = new StringBuilder();
64  1 sb.append("123456");
65  1 SequenceFeature sf = new SequenceFeature("disulfide bond", "desc", 1, 3,
66    1.2f, "group");
67   
68    // residuePos == 2 does not match start or end of feature, nothing done:
69  1 sar.appendFeature(sb, 2, null, sf, null, 0);
70  1 assertEquals("123456", sb.toString());
71   
72    // residuePos == 1 matches start of feature, text appended (but no <br/>)
73    // feature score is not included
74  1 sar.appendFeature(sb, 1, null, sf, null, 0);
75  1 assertEquals("123456disulfide bond 1:3", sb.toString());
76   
77    // residuePos == 3 matches end of feature, text appended
78    // <br/> is prefixed once sb.length() > 6
79  1 sar.appendFeature(sb, 3, null, sf, null, 0);
80  1 assertEquals("123456disulfide bond 1:3<br/>disulfide bond 1:3",
81    sb.toString());
82    }
83   
 
84  1 toggle @Test(groups = "Functional")
85    public void testAppendFeatures_longText()
86    {
87  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
88  1 StringBuilder sb = new StringBuilder();
89  1 String longString = "Abcd".repeat(50);
90  1 SequenceFeature sf = new SequenceFeature("sequence", longString, 1, 3,
91    "group");
92   
93  1 sar.appendFeature(sb, 1, null, sf, null, 0);
94  1 assertTrue(sb.length() < 100);
95   
96  1 List<SequenceFeature> sfl = new ArrayList<>();
97  1 sb.setLength(0);
98  1 sfl.add(sf);
99  1 sfl.add(sf);
100  1 sfl.add(sf);
101  1 sfl.add(sf);
102  1 sfl.add(sf);
103  1 sfl.add(sf);
104  1 sfl.add(sf);
105  1 sfl.add(sf);
106  1 sfl.add(sf);
107  1 sfl.add(sf);
108  1 int n = sar.appendFeatures(sb, 1, sfl, new FeatureRenderer(null), 200); // text
109    // should
110    // terminate
111    // before
112    // 200
113    // characters
114  1 String s = sb.toString();
115  1 assertTrue(s.length() < 200);
116  1 assertEquals(n, 7); // should be 7 features left over
117   
118    }
119   
 
120  1 toggle @Test(groups = "Functional")
121    public void testAppendFeature_status()
122    {
123  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
124  1 StringBuilder sb = new StringBuilder();
125  1 SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3,
126    Float.NaN, "group");
127  1 sf.setStatus("Confirmed");
128   
129  1 sar.appendFeature(sb, 1, null, sf, null, 0);
130  1 assertEquals("METAL 1 3; Fe2-S; (Confirmed)", sb.toString());
131    }
132   
 
133  1 toggle @Test(groups = "Functional")
134    public void testAppendFeature_withScore()
135    {
136  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
137  1 StringBuilder sb = new StringBuilder();
138  1 SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3, 1.3f,
139    "group");
140   
141  1 FeatureRendererModel fr = new FeatureRenderer(null);
142  1 Map<String, float[][]> minmax = fr.getMinMax();
143  1 sar.appendFeature(sb, 1, fr, sf, null, 0);
144    /*
145    * map has no entry for this feature type - score is not shown:
146    */
147  1 assertEquals("METAL 1 3; Fe2-S", sb.toString());
148   
149    /*
150    * map has entry for this feature type - score is shown:
151    */
152  1 minmax.put("METAL", new float[][] { { 0f, 1f }, null });
153  1 sar.appendFeature(sb, 1, fr, sf, null, 0);
154    // <br/> is appended to a buffer > 6 in length
155  1 assertEquals("METAL 1 3; Fe2-S<br/>METAL 1 3; Fe2-S Score=1.3",
156    sb.toString());
157   
158    /*
159    * map has min == max for this feature type - score is not shown:
160    */
161  1 minmax.put("METAL", new float[][] { { 2f, 2f }, null });
162  1 sb.setLength(0);
163  1 sar.appendFeature(sb, 1, fr, sf, null, 0);
164  1 assertEquals("METAL 1 3; Fe2-S", sb.toString());
165    }
166   
 
167  1 toggle @Test(groups = "Functional")
168    public void testAppendFeature_noScore()
169    {
170  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
171  1 StringBuilder sb = new StringBuilder();
172  1 SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3,
173    Float.NaN, "group");
174   
175  1 sar.appendFeature(sb, 1, null, sf, null, 0);
176  1 assertEquals("METAL 1 3; Fe2-S", sb.toString());
177    }
178   
179    /**
180    * A specific attribute value is included if it is used to colour the feature
181    */
 
182  1 toggle @Test(groups = "Functional")
183    public void testAppendFeature_colouredByAttribute()
184    {
185  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
186  1 StringBuilder sb = new StringBuilder();
187  1 SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3,
188    Float.NaN, "group");
189  1 sf.setValue("clinical_significance", "Benign");
190   
191    /*
192    * first with no colour by attribute
193    */
194  1 FeatureRendererModel fr = new FeatureRenderer(null);
195  1 sar.appendFeature(sb, 1, fr, sf, null, 0);
196  1 assertEquals("METAL 1 3; Fe2-S", sb.toString());
197   
198    /*
199    * then with colour by an attribute the feature lacks
200    */
201  1 FeatureColourI fc = new FeatureColour(null, Color.white, Color.black,
202    null, 5, 10);
203  1 fc.setAttributeName("Pfam");
204  1 fr.setColour("METAL", fc);
205  1 sb.setLength(0);
206  1 sar.appendFeature(sb, 1, fr, sf, null, 0);
207  1 assertEquals("METAL 1 3; Fe2-S", sb.toString()); // no change
208   
209    /*
210    * then with colour by an attribute the feature has
211    */
212  1 fc.setAttributeName("clinical_significance");
213  1 sb.setLength(0);
214  1 sar.appendFeature(sb, 1, fr, sf, null, 0);
215  1 assertEquals("METAL 1 3; Fe2-S; clinical_significance=Benign",
216    sb.toString());
217    }
218   
 
219  1 toggle @Test(groups = "Functional")
220    public void testAppendFeature_withScoreStatusAttribute()
221    {
222  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
223  1 StringBuilder sb = new StringBuilder();
224  1 SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3, 1.3f,
225    "group");
226  1 sf.setStatus("Confirmed");
227  1 sf.setValue("clinical_significance", "Benign");
228   
229  1 FeatureRendererModel fr = new FeatureRenderer(null);
230  1 Map<String, float[][]> minmax = fr.getMinMax();
231  1 FeatureColourI fc = new FeatureColour(null, Color.white, Color.blue,
232    null, 12, 22);
233  1 fc.setAttributeName("clinical_significance");
234  1 fr.setColour("METAL", fc);
235  1 minmax.put("METAL", new float[][] { { 0f, 1f }, null });
236  1 sar.appendFeature(sb, 1, fr, sf, null, 0);
237   
238  1 assertEquals(
239    "METAL 1 3; Fe2-S Score=1.3; (Confirmed); clinical_significance=Benign",
240    sb.toString());
241    }
242   
 
243  1 toggle @Test(groups = "Functional")
244    public void testAppendFeature_DescEqualsType()
245    {
246  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
247  1 StringBuilder sb = new StringBuilder();
248  1 SequenceFeature sf = new SequenceFeature("METAL", "METAL", 1, 3,
249    Float.NaN, "group");
250   
251    // description is not included if it duplicates type:
252  1 sar.appendFeature(sb, 1, null, sf, null, 0);
253  1 assertEquals("METAL 1 3", sb.toString());
254   
255  1 sb.setLength(0);
256  1 sf.setDescription("Metal");
257    // test is case-sensitive:
258  1 sar.appendFeature(sb, 1, null, sf, null, 0);
259  1 assertEquals("METAL 1 3; Metal", sb.toString());
260    }
261   
 
262  1 toggle @Test(groups = "Functional")
263    public void testAppendFeature_stripHtml()
264    {
265  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
266  1 StringBuilder sb = new StringBuilder();
267  1 SequenceFeature sf = new SequenceFeature("METAL",
268    "<html><body>hello<em>world</em></body></html>", 1, 3,
269    Float.NaN, "group");
270   
271  1 sar.appendFeature(sb, 1, null, sf, null, 0);
272    // !! strips off </body> but not <body> ??
273  1 assertEquals("METAL 1 3; <body>hello<em>world</em>", sb.toString());
274   
275  1 sb.setLength(0);
276  1 sf.setDescription("<br>&kHD>6");
277  1 sar.appendFeature(sb, 1, null, sf, null, 0);
278    // if no <html> tag, html-encodes > and < (only):
279  1 assertEquals("METAL 1 3; &lt;br&gt;&kHD&gt;6", sb.toString());
280    }
281   
 
282  1 toggle @Test(groups = "Functional")
283    public void testCreateSequenceAnnotationReport()
284    {
285  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
286  1 StringBuilder sb = new StringBuilder();
287   
288  1 SequenceI seq = new Sequence("s1", "MAKLKRFQSSTLL");
289  1 seq.setDescription("SeqDesc");
290   
291    /*
292    * positional features are ignored
293    */
294  1 seq.addSequenceFeature(
295    new SequenceFeature("Domain", "Ferredoxin", 5, 10, 1f, null));
296  1 sar.createSequenceAnnotationReport(sb, seq, true, true, null);
297  1 assertEquals("<i>SeqDesc\n" + "\n" + "</i>", sb.toString());
298   
299    /*
300    * non-positional feature
301    */
302  1 seq.addSequenceFeature(
303    new SequenceFeature("Type1", "Nonpos", 0, 0, 1f, null));
304  1 sb.setLength(0);
305  1 sar.createSequenceAnnotationReport(sb, seq, true, true, null);
306  1 String expected = "<i>SeqDesc\n" + "\n"
307    + "<br/>Type1 ; Nonpos Score=1.0</i>";
308  1 assertEquals(expected, sb.toString());
309   
310    /*
311    * non-positional features not wanted
312    */
313  1 sb.setLength(0);
314  1 sar.createSequenceAnnotationReport(sb, seq, true, false, null);
315  1 assertEquals("<i>SeqDesc\n\n</i>", sb.toString());
316   
317    /*
318    * add non-pos feature with score inside min-max range for feature type
319    * minmax holds { [positionalMin, positionalMax], [nonPosMin, nonPosMax] }
320    * score is only appended for positional features so ignored here!
321    * minMax are not recorded for non-positional features
322    */
323  1 seq.addSequenceFeature(
324    new SequenceFeature("Metal", "Desc", 0, 0, 5f, null));
325   
326  1 FeatureRendererModel fr = new FeatureRenderer(null);
327  1 Map<String, float[][]> minmax = fr.getMinMax();
328  1 minmax.put("Metal", new float[][] { null, new float[] { 2f, 5f } });
329   
330  1 sb.setLength(0);
331  1 sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
332  1 expected = "<i>SeqDesc\n" + "\n"
333    + "<br/>Metal ; Desc<br/>Type1 ; Nonpos</i>";
334  1 assertEquals(expected, sb.toString());
335   
336    /*
337    * 'linkonly' features are ignored; this is obsolete, as linkonly
338    * is only set by DasSequenceFetcher, and DAS is history
339    */
340  1 SequenceFeature sf = new SequenceFeature("Metal", "Desc", 0, 0, 5f,
341    null);
342  1 sf.setValue("linkonly", Boolean.TRUE);
343  1 seq.addSequenceFeature(sf);
344  1 sb.setLength(0);
345  1 sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
346  1 assertEquals(expected, sb.toString()); // unchanged!
347   
348    /*
349    * 'clinical_significance' attribute is only included in description
350    * when used for feature colouring
351    */
352  1 SequenceFeature sf2 = new SequenceFeature("Variant", "Havana", 0, 0, 5f,
353    null);
354  1 sf2.setValue(GffConstants.CLINICAL_SIGNIFICANCE, "benign");
355  1 seq.addSequenceFeature(sf2);
356  1 sb.setLength(0);
357  1 sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
358  1 expected = "<i>SeqDesc\n" + "\n"
359    + "<br/>Metal ; Desc<br/>Type1 ; Nonpos<br/>Variant ; Havana</i>";
360  1 assertEquals(expected, sb.toString());
361   
362    /*
363    * add dbrefs
364    */
365  1 seq.addDBRef(new DBRefEntry("PDB", "0", "3iu1"));
366  1 seq.addDBRef(new DBRefEntry("Uniprot", "1", "P30419"));
367   
368    // with showDbRefs = false
369  1 sb.setLength(0);
370  1 sar.createSequenceAnnotationReport(sb, seq, false, true, fr);
371  1 assertEquals(expected, sb.toString()); // unchanged
372   
373    // with showDbRefs = true, colour Variant features by clinical_significance
374  1 sb.setLength(0);
375  1 FeatureColourI fc = new FeatureColour(null, Color.green, Color.pink,
376    null, 2, 3);
377  1 fc.setAttributeName("clinical_significance");
378  1 fr.setColour("Variant", fc);
379  1 sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
380  1 expected = "<i>SeqDesc\n" + "<br/>\n" + "UNIPROT P30419<br/>\n"
381    + "PDB 3iu1\n"
382    + "<br/>Metal ; Desc<br/>Type1 ; Nonpos<br/>Variant ; Havana; clinical_significance=benign</i>";
383  1 assertEquals(expected, sb.toString());
384    // with showNonPositionalFeatures = false
385  1 sb.setLength(0);
386  1 sar.createSequenceAnnotationReport(sb, seq, true, false, fr);
387  1 expected = "<i>SeqDesc\n" + "<br/>\n" + "UNIPROT P30419<br/>\n"
388    + "PDB 3iu1\n" + "</i>";
389  1 assertEquals(expected, sb.toString());
390   
391    /*
392    * long feature description is truncated with ellipsis
393    */
394  1 sb.setLength(0);
395  1 sf2.setDescription(
396    "This is a very long description which should be truncated");
397  1 sar.createSequenceAnnotationReport(sb, seq, false, true, fr);
398  1 expected = "<i>SeqDesc\n" + "\n"
399    + "<br/>Metal ; Desc<br/>Type1 ; Nonpos<br/>Variant ; This is a very long description which sh...; clinical_significance=benign</i>";
400  1 assertEquals(expected, sb.toString());
401   
402    // see other tests for treatment of status and html
403    }
404   
405    /**
406    * Test that exercises an abbreviated sequence details report, with ellipsis
407    * where there are more than 40 different sources, or more than 4 dbrefs for a
408    * single source
409    */
 
410  1 toggle @Test(groups = "Functional")
411    public void testCreateSequenceAnnotationReport_withEllipsis()
412    {
413  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
414  1 StringBuilder sb = new StringBuilder();
415   
416  1 SequenceI seq = new Sequence("s1", "ABC");
417   
418  1 int maxSources = (int) PA.getValue(sar, "MAX_SOURCES");
419  7 for (int i = 0; i <= maxSources; i++)
420    {
421  6 seq.addDBRef(new DBRefEntry("PDB" + i, "0", "3iu1"));
422    }
423   
424  1 int maxRefs = (int) PA.getValue(sar, "MAX_REFS_PER_SOURCE");
425  6 for (int i = 0; i <= maxRefs; i++)
426    {
427  5 seq.addDBRef(new DBRefEntry("Uniprot", "0", "P3041" + i));
428    }
429   
430  1 sar.createSequenceAnnotationReport(sb, seq, true, true, null, true);
431  1 String report = sb.toString();
432  1 assertTrue(report.startsWith("<i>\n" + "<br/>\n" + "UNIPROT P30410,\n"
433    + " P30411,\n" + " P30412,\n" + " P30413,...<br/>\n"
434    + "PDB0 3iu1<br/>\n" + "PDB1 3iu1<br/>"));
435  1 assertTrue(report.endsWith("PDB3 3iu1<br/>\n" + "PDB4,...<br/>\n"
436    + "(Output Sequence Details to list all database references)\n"
437    + "</i>"));
438    }
439   
440    /**
441    * Test adding a linked feature to the tooltip
442    */
 
443  1 toggle @Test(groups = "Functional")
444    public void testAppendFeature_virtualFeature()
445    {
446    /*
447    * map CDS to peptide sequence
448    */
449  1 SequenceI cds = new Sequence("Cds/101-121", "CCTttgAGAtttCAAatgGAT");
450  1 SequenceI peptide = new Sequence("Peptide/8-14", "PLRFQMD");
451  1 MapList map = new MapList(new int[] { 101, 118 }, new int[] { 8, 13 },
452    3, 1);
453  1 Mapping mapping = new Mapping(peptide, map);
454   
455    /*
456    * assume variant feature found at CDS position 106 G>C
457    */
458  1 List<SequenceFeature> features = new ArrayList<>();
459    // vary ttg (Leu) to ttc (Phe)
460  1 SequenceFeature sf = new SequenceFeature("variant", "G,C", 106, 106,
461    Float.NaN, null);
462  1 features.add(sf);
463  1 MappedFeatures mf = new MappedFeatures(mapping, cds, 9, 'L', features);
464   
465  1 StringBuilder sb = new StringBuilder();
466  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
467  1 sar.appendFeature(sb, 1, null, sf, mf, 0);
468   
469    /*
470    * linked feature shown in tooltip in protein coordinates
471    */
472  1 assertEquals("variant 9; G,C", sb.toString());
473   
474    /*
475    * adding "alleles" attribute to variant allows peptide consequence
476    * to be calculated and added to the tooltip
477    */
478  1 sf.setValue("alleles", "G,C");
479  1 sb = new StringBuilder();
480  1 sar.appendFeature(sb, 1, null, sf, mf, 0);
481  1 assertEquals("variant 9; G,C p.Leu9Phe", sb.toString());
482   
483    /*
484    * now a virtual peptide feature on CDS
485    * feature at 11-12 on peptide maps to 110-115 on CDS
486    * here we test for tooltip at 113 (t)
487    */
488  1 SequenceFeature sf2 = new SequenceFeature("metal", "Fe", 11, 12, 2.3f,
489    "Uniprot");
490  1 features.clear();
491  1 features.add(sf2);
492  1 mapping = new Mapping(peptide, map);
493  1 mf = new MappedFeatures(mapping, peptide, 113, 't', features);
494  1 sb = new StringBuilder();
495  1 sar.appendFeature(sb, 1, null, sf2, mf, 0);
496  1 assertEquals("metal 110 115; Fe Score=2.3", sb.toString());
497    }
498    }