JAL-2069 spike updated with latest (FeatureTypeSettings)
[jalview.git] / test / jalview / io / vcf / VCFLoaderTest.java
1 package jalview.io.vcf;
2
3 import static org.testng.Assert.assertEquals;
4
5 import jalview.bin.Cache;
6 import jalview.datamodel.AlignmentI;
7 import jalview.datamodel.DBRefEntry;
8 import jalview.datamodel.Mapping;
9 import jalview.datamodel.Sequence;
10 import jalview.datamodel.SequenceFeature;
11 import jalview.datamodel.SequenceI;
12 import jalview.datamodel.features.SequenceFeatures;
13 import jalview.gui.AlignFrame;
14 import jalview.io.DataSourceType;
15 import jalview.io.FileLoader;
16 import jalview.io.gff.Gff3Helper;
17 import jalview.io.gff.SequenceOntologyI;
18 import jalview.util.MapList;
19
20 import java.io.File;
21 import java.io.IOException;
22 import java.io.PrintWriter;
23 import java.util.List;
24 import java.util.Map;
25
26 import org.testng.annotations.BeforeClass;
27 import org.testng.annotations.Test;
28
29 public class VCFLoaderTest
30 {
31   private static final float DELTA = 0.00001f;
32
33   // columns 9717- of gene P30419 from Ensembl (much modified)
34   private static final String FASTA = ""
35           +
36           /*
37            * forward strand 'gene' and 'transcript' with two exons
38            */
39           ">gene1/1-25 chromosome:GRCh38:17:45051610:45051634:1\n"
40           + "CAAGCTGGCGGACGAGAGTGTGACA\n"
41           + ">transcript1/1-18\n--AGCTGGCG----AGAGTGTGAC-\n"
42
43           /*
44            * reverse strand gene and transcript (reverse complement alleles!)
45            */
46           + ">gene2/1-25 chromosome:GRCh38:17:45051610:45051634:-1\n"
47           + "TGTCACACTCTCGTCCGCCAGCTTG\n"
48           + ">transcript2/1-18\n" + "-GTCACACTCT----CGCCAGCT--\n"
49
50           /*
51            * 'gene' on chromosome 5 with two transcripts
52            */
53           + ">gene3/1-25 chromosome:GRCh38:5:45051610:45051634:1\n"
54           + "CAAGCTGGCGGACGAGAGTGTGACA\n"
55           + ">transcript3/1-18\n--AGCTGGCG----AGAGTGTGAC-\n"
56           + ">transcript4/1-18\n-----TGG-GGACGAGAGTGTGA-A\n";
57
58   private static final String[] VCF = { "##fileformat=VCFv4.2",
59       "##INFO=<ID=AF,Number=A,Type=Float,Description=\"Allele Frequency, for each ALT allele, in the same order as listed\">",
60       "##reference=Homo_sapiens/GRCh38",
61       "#CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO",
62       // A/T,C variants in position 2 of gene sequence (precedes transcript)
63       // should create 2 variant features with respective scores
64       "17\t45051611\t.\tA\tT,C\t1666.64\tRF\tAC=15;AF=5.0e-03,4.0e-03",
65       // SNP G/C in position 4 of gene sequence, position 2 of transcript
66       // insertion G/GA is transferred to nucleotide but not to peptide
67       "17\t45051613\t.\tG\tGA,C\t1666.64\tRF\tAC=15;AF=3.0e-03,2.0e-03" };
68
69   @BeforeClass
70   public void setUp()
71   {
72     /*
73      * configure to capture all available VCF and VEP (CSQ) fields
74      */
75     Cache.loadProperties("test/jalview/io/testProps.jvprops");
76     Cache.setProperty("VCF_FIELDS", ".*");
77     Cache.setProperty("VEP_FIELDS", ".*");
78   }
79
80   @Test(groups = "Functional")
81   public void testDoLoad() throws IOException
82   {
83     AlignmentI al = buildAlignment();
84     VCFLoader loader = new VCFLoader(al);
85
86     File f = makeVcf();
87
88     loader.doLoad(f.getPath(), null);
89
90     /*
91      * verify variant feature(s) added to gene
92      * NB alleles at a locus may not be processed, and features added,
93      * in the order in which they appear in the VCF record as method
94      * VariantContext.getAlternateAlleles() does not guarantee order
95      * - order of assertions here matches what we find (is not important) 
96      */
97     List<SequenceFeature> geneFeatures = al.getSequenceAt(0)
98             .getSequenceFeatures();
99     SequenceFeatures.sortFeatures(geneFeatures, true);
100     assertEquals(geneFeatures.size(), 4);
101     SequenceFeature sf = geneFeatures.get(0);
102     assertEquals(sf.getFeatureGroup(), "VCF");
103     assertEquals(sf.getBegin(), 2);
104     assertEquals(sf.getEnd(), 2);
105     assertEquals(sf.getScore(), 4.0e-03, DELTA);
106     assertEquals(sf.getValue(Gff3Helper.ALLELES), "A,C");
107     assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
108     sf = geneFeatures.get(1);
109     assertEquals(sf.getFeatureGroup(), "VCF");
110     assertEquals(sf.getBegin(), 2);
111     assertEquals(sf.getEnd(), 2);
112     assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
113     assertEquals(sf.getScore(), 5.0e-03, DELTA);
114     assertEquals(sf.getValue(Gff3Helper.ALLELES), "A,T");
115
116     sf = geneFeatures.get(2);
117     assertEquals(sf.getFeatureGroup(), "VCF");
118     assertEquals(sf.getBegin(), 4);
119     assertEquals(sf.getEnd(), 4);
120     assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
121     assertEquals(sf.getScore(), 2.0e-03, DELTA);
122     assertEquals(sf.getValue(Gff3Helper.ALLELES), "G,C");
123
124     sf = geneFeatures.get(3);
125     assertEquals(sf.getFeatureGroup(), "VCF");
126     assertEquals(sf.getBegin(), 4);
127     assertEquals(sf.getEnd(), 4);
128     assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
129     assertEquals(sf.getScore(), 3.0e-03, DELTA);
130     assertEquals(sf.getValue(Gff3Helper.ALLELES), "G,GA");
131
132     /*
133      * verify variant feature(s) added to transcript
134      */
135     List<SequenceFeature> transcriptFeatures = al.getSequenceAt(1)
136             .getSequenceFeatures();
137     assertEquals(transcriptFeatures.size(), 2);
138     sf = transcriptFeatures.get(0);
139     assertEquals(sf.getFeatureGroup(), "VCF");
140     assertEquals(sf.getBegin(), 2);
141     assertEquals(sf.getEnd(), 2);
142     assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
143     assertEquals(sf.getScore(), 2.0e-03, DELTA);
144     assertEquals(sf.getValue(Gff3Helper.ALLELES), "G,C");
145     sf = transcriptFeatures.get(1);
146     assertEquals(sf.getFeatureGroup(), "VCF");
147     assertEquals(sf.getBegin(), 2);
148     assertEquals(sf.getEnd(), 2);
149     assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
150     assertEquals(sf.getScore(), 3.0e-03, DELTA);
151     assertEquals(sf.getValue(Gff3Helper.ALLELES), "G,GA");
152
153     /*
154      * verify SNP variant feature(s) computed and added to protein
155      * first codon AGC varies to ACC giving S/T
156      */
157     DBRefEntry[] dbRefs = al.getSequenceAt(1).getDBRefs();
158     SequenceI peptide = null;
159     for (DBRefEntry dbref : dbRefs)
160     {
161       if (dbref.getMap().getMap().getFromRatio() == 3)
162       {
163         peptide = dbref.getMap().getTo();
164       }
165     }
166     List<SequenceFeature> proteinFeatures = peptide.getSequenceFeatures();
167     assertEquals(proteinFeatures.size(), 1);
168     sf = proteinFeatures.get(0);
169     assertEquals(sf.getFeatureGroup(), "VCF");
170     assertEquals(sf.getBegin(), 1);
171     assertEquals(sf.getEnd(), 1);
172     assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
173     assertEquals(sf.getDescription(), "p.Ser1Thr");
174   }
175
176   private File makeVcf() throws IOException
177   {
178     File f = File.createTempFile("Test", ".vcf");
179     f.deleteOnExit();
180     PrintWriter pw = new PrintWriter(f);
181     for (String vcfLine : VCF)
182     {
183       pw.println(vcfLine);
184     }
185     pw.close();
186     return f;
187   }
188
189   /**
190    * Make a simple alignment with one 'gene' and one 'transcript'
191    * 
192    * @return
193    */
194   private AlignmentI buildAlignment()
195   {
196     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(FASTA,
197             DataSourceType.PASTE);
198
199     /*
200      * map gene1 sequence to chromosome (normally done when the sequence is fetched
201      * from Ensembl and transcripts computed)
202      */
203     AlignmentI alignment = af.getViewport().getAlignment();
204     SequenceI gene1 = alignment.findName("gene1");
205     int[] to = new int[] { 45051610, 45051634 };
206     int[] from = new int[] { gene1.getStart(), gene1.getEnd() };
207     gene1.setGeneLoci("homo_sapiens", "GRCh38", "17", new MapList(from, to,
208             1, 1));
209
210     /*
211      * map 'transcript1' to chromosome via 'gene1'
212      * transcript1/1-18 is gene1/3-10,15-24
213      * which is chromosome 45051612-45051619,45051624-45051633
214      */
215     to = new int[] { 45051612, 45051619, 45051624, 45051633 };
216     SequenceI transcript1 = alignment.findName("transcript1");
217     from = new int[] { transcript1.getStart(), transcript1.getEnd() };
218     transcript1.setGeneLoci("homo_sapiens", "GRCh38", "17", new MapList(
219             from, to,
220             1, 1));
221
222     /*
223      * map gene2 to chromosome reverse strand
224      */
225     SequenceI gene2 = alignment.findName("gene2");
226     to = new int[] { 45051634, 45051610 };
227     from = new int[] { gene2.getStart(), gene2.getEnd() };
228     gene2.setGeneLoci("homo_sapiens", "GRCh38", "17", new MapList(from, to,
229             1, 1));
230
231     /*
232      * map 'transcript2' to chromosome via 'gene2'
233      * transcript2/1-18 is gene2/2-11,16-23
234      * which is chromosome 45051633-45051624,45051619-45051612
235      */
236     to = new int[] { 45051633, 45051624, 45051619, 45051612 };
237     SequenceI transcript2 = alignment.findName("transcript2");
238     from = new int[] { transcript2.getStart(), transcript2.getEnd() };
239     transcript2.setGeneLoci("homo_sapiens", "GRCh38", "17", new MapList(
240             from, to,
241             1, 1));
242
243     /*
244      * add a protein product as a DBRef on transcript1
245      */
246     SequenceI peptide1 = new Sequence("ENSP001", "SWRECD");
247     MapList mapList = new MapList(new int[] { 1, 18 }, new int[] { 1, 6 },
248             3, 1);
249     Mapping map = new Mapping(peptide1, mapList);
250     DBRefEntry product = new DBRefEntry("", "", "ENSP001", map);
251     transcript1.addDBRef(product);
252
253     /*
254      * add a protein product as a DBRef on transcript2
255      */
256     SequenceI peptide2 = new Sequence("ENSP002", "VTLSPA");
257     mapList = new MapList(new int[] { 1, 18 }, new int[] { 1, 6 }, 3, 1);
258     map = new Mapping(peptide2, mapList);
259     product = new DBRefEntry("", "", "ENSP002", map);
260     transcript2.addDBRef(product);
261
262     /*
263      * map gene3 to chromosome 
264      */
265     SequenceI gene3 = alignment.findName("gene3");
266     to = new int[] { 45051610, 45051634 };
267     from = new int[] { gene3.getStart(), gene3.getEnd() };
268     gene3.setGeneLoci("homo_sapiens", "GRCh38", "5", new MapList(from, to,
269             1, 1));
270
271     /*
272      * map 'transcript3' to chromosome
273      */
274     SequenceI transcript3 = alignment.findName("transcript3");
275     to = new int[] { 45051612, 45051619, 45051624, 45051633 };
276     from = new int[] { transcript3.getStart(), transcript3.getEnd() };
277     transcript3.setGeneLoci("homo_sapiens", "GRCh38", "5", new MapList(
278             from, to,
279             1, 1));
280
281     /*
282      * map 'transcript4' to chromosome
283      */
284     SequenceI transcript4 = alignment.findName("transcript4");
285     to = new int[] { 45051615, 45051617, 45051619, 45051632, 45051634,
286         45051634 };
287     from = new int[] { transcript4.getStart(), transcript4.getEnd() };
288     transcript4.setGeneLoci("homo_sapiens", "GRCh38", "5", new MapList(
289             from, to,
290             1, 1));
291
292     /*
293      * add a protein product as a DBRef on transcript3
294      */
295     SequenceI peptide3 = new Sequence("ENSP003", "SWRECD");
296     mapList = new MapList(new int[] { 1, 18 }, new int[] { 1, 6 }, 3, 1);
297     map = new Mapping(peptide3, mapList);
298     product = new DBRefEntry("", "", "ENSP003", map);
299     transcript3.addDBRef(product);
300
301     return alignment;
302   }
303
304   /**
305    * Test with 'gene' and 'transcript' mapped to the reverse strand of the
306    * chromosome. The VCF variant positions (in forward coordinates) should get
307    * correctly located on sequence positions.
308    * 
309    * @throws IOException
310    */
311   @Test(groups = "Functional")
312   public void testDoLoad_reverseStrand() throws IOException
313   {
314     AlignmentI al = buildAlignment();
315
316     VCFLoader loader = new VCFLoader(al);
317
318     File f = makeVcf();
319
320     loader.doLoad(f.getPath(), null);
321
322     /*
323      * verify variant feature(s) added to gene2
324      * gene/1-25 maps to chromosome 45051634- reverse strand
325      * variants A/T, A/C at 45051611 and G/GA,G/C at 45051613 map to
326      * T/A, T/G and C/TC,C/G at gene positions 24 and 22 respectively
327      */
328     List<SequenceFeature> geneFeatures = al.getSequenceAt(2)
329             .getSequenceFeatures();
330     SequenceFeatures.sortFeatures(geneFeatures, true);
331     assertEquals(geneFeatures.size(), 4);
332     SequenceFeature sf = geneFeatures.get(0);
333     assertEquals(sf.getFeatureGroup(), "VCF");
334     assertEquals(sf.getBegin(), 22);
335     assertEquals(sf.getEnd(), 22);
336     assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
337     assertEquals(sf.getScore(), 2.0e-03, DELTA);
338     assertEquals("C,G", sf.getValue(Gff3Helper.ALLELES));
339
340     sf = geneFeatures.get(1);
341     assertEquals(sf.getFeatureGroup(), "VCF");
342     assertEquals(sf.getBegin(), 22);
343     assertEquals(sf.getEnd(), 22);
344     assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
345     assertEquals(sf.getScore(), 3.0e-03, DELTA);
346     assertEquals("C,TC", sf.getValue(Gff3Helper.ALLELES));
347
348     sf = geneFeatures.get(2);
349     assertEquals(sf.getFeatureGroup(), "VCF");
350     assertEquals(sf.getBegin(), 24);
351     assertEquals(sf.getEnd(), 24);
352     assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
353     assertEquals(sf.getScore(), 4.0e-03, DELTA);
354     assertEquals("T,G", sf.getValue(Gff3Helper.ALLELES));
355
356     sf = geneFeatures.get(3);
357     assertEquals(sf.getFeatureGroup(), "VCF");
358     assertEquals(sf.getBegin(), 24);
359     assertEquals(sf.getEnd(), 24);
360     assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
361     assertEquals(sf.getScore(), 5.0e-03, DELTA);
362     assertEquals("T,A", sf.getValue(Gff3Helper.ALLELES));
363
364     /*
365      * verify variant feature(s) added to transcript2
366      * variants G/GA,G/C at position 22 of gene overlap and map to
367      * C/TC,C/G at position 17 of transcript
368      */
369     List<SequenceFeature> transcriptFeatures = al.getSequenceAt(3)
370             .getSequenceFeatures();
371     assertEquals(transcriptFeatures.size(), 2);
372     sf = transcriptFeatures.get(0);
373     assertEquals(sf.getFeatureGroup(), "VCF");
374     assertEquals(sf.getBegin(), 17);
375     assertEquals(sf.getEnd(), 17);
376     assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
377     assertEquals(sf.getScore(), 2.0e-03, DELTA);
378     assertEquals("C,G", sf.getValue(Gff3Helper.ALLELES));
379
380     sf = transcriptFeatures.get(1);
381     assertEquals(sf.getFeatureGroup(), "VCF");
382     assertEquals(sf.getBegin(), 17);
383     assertEquals(sf.getEnd(), 17);
384     assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
385     assertEquals(sf.getScore(), 3.0e-03, DELTA);
386     assertEquals("C,TC", sf.getValue(Gff3Helper.ALLELES));
387
388     /*
389      * verify variant feature(s) computed and added to protein
390      * last codon GCT varies to GGT giving A/G in the last peptide position
391      */
392     DBRefEntry[] dbRefs = al.getSequenceAt(3).getDBRefs();
393     SequenceI peptide = null;
394     for (DBRefEntry dbref : dbRefs)
395     {
396       if (dbref.getMap().getMap().getFromRatio() == 3)
397       {
398         peptide = dbref.getMap().getTo();
399       }
400     }
401     List<SequenceFeature> proteinFeatures = peptide.getSequenceFeatures();
402     assertEquals(proteinFeatures.size(), 1);
403     sf = proteinFeatures.get(0);
404     assertEquals(sf.getFeatureGroup(), "VCF");
405     assertEquals(sf.getBegin(), 6);
406     assertEquals(sf.getEnd(), 6);
407     assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
408     assertEquals(sf.getDescription(), "p.Ala6Gly");
409   }
410
411   /**
412    * Tests that if VEP consequence (CSQ) data is present in the VCF data, then
413    * it is added to the variant feature, but restricted where possible to the
414    * consequences for a specific transcript
415    * 
416    * @throws IOException
417    */
418   @Test(groups = "Functional")
419   public void testDoLoad_vepCsq() throws IOException
420   {
421     AlignmentI al = buildAlignment();
422
423     VCFLoader loader = new VCFLoader(al);
424
425     /*
426      * VCF data file with variants at gene3 positions
427      * 1 C/A
428      * 5 C/T
429      * 9 CGT/C (deletion)
430      * 13 C/G, C/T
431      * 17 A/AC (insertion), A/G
432      */
433     loader.doLoad("test/jalview/io/vcf/testVcf.dat", null);
434
435     /*
436      * verify variant feature(s) added to gene3
437      */
438     List<SequenceFeature> geneFeatures = al.findName("gene3")
439             .getSequenceFeatures();
440     SequenceFeatures.sortFeatures(geneFeatures, true);
441     assertEquals(geneFeatures.size(), 7);
442     SequenceFeature sf = geneFeatures.get(0);
443     assertEquals(sf.getBegin(), 1);
444     assertEquals(sf.getEnd(), 1);
445     assertEquals(sf.getScore(), 0.1f, DELTA);
446     assertEquals(sf.getValue("alleles"), "C,A");
447     // gene features include Consequence for all transcripts
448     Map map = (Map) sf.getValue("CSQ");
449     assertEquals(map.size(), 9);
450
451     sf = geneFeatures.get(1);
452     assertEquals(sf.getBegin(), 5);
453     assertEquals(sf.getEnd(), 5);
454     assertEquals(sf.getScore(), 0.2f, DELTA);
455     assertEquals(sf.getValue("alleles"), "C,T");
456     map = (Map) sf.getValue("CSQ");
457     assertEquals(map.size(), 9);
458
459     sf = geneFeatures.get(2);
460     assertEquals(sf.getBegin(), 9);
461     assertEquals(sf.getEnd(), 11); // deletion over 3 positions
462     assertEquals(sf.getScore(), 0.3f, DELTA);
463     assertEquals(sf.getValue("alleles"), "CGG,C");
464     map = (Map) sf.getValue("CSQ");
465     assertEquals(map.size(), 9);
466
467     sf = geneFeatures.get(3);
468     assertEquals(sf.getBegin(), 13);
469     assertEquals(sf.getEnd(), 13);
470     assertEquals(sf.getScore(), 0.5f, DELTA);
471     assertEquals(sf.getValue("alleles"), "C,T");
472     map = (Map) sf.getValue("CSQ");
473     assertEquals(map.size(), 9);
474
475     sf = geneFeatures.get(4);
476     assertEquals(sf.getBegin(), 13);
477     assertEquals(sf.getEnd(), 13);
478     assertEquals(sf.getScore(), 0.4f, DELTA);
479     assertEquals(sf.getValue("alleles"), "C,G");
480     map = (Map) sf.getValue("CSQ");
481     assertEquals(map.size(), 9);
482
483     sf = geneFeatures.get(5);
484     assertEquals(sf.getBegin(), 17);
485     assertEquals(sf.getEnd(), 17);
486     assertEquals(sf.getScore(), 0.7f, DELTA);
487     assertEquals(sf.getValue("alleles"), "A,G");
488     map = (Map) sf.getValue("CSQ");
489     assertEquals(map.size(), 9);
490
491     sf = geneFeatures.get(6);
492     assertEquals(sf.getBegin(), 17);
493     assertEquals(sf.getEnd(), 17); // insertion
494     assertEquals(sf.getScore(), 0.6f, DELTA);
495     assertEquals(sf.getValue("alleles"), "A,AC");
496     map = (Map) sf.getValue("CSQ");
497     assertEquals(map.size(), 9);
498
499     /*
500      * verify variant feature(s) added to transcript3
501      * at columns 5 (1), 17 (2), positions 3, 11
502      * note the deletion at columns 9-11 is not transferred since col 11
503      * has no mapping to transcript 3 
504      */
505     List<SequenceFeature> transcriptFeatures = al.findName("transcript3")
506             .getSequenceFeatures();
507     SequenceFeatures.sortFeatures(transcriptFeatures, true);
508     assertEquals(transcriptFeatures.size(), 3);
509     sf = transcriptFeatures.get(0);
510     assertEquals(sf.getBegin(), 3);
511     assertEquals(sf.getEnd(), 3);
512     assertEquals(sf.getScore(), 0.2f, DELTA);
513     assertEquals(sf.getValue("alleles"), "C,T");
514     // transcript features only have Consequence for that transcripts
515     map = (Map) sf.getValue("CSQ");
516     assertEquals(map.size(), 9);
517     assertEquals(sf.getValueAsString("CSQ", "Feature"), "transcript3");
518
519     sf = transcriptFeatures.get(1);
520     assertEquals(sf.getBegin(), 11);
521     assertEquals(sf.getEnd(), 11);
522     assertEquals(sf.getScore(), 0.7f, DELTA);
523     assertEquals(sf.getValue("alleles"), "A,G");
524     assertEquals(map.size(), 9);
525     assertEquals(sf.getValueAsString("CSQ", "Feature"), "transcript3");
526
527     sf = transcriptFeatures.get(2);
528     assertEquals(sf.getBegin(), 11);
529     assertEquals(sf.getEnd(), 11);
530     assertEquals(sf.getScore(), 0.6f, DELTA);
531     assertEquals(sf.getValue("alleles"), "A,AC");
532     assertEquals(map.size(), 9);
533     assertEquals(sf.getValueAsString("CSQ", "Feature"), "transcript3");
534
535     /*
536      * verify variants computed on protein product for transcript3
537      * peptide is SWRECD
538      * codon variants are AGC/AGT position 1 which is synonymous
539      * and GAG/GGG which is E/G in position 4
540      * the insertion variant is not transferred to the peptide
541      */
542     DBRefEntry[] dbRefs = al.findName("transcript3").getDBRefs();
543     SequenceI peptide = null;
544     for (DBRefEntry dbref : dbRefs)
545     {
546       if (dbref.getMap().getMap().getFromRatio() == 3)
547       {
548         peptide = dbref.getMap().getTo();
549       }
550     }
551     List<SequenceFeature> proteinFeatures = peptide.getSequenceFeatures();
552     assertEquals(proteinFeatures.size(), 1);
553     sf = proteinFeatures.get(0);
554     assertEquals(sf.getFeatureGroup(), "VCF");
555     assertEquals(sf.getBegin(), 4);
556     assertEquals(sf.getEnd(), 4);
557     assertEquals(sf.getType(), SequenceOntologyI.SEQUENCE_VARIANT);
558     assertEquals(sf.getDescription(), "p.Glu4Gly");
559
560     /*
561      * verify variant feature(s) added to transcript4
562      * at columns 13 (2) and 17 (2), positions 7 and 11
563      */
564     transcriptFeatures = al.findName("transcript4").getSequenceFeatures();
565     SequenceFeatures.sortFeatures(transcriptFeatures, true);
566     assertEquals(transcriptFeatures.size(), 4);
567     sf = transcriptFeatures.get(0);
568     assertEquals(sf.getBegin(), 7);
569     assertEquals(sf.getEnd(), 7);
570     assertEquals(sf.getScore(), 0.5f, DELTA);
571     assertEquals(sf.getValue("alleles"), "C,T");
572     assertEquals(map.size(), 9);
573     assertEquals(sf.getValueAsString("CSQ", "Feature"), "transcript4");
574
575     sf = transcriptFeatures.get(1);
576     assertEquals(sf.getBegin(), 7);
577     assertEquals(sf.getEnd(), 7);
578     assertEquals(sf.getScore(), 0.4f, DELTA);
579     assertEquals(sf.getValue("alleles"), "C,G");
580     assertEquals(map.size(), 9);
581     assertEquals(sf.getValueAsString("CSQ", "Feature"), "transcript4");
582
583     sf = transcriptFeatures.get(2);
584     assertEquals(sf.getBegin(), 11);
585     assertEquals(sf.getEnd(), 11);
586     assertEquals(sf.getScore(), 0.7f, DELTA);
587     assertEquals(sf.getValue("alleles"), "A,G");
588     assertEquals(map.size(), 9);
589     assertEquals(sf.getValueAsString("CSQ", "Feature"), "transcript4");
590
591     sf = transcriptFeatures.get(3);
592     assertEquals(sf.getBegin(), 11);
593     assertEquals(sf.getEnd(), 11);
594     assertEquals(sf.getScore(), 0.6f, DELTA);
595     assertEquals(sf.getValue("alleles"), "A,AC");
596     assertEquals(map.size(), 9);
597     assertEquals(sf.getValueAsString("CSQ", "Feature"), "transcript4");
598   }
599 }