Clover icon

Coverage Report

  1. Project Clover database Thu Aug 13 2020 12:04:21 BST
  2. Package jalview.io

File SequenceAnnotationReportTest.java

 

Code metrics

4
201
13
1
488
316
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,
66    3, 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,
109    new FeatureRenderer(null), 200); // text should terminate before 200 characters
110  1 String s = sb.toString();
111  1 assertTrue(s.length() < 200);
112  1 assertEquals(n, 7); // should be 7 features left over
113   
114    }
115   
 
116  1 toggle @Test(groups = "Functional")
117    public void testAppendFeature_status()
118    {
119  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
120  1 StringBuilder sb = new StringBuilder();
121  1 SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3,
122    Float.NaN, "group");
123  1 sf.setStatus("Confirmed");
124   
125  1 sar.appendFeature(sb, 1, null, sf, null, 0);
126  1 assertEquals("METAL 1 3; Fe2-S; (Confirmed)", sb.toString());
127    }
128   
 
129  1 toggle @Test(groups = "Functional")
130    public void testAppendFeature_withScore()
131    {
132  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
133  1 StringBuilder sb = new StringBuilder();
134  1 SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3, 1.3f,
135    "group");
136   
137  1 FeatureRendererModel fr = new FeatureRenderer(null);
138  1 Map<String, float[][]> minmax = fr.getMinMax();
139  1 sar.appendFeature(sb, 1, fr, sf, null, 0);
140    /*
141    * map has no entry for this feature type - score is not shown:
142    */
143  1 assertEquals("METAL 1 3; Fe2-S", sb.toString());
144   
145    /*
146    * map has entry for this feature type - score is shown:
147    */
148  1 minmax.put("METAL", new float[][] { { 0f, 1f }, null });
149  1 sar.appendFeature(sb, 1, fr, sf, null, 0);
150    // <br/> is appended to a buffer > 6 in length
151  1 assertEquals("METAL 1 3; Fe2-S<br/>METAL 1 3; Fe2-S Score=1.3",
152    sb.toString());
153   
154    /*
155    * map has min == max for this feature type - score is not shown:
156    */
157  1 minmax.put("METAL", new float[][] { { 2f, 2f }, null });
158  1 sb.setLength(0);
159  1 sar.appendFeature(sb, 1, fr, sf, null, 0);
160  1 assertEquals("METAL 1 3; Fe2-S", sb.toString());
161    }
162   
 
163  1 toggle @Test(groups = "Functional")
164    public void testAppendFeature_noScore()
165    {
166  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
167  1 StringBuilder sb = new StringBuilder();
168  1 SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3,
169    Float.NaN, "group");
170   
171  1 sar.appendFeature(sb, 1, null, sf, null, 0);
172  1 assertEquals("METAL 1 3; Fe2-S", sb.toString());
173    }
174   
175    /**
176    * A specific attribute value is included if it is used to colour the feature
177    */
 
178  1 toggle @Test(groups = "Functional")
179    public void testAppendFeature_colouredByAttribute()
180    {
181  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
182  1 StringBuilder sb = new StringBuilder();
183  1 SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3,
184    Float.NaN, "group");
185  1 sf.setValue("clinical_significance", "Benign");
186   
187    /*
188    * first with no colour by attribute
189    */
190  1 FeatureRendererModel fr = new FeatureRenderer(null);
191  1 sar.appendFeature(sb, 1, fr, sf, null, 0);
192  1 assertEquals("METAL 1 3; Fe2-S", sb.toString());
193   
194    /*
195    * then with colour by an attribute the feature lacks
196    */
197  1 FeatureColourI fc = new FeatureColour(null, Color.white, Color.black,
198    null, 5, 10);
199  1 fc.setAttributeName("Pfam");
200  1 fr.setColour("METAL", fc);
201  1 sb.setLength(0);
202  1 sar.appendFeature(sb, 1, fr, sf, null, 0);
203  1 assertEquals("METAL 1 3; Fe2-S", sb.toString()); // no change
204   
205    /*
206    * then with colour by an attribute the feature has
207    */
208  1 fc.setAttributeName("clinical_significance");
209  1 sb.setLength(0);
210  1 sar.appendFeature(sb, 1, fr, sf, null, 0);
211  1 assertEquals("METAL 1 3; Fe2-S; clinical_significance=Benign",
212    sb.toString());
213    }
214   
 
215  1 toggle @Test(groups = "Functional")
216    public void testAppendFeature_withScoreStatusAttribute()
217    {
218  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
219  1 StringBuilder sb = new StringBuilder();
220  1 SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3, 1.3f,
221    "group");
222  1 sf.setStatus("Confirmed");
223  1 sf.setValue("clinical_significance", "Benign");
224   
225  1 FeatureRendererModel fr = new FeatureRenderer(null);
226  1 Map<String, float[][]> minmax = fr.getMinMax();
227  1 FeatureColourI fc = new FeatureColour(null, Color.white, Color.blue,
228    null, 12, 22);
229  1 fc.setAttributeName("clinical_significance");
230  1 fr.setColour("METAL", fc);
231  1 minmax.put("METAL", new float[][] { { 0f, 1f }, null });
232  1 sar.appendFeature(sb, 1, fr, sf, null, 0);
233   
234  1 assertEquals(
235    "METAL 1 3; Fe2-S Score=1.3; (Confirmed); clinical_significance=Benign",
236    sb.toString());
237    }
238   
 
239  1 toggle @Test(groups = "Functional")
240    public void testAppendFeature_DescEqualsType()
241    {
242  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
243  1 StringBuilder sb = new StringBuilder();
244  1 SequenceFeature sf = new SequenceFeature("METAL", "METAL", 1, 3,
245    Float.NaN, "group");
246   
247    // description is not included if it duplicates type:
248  1 sar.appendFeature(sb, 1, null, sf, null, 0);
249  1 assertEquals("METAL 1 3", sb.toString());
250   
251  1 sb.setLength(0);
252  1 sf.setDescription("Metal");
253    // test is case-sensitive:
254  1 sar.appendFeature(sb, 1, null, sf, null, 0);
255  1 assertEquals("METAL 1 3; Metal", sb.toString());
256    }
257   
 
258  1 toggle @Test(groups = "Functional")
259    public void testAppendFeature_stripHtml()
260    {
261  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
262  1 StringBuilder sb = new StringBuilder();
263  1 SequenceFeature sf = new SequenceFeature("METAL",
264    "<html><body>hello<em>world</em></body></html>", 1, 3,
265    Float.NaN, "group");
266   
267  1 sar.appendFeature(sb, 1, null, sf, null, 0);
268    // !! strips off </body> but not <body> ??
269  1 assertEquals("METAL 1 3; <body>hello<em>world</em>", sb.toString());
270   
271  1 sb.setLength(0);
272  1 sf.setDescription("<br>&kHD>6");
273  1 sar.appendFeature(sb, 1, null, sf, null, 0);
274    // if no <html> tag, html-encodes > and < (only):
275  1 assertEquals("METAL 1 3; &lt;br&gt;&kHD&gt;6", sb.toString());
276    }
277   
 
278  1 toggle @Test(groups = "Functional")
279    public void testCreateSequenceAnnotationReport()
280    {
281  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
282  1 StringBuilder sb = new StringBuilder();
283   
284  1 SequenceI seq = new Sequence("s1", "MAKLKRFQSSTLL");
285  1 seq.setDescription("SeqDesc");
286   
287    /*
288    * positional features are ignored
289    */
290  1 seq.addSequenceFeature(new SequenceFeature("Domain", "Ferredoxin", 5,
291    10, 1f, null));
292  1 sar.createSequenceAnnotationReport(sb, seq, true, true, null);
293  1 assertEquals("<i>SeqDesc</i>", sb.toString());
294   
295    /*
296    * non-positional feature
297    */
298  1 seq.addSequenceFeature(new SequenceFeature("Type1", "Nonpos", 0, 0, 1f,
299    null));
300  1 sb.setLength(0);
301  1 sar.createSequenceAnnotationReport(sb, seq, true, true, null);
302  1 String expected = "<i>SeqDesc<br/>Type1 ; Nonpos Score=1.0</i>";
303  1 assertEquals(expected, sb.toString());
304   
305    /*
306    * non-positional features not wanted
307    */
308  1 sb.setLength(0);
309  1 sar.createSequenceAnnotationReport(sb, seq, true, false, null);
310  1 assertEquals("<i>SeqDesc</i>", sb.toString());
311   
312    /*
313    * add non-pos feature with score inside min-max range for feature type
314    * minmax holds { [positionalMin, positionalMax], [nonPosMin, nonPosMax] }
315    * score is only appended for positional features so ignored here!
316    * minMax are not recorded for non-positional features
317    */
318  1 seq.addSequenceFeature(new SequenceFeature("Metal", "Desc", 0, 0, 5f,
319    null));
320   
321  1 FeatureRendererModel fr = new FeatureRenderer(null);
322  1 Map<String, float[][]> minmax = fr.getMinMax();
323  1 minmax.put("Metal", new float[][] { null, new float[] { 2f, 5f } });
324   
325  1 sb.setLength(0);
326  1 sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
327  1 expected = "<i>SeqDesc<br/>Metal ; Desc<br/>Type1 ; Nonpos</i>";
328  1 assertEquals(expected, sb.toString());
329   
330    /*
331    * 'linkonly' features are ignored; this is obsolete, as linkonly
332    * is only set by DasSequenceFetcher, and DAS is history
333    */
334  1 SequenceFeature sf = new SequenceFeature("Metal", "Desc", 0, 0, 5f,
335    null);
336  1 sf.setValue("linkonly", Boolean.TRUE);
337  1 seq.addSequenceFeature(sf);
338  1 sb.setLength(0);
339  1 sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
340  1 assertEquals(expected, sb.toString()); // unchanged!
341   
342    /*
343    * 'clinical_significance' attribute is only included in description
344    * when used for feature colouring
345    */
346  1 SequenceFeature sf2 = new SequenceFeature("Variant", "Havana", 0, 0,
347    5f, null);
348  1 sf2.setValue(GffConstants.CLINICAL_SIGNIFICANCE, "benign");
349  1 seq.addSequenceFeature(sf2);
350  1 sb.setLength(0);
351  1 sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
352  1 expected = "<i>SeqDesc<br/>Metal ; Desc<br/>Type1 ; Nonpos<br/>Variant ; Havana</i>";
353  1 assertEquals(expected, sb.toString());
354   
355    /*
356    * add dbrefs
357    */
358  1 seq.addDBRef(new DBRefEntry("PDB", "0", "3iu1"));
359  1 seq.addDBRef(new DBRefEntry("Uniprot", "1", "P30419"));
360   
361    // with showDbRefs = false
362  1 sb.setLength(0);
363  1 sar.createSequenceAnnotationReport(sb, seq, false, true, fr);
364  1 assertEquals(expected, sb.toString()); // unchanged
365   
366    // with showDbRefs = true, colour Variant features by clinical_significance
367  1 sb.setLength(0);
368  1 FeatureColourI fc = new FeatureColour(null, Color.green, Color.pink,
369    null, 2, 3);
370  1 fc.setAttributeName("clinical_significance");
371  1 fr.setColour("Variant", fc);
372  1 sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
373  1 expected = "<i>SeqDesc<br/>UNIPROT P30419<br/>PDB 3iu1<br/>Metal ; Desc<br/>"
374    + "Type1 ; Nonpos<br/>Variant ; Havana; clinical_significance=benign</i>";
375  1 assertEquals(expected, sb.toString());
376    // with showNonPositionalFeatures = false
377  1 sb.setLength(0);
378  1 sar.createSequenceAnnotationReport(sb, seq, true, false, fr);
379  1 expected = "<i>SeqDesc<br/>UNIPROT P30419<br/>PDB 3iu1</i>";
380  1 assertEquals(expected, sb.toString());
381   
382    /*
383    * long feature description is truncated with ellipsis
384    */
385  1 sb.setLength(0);
386  1 sf2.setDescription(
387    "This is a very long description which should be truncated");
388  1 sar.createSequenceAnnotationReport(sb, seq, false, true, fr);
389  1 expected = "<i>SeqDesc<br/>Metal ; Desc<br/>Type1 ; Nonpos<br/>Variant ; This is a very long description which sh...; clinical_significance=benign</i>";
390  1 assertEquals(expected, sb.toString());
391   
392    // see other tests for treatment of status and html
393    }
394   
395    /**
396    * Test that exercises an abbreviated sequence details report, with ellipsis
397    * where there are more than 40 different sources, or more than 4 dbrefs for a
398    * single source
399    */
 
400  1 toggle @Test(groups = "Functional")
401    public void testCreateSequenceAnnotationReport_withEllipsis()
402    {
403  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
404  1 StringBuilder sb = new StringBuilder();
405   
406  1 SequenceI seq = new Sequence("s1", "ABC");
407   
408  1 int maxSources = (int) PA.getValue(sar, "MAX_SOURCES");
409  42 for (int i = 0; i <= maxSources; i++)
410    {
411  41 seq.addDBRef(new DBRefEntry("PDB" + i, "0", "3iu1"));
412    }
413   
414  1 int maxRefs = (int) PA.getValue(sar, "MAX_REFS_PER_SOURCE");
415  6 for (int i = 0; i <= maxRefs; i++)
416    {
417  5 seq.addDBRef(new DBRefEntry("Uniprot", "0", "P3041" + i));
418    }
419   
420  1 sar.createSequenceAnnotationReport(sb, seq, true, true, null, true);
421  1 String report = sb.toString();
422  1 assertTrue(report
423    .startsWith(
424    "<i><br/>UNIPROT P30410, P30411, P30412, P30413,...<br/>PDB0 3iu1"));
425  1 assertTrue(report
426    .endsWith(
427    "<br/>PDB7 3iu1<br/>PDB8,...<br/>(Output Sequence Details to list all database references)</i>"));
428    }
429   
430    /**
431    * Test adding a linked feature to the tooltip
432    */
 
433  1 toggle @Test(groups = "Functional")
434    public void testAppendFeature_virtualFeature()
435    {
436    /*
437    * map CDS to peptide sequence
438    */
439  1 SequenceI cds = new Sequence("Cds/101-121", "CCTttgAGAtttCAAatgGAT");
440  1 SequenceI peptide = new Sequence("Peptide/8-14", "PLRFQMD");
441  1 MapList map = new MapList(new int[] { 101, 118 }, new int[] { 8, 13 },
442    3, 1);
443  1 Mapping mapping = new Mapping(peptide, map);
444   
445    /*
446    * assume variant feature found at CDS position 106 G>C
447    */
448  1 List<SequenceFeature> features = new ArrayList<>();
449    // vary ttg (Leu) to ttc (Phe)
450  1 SequenceFeature sf = new SequenceFeature("variant", "G,C", 106, 106,
451    Float.NaN, null);
452  1 features.add(sf);
453  1 MappedFeatures mf = new MappedFeatures(mapping, cds, 9, 'L', features);
454   
455  1 StringBuilder sb = new StringBuilder();
456  1 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
457  1 sar.appendFeature(sb, 1, null, sf, mf, 0);
458   
459    /*
460    * linked feature shown in tooltip in protein coordinates
461    */
462  1 assertEquals("variant 9; G,C", sb.toString());
463   
464    /*
465    * adding "alleles" attribute to variant allows peptide consequence
466    * to be calculated and added to the tooltip
467    */
468  1 sf.setValue("alleles", "G,C");
469  1 sb = new StringBuilder();
470  1 sar.appendFeature(sb, 1, null, sf, mf, 0);
471  1 assertEquals("variant 9; G,C p.Leu9Phe", sb.toString());
472   
473    /*
474    * now a virtual peptide feature on CDS
475    * feature at 11-12 on peptide maps to 110-115 on CDS
476    * here we test for tooltip at 113 (t)
477    */
478  1 SequenceFeature sf2 = new SequenceFeature("metal", "Fe", 11, 12,
479    2.3f, "Uniprot");
480  1 features.clear();
481  1 features.add(sf2);
482  1 mapping = new Mapping(peptide, map);
483  1 mf = new MappedFeatures(mapping, peptide, 113, 't', features);
484  1 sb = new StringBuilder();
485  1 sar.appendFeature(sb, 1, null, sf2, mf, 0);
486  1 assertEquals("metal 110 115; Fe Score=2.3", sb.toString());
487    }
488    }