Clover icon

Coverage Report

  1. Project Clover database Thu Nov 7 2024 17:01:39 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
0.00%
 

Contributing tests

No tests hitting this source file were found.

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  0 toggle @BeforeClass(alwaysRun = true)
53    public void setUpJvOptionPane()
54    {
55  0 JvOptionPane.setInteractiveMode(false);
56  0 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
57    }
58   
 
59  0 toggle @Test(groups = "Functional")
60    public void testAppendFeature_disulfideBond()
61    {
62  0 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
63  0 StringBuilder sb = new StringBuilder();
64  0 sb.append("123456");
65  0 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  0 sar.appendFeature(sb, 2, null, sf, null, 0);
70  0 assertEquals("123456", sb.toString());
71   
72    // residuePos == 1 matches start of feature, text appended (but no <br/>)
73    // feature score is not included
74  0 sar.appendFeature(sb, 1, null, sf, null, 0);
75  0 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  0 sar.appendFeature(sb, 3, null, sf, null, 0);
80  0 assertEquals("123456disulfide bond 1:3<br/>disulfide bond 1:3",
81    sb.toString());
82    }
83   
 
84  0 toggle @Test(groups = "Functional")
85    public void testAppendFeatures_longText()
86    {
87  0 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
88  0 StringBuilder sb = new StringBuilder();
89  0 String longString = "Abcd".repeat(50);
90  0 SequenceFeature sf = new SequenceFeature("sequence", longString, 1, 3,
91    "group");
92   
93  0 sar.appendFeature(sb, 1, null, sf, null, 0);
94  0 assertTrue(sb.length() < 100);
95   
96  0 List<SequenceFeature> sfl = new ArrayList<>();
97  0 sb.setLength(0);
98  0 sfl.add(sf);
99  0 sfl.add(sf);
100  0 sfl.add(sf);
101  0 sfl.add(sf);
102  0 sfl.add(sf);
103  0 sfl.add(sf);
104  0 sfl.add(sf);
105  0 sfl.add(sf);
106  0 sfl.add(sf);
107  0 sfl.add(sf);
108  0 int n = sar.appendFeatures(sb, 1, sfl, new FeatureRenderer(null), 200); // text
109    // should
110    // terminate
111    // before
112    // 200
113    // characters
114  0 String s = sb.toString();
115  0 assertTrue(s.length() < 200);
116  0 assertEquals(n, 7); // should be 7 features left over
117   
118    }
119   
 
120  0 toggle @Test(groups = "Functional")
121    public void testAppendFeature_status()
122    {
123  0 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
124  0 StringBuilder sb = new StringBuilder();
125  0 SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3,
126    Float.NaN, "group");
127  0 sf.setStatus("Confirmed");
128   
129  0 sar.appendFeature(sb, 1, null, sf, null, 0);
130  0 assertEquals("METAL 1 3; Fe2-S; (Confirmed)", sb.toString());
131    }
132   
 
133  0 toggle @Test(groups = "Functional")
134    public void testAppendFeature_withScore()
135    {
136  0 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
137  0 StringBuilder sb = new StringBuilder();
138  0 SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3, 1.3f,
139    "group");
140   
141  0 FeatureRendererModel fr = new FeatureRenderer(null);
142  0 Map<String, float[][]> minmax = fr.getMinMax();
143  0 sar.appendFeature(sb, 1, fr, sf, null, 0);
144    /*
145    * map has no entry for this feature type - score is not shown:
146    */
147  0 assertEquals("METAL 1 3; Fe2-S", sb.toString());
148   
149    /*
150    * map has entry for this feature type - score is shown:
151    */
152  0 minmax.put("METAL", new float[][] { { 0f, 1f }, null });
153  0 sar.appendFeature(sb, 1, fr, sf, null, 0);
154    // <br/> is appended to a buffer > 6 in length
155  0 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  0 minmax.put("METAL", new float[][] { { 2f, 2f }, null });
162  0 sb.setLength(0);
163  0 sar.appendFeature(sb, 1, fr, sf, null, 0);
164  0 assertEquals("METAL 1 3; Fe2-S", sb.toString());
165    }
166   
 
167  0 toggle @Test(groups = "Functional")
168    public void testAppendFeature_noScore()
169    {
170  0 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
171  0 StringBuilder sb = new StringBuilder();
172  0 SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3,
173    Float.NaN, "group");
174   
175  0 sar.appendFeature(sb, 1, null, sf, null, 0);
176  0 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  0 toggle @Test(groups = "Functional")
183    public void testAppendFeature_colouredByAttribute()
184    {
185  0 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
186  0 StringBuilder sb = new StringBuilder();
187  0 SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3,
188    Float.NaN, "group");
189  0 sf.setValue("clinical_significance", "Benign");
190   
191    /*
192    * first with no colour by attribute
193    */
194  0 FeatureRendererModel fr = new FeatureRenderer(null);
195  0 sar.appendFeature(sb, 1, fr, sf, null, 0);
196  0 assertEquals("METAL 1 3; Fe2-S", sb.toString());
197   
198    /*
199    * then with colour by an attribute the feature lacks
200    */
201  0 FeatureColourI fc = new FeatureColour(null, Color.white, Color.black,
202    null, 5, 10);
203  0 fc.setAttributeName("Pfam");
204  0 fr.setColour("METAL", fc);
205  0 sb.setLength(0);
206  0 sar.appendFeature(sb, 1, fr, sf, null, 0);
207  0 assertEquals("METAL 1 3; Fe2-S", sb.toString()); // no change
208   
209    /*
210    * then with colour by an attribute the feature has
211    */
212  0 fc.setAttributeName("clinical_significance");
213  0 sb.setLength(0);
214  0 sar.appendFeature(sb, 1, fr, sf, null, 0);
215  0 assertEquals("METAL 1 3; Fe2-S; clinical_significance=Benign",
216    sb.toString());
217    }
218   
 
219  0 toggle @Test(groups = "Functional")
220    public void testAppendFeature_withScoreStatusAttribute()
221    {
222  0 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
223  0 StringBuilder sb = new StringBuilder();
224  0 SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3, 1.3f,
225    "group");
226  0 sf.setStatus("Confirmed");
227  0 sf.setValue("clinical_significance", "Benign");
228   
229  0 FeatureRendererModel fr = new FeatureRenderer(null);
230  0 Map<String, float[][]> minmax = fr.getMinMax();
231  0 FeatureColourI fc = new FeatureColour(null, Color.white, Color.blue,
232    null, 12, 22);
233  0 fc.setAttributeName("clinical_significance");
234  0 fr.setColour("METAL", fc);
235  0 minmax.put("METAL", new float[][] { { 0f, 1f }, null });
236  0 sar.appendFeature(sb, 1, fr, sf, null, 0);
237   
238  0 assertEquals(
239    "METAL 1 3; Fe2-S Score=1.3; (Confirmed); clinical_significance=Benign",
240    sb.toString());
241    }
242   
 
243  0 toggle @Test(groups = "Functional")
244    public void testAppendFeature_DescEqualsType()
245    {
246  0 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
247  0 StringBuilder sb = new StringBuilder();
248  0 SequenceFeature sf = new SequenceFeature("METAL", "METAL", 1, 3,
249    Float.NaN, "group");
250   
251    // description is not included if it duplicates type:
252  0 sar.appendFeature(sb, 1, null, sf, null, 0);
253  0 assertEquals("METAL 1 3", sb.toString());
254   
255  0 sb.setLength(0);
256  0 sf.setDescription("Metal");
257    // test is case-sensitive:
258  0 sar.appendFeature(sb, 1, null, sf, null, 0);
259  0 assertEquals("METAL 1 3; Metal", sb.toString());
260    }
261   
 
262  0 toggle @Test(groups = "Functional")
263    public void testAppendFeature_stripHtml()
264    {
265  0 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
266  0 StringBuilder sb = new StringBuilder();
267  0 SequenceFeature sf = new SequenceFeature("METAL",
268    "<html><body>hello<em>world</em></body></html>", 1, 3,
269    Float.NaN, "group");
270   
271  0 sar.appendFeature(sb, 1, null, sf, null, 0);
272    // !! strips off </body> but not <body> ??
273  0 assertEquals("METAL 1 3; <body>hello<em>world</em>", sb.toString());
274   
275  0 sb.setLength(0);
276  0 sf.setDescription("<br>&kHD>6");
277  0 sar.appendFeature(sb, 1, null, sf, null, 0);
278    // if no <html> tag, html-encodes > and < (only):
279  0 assertEquals("METAL 1 3; &lt;br&gt;&kHD&gt;6", sb.toString());
280    }
281   
 
282  0 toggle @Test(groups = "Functional")
283    public void testCreateSequenceAnnotationReport()
284    {
285  0 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
286  0 StringBuilder sb = new StringBuilder();
287   
288  0 SequenceI seq = new Sequence("s1", "MAKLKRFQSSTLL");
289  0 seq.setDescription("SeqDesc");
290   
291    /*
292    * positional features are ignored
293    */
294  0 seq.addSequenceFeature(
295    new SequenceFeature("Domain", "Ferredoxin", 5, 10, 1f, null));
296  0 sar.createSequenceAnnotationReport(sb, seq, true, true, null);
297  0 assertEquals("<i>SeqDesc\n" + "\n" + "</i>", sb.toString());
298   
299    /*
300    * non-positional feature
301    */
302  0 seq.addSequenceFeature(
303    new SequenceFeature("Type1", "Nonpos", 0, 0, 1f, null));
304  0 sb.setLength(0);
305  0 sar.createSequenceAnnotationReport(sb, seq, true, true, null);
306  0 String expected = "<i>SeqDesc\n" + "\n"
307    + "<br/>Type1 ; Nonpos Score=1.0</i>";
308  0 assertEquals(expected, sb.toString());
309   
310    /*
311    * non-positional features not wanted
312    */
313  0 sb.setLength(0);
314  0 sar.createSequenceAnnotationReport(sb, seq, true, false, null);
315  0 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  0 seq.addSequenceFeature(
324    new SequenceFeature("Metal", "Desc", 0, 0, 5f, null));
325   
326  0 FeatureRendererModel fr = new FeatureRenderer(null);
327  0 Map<String, float[][]> minmax = fr.getMinMax();
328  0 minmax.put("Metal", new float[][] { null, new float[] { 2f, 5f } });
329   
330  0 sb.setLength(0);
331  0 sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
332  0 expected = "<i>SeqDesc\n" + "\n"
333    + "<br/>Metal ; Desc<br/>Type1 ; Nonpos</i>";
334  0 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  0 SequenceFeature sf = new SequenceFeature("Metal", "Desc", 0, 0, 5f,
341    null);
342  0 sf.setValue("linkonly", Boolean.TRUE);
343  0 seq.addSequenceFeature(sf);
344  0 sb.setLength(0);
345  0 sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
346  0 assertEquals(expected, sb.toString()); // unchanged!
347   
348    /*
349    * 'clinical_significance' attribute is only included in description
350    * when used for feature colouring
351    */
352  0 SequenceFeature sf2 = new SequenceFeature("Variant", "Havana", 0, 0, 5f,
353    null);
354  0 sf2.setValue(GffConstants.CLINICAL_SIGNIFICANCE, "benign");
355  0 seq.addSequenceFeature(sf2);
356  0 sb.setLength(0);
357  0 sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
358  0 expected = "<i>SeqDesc\n" + "\n"
359    + "<br/>Metal ; Desc<br/>Type1 ; Nonpos<br/>Variant ; Havana</i>";
360  0 assertEquals(expected, sb.toString());
361   
362    /*
363    * add dbrefs
364    */
365  0 seq.addDBRef(new DBRefEntry("PDB", "0", "3iu1"));
366  0 seq.addDBRef(new DBRefEntry("Uniprot", "1", "P30419"));
367   
368    // with showDbRefs = false
369  0 sb.setLength(0);
370  0 sar.createSequenceAnnotationReport(sb, seq, false, true, fr);
371  0 assertEquals(expected, sb.toString()); // unchanged
372   
373    // with showDbRefs = true, colour Variant features by clinical_significance
374  0 sb.setLength(0);
375  0 FeatureColourI fc = new FeatureColour(null, Color.green, Color.pink,
376    null, 2, 3);
377  0 fc.setAttributeName("clinical_significance");
378  0 fr.setColour("Variant", fc);
379  0 sar.createSequenceAnnotationReport(sb, seq, true, true, fr);
380  0 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  0 assertEquals(expected, sb.toString());
384    // with showNonPositionalFeatures = false
385  0 sb.setLength(0);
386  0 sar.createSequenceAnnotationReport(sb, seq, true, false, fr);
387  0 expected = "<i>SeqDesc\n" + "<br/>\n" + "UNIPROT P30419<br/>\n"
388    + "PDB 3iu1\n" + "</i>";
389  0 assertEquals(expected, sb.toString());
390   
391    /*
392    * long feature description is truncated with ellipsis
393    */
394  0 sb.setLength(0);
395  0 sf2.setDescription(
396    "This is a very long description which should be truncated");
397  0 sar.createSequenceAnnotationReport(sb, seq, false, true, fr);
398  0 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  0 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  0 toggle @Test(groups = "Functional")
411    public void testCreateSequenceAnnotationReport_withEllipsis()
412    {
413  0 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
414  0 StringBuilder sb = new StringBuilder();
415   
416  0 SequenceI seq = new Sequence("s1", "ABC");
417   
418  0 int maxSources = (int) PA.getValue(sar, "MAX_SOURCES");
419  0 for (int i = 0; i <= maxSources; i++)
420    {
421  0 seq.addDBRef(new DBRefEntry("PDB" + i, "0", "3iu1"));
422    }
423   
424  0 int maxRefs = (int) PA.getValue(sar, "MAX_REFS_PER_SOURCE");
425  0 for (int i = 0; i <= maxRefs; i++)
426    {
427  0 seq.addDBRef(new DBRefEntry("Uniprot", "0", "P3041" + i));
428    }
429   
430  0 sar.createSequenceAnnotationReport(sb, seq, true, true, null, true);
431  0 String report = sb.toString();
432  0 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  0 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  0 toggle @Test(groups = "Functional")
444    public void testAppendFeature_virtualFeature()
445    {
446    /*
447    * map CDS to peptide sequence
448    */
449  0 SequenceI cds = new Sequence("Cds/101-121", "CCTttgAGAtttCAAatgGAT");
450  0 SequenceI peptide = new Sequence("Peptide/8-14", "PLRFQMD");
451  0 MapList map = new MapList(new int[] { 101, 118 }, new int[] { 8, 13 },
452    3, 1);
453  0 Mapping mapping = new Mapping(peptide, map);
454   
455    /*
456    * assume variant feature found at CDS position 106 G>C
457    */
458  0 List<SequenceFeature> features = new ArrayList<>();
459    // vary ttg (Leu) to ttc (Phe)
460  0 SequenceFeature sf = new SequenceFeature("variant", "G,C", 106, 106,
461    Float.NaN, null);
462  0 features.add(sf);
463  0 MappedFeatures mf = new MappedFeatures(mapping, cds, 9, 'L', features);
464   
465  0 StringBuilder sb = new StringBuilder();
466  0 SequenceAnnotationReport sar = new SequenceAnnotationReport(false);
467  0 sar.appendFeature(sb, 1, null, sf, mf, 0);
468   
469    /*
470    * linked feature shown in tooltip in protein coordinates
471    */
472  0 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  0 sf.setValue("alleles", "G,C");
479  0 sb = new StringBuilder();
480  0 sar.appendFeature(sb, 1, null, sf, mf, 0);
481  0 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  0 SequenceFeature sf2 = new SequenceFeature("metal", "Fe", 11, 12, 2.3f,
489    "Uniprot");
490  0 features.clear();
491  0 features.add(sf2);
492  0 mapping = new Mapping(peptide, map);
493  0 mf = new MappedFeatures(mapping, peptide, 113, 't', features);
494  0 sb = new StringBuilder();
495  0 sar.appendFeature(sb, 1, null, sf2, mf, 0);
496  0 assertEquals("metal 110 115; Fe Score=2.3", sb.toString());
497    }
498    }