From f77abf6f05b4464acf639da3ddfd048e19bd9504 Mon Sep 17 00:00:00 2001 From: Andy Menzies Date: Thu, 9 Apr 2015 16:58:46 +0100 Subject: [PATCH 1/5] added ability to zip and tabix index the output file --- bin/AnnotateVcf.pl | 67 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/bin/AnnotateVcf.pl b/bin/AnnotateVcf.pl index 36c000f..7bd2083 100755 --- a/bin/AnnotateVcf.pl +++ b/bin/AnnotateVcf.pl @@ -33,6 +33,8 @@ use Data::Dumper; use List::Util qw(first); +use File::Temp qw(tempfile); +use Try::Tiny qw(try catch); use FindBin qw($Bin); use lib "$Bin/../lib"; @@ -76,6 +78,10 @@ const my $REPRE_BM => Sanger::CGP::Vagrent::Bookmarkers::RepresentativeTranscriptBookmarker->new(); const my $WORST_BM => Sanger::CGP::Vagrent::Bookmarkers::MostDeleteriousBookmarker->new(); +const my $SORT_CMD => 'cat %s | vcf-sort > %s'; +const my $BGZIP_CMD => 'bgzip %s'; +const my $TABIX_CMB => 'tabix -p vcf %s'; + my $header_already_parsed = 0; @@ -86,12 +92,22 @@ unless(defined $options->{'species'} && defined $options->{'assembly'}) { croak 'unable to determine species and assembly from VCF file, please specify on command line' unless find_species_in_vcf($vcf_in,$options); } - open my $OUT_FH, '>', $options->{'output'} or croak 'Failed to create: '.$options->{'output'}; + my $output = $options->{'output'}; + if($options->{'tabix'}){ + (undef,$output) = tempfile('vagrentXXXXXXX', OPEN => 0, SUFFIX => '.vcf'); + } + + open my $OUT_FH, '>', $output or croak 'Failed to create: '.$output; my $annotator = get_annotator($options); process_data($vcf_in,$OUT_FH,$annotator,$options); - close $OUT_FH or croak 'Failed to close: '.$options->{'output'}; - Vcf::validate($options->{'output'}); + close $OUT_FH or croak 'Failed to close: '.$output; + Vcf::validate($output); + + if($options->{'tabix'}){ + compressAndIndex($options,$output); + } + 1; } or do { warn "EVAL_ERROR: $EVAL_ERROR\n" if($EVAL_ERROR); @@ -100,6 +116,44 @@ croak 'A problem occurred'; }; +sub compressAndIndex { + my ($options, $tmpfile) = @_; + + my $sort_cmd = sprintf $SORT_CMD, $tmpfile, $options->{'output'}; + my $bgzip_cmd = sprintf $BGZIP_CMD, $options->{'output'}; + my $totabix = $options->{'output'} .'.gz'; + my $tabix_cmd = sprintf $TABIX_CMB, $totabix; + + try { + my $tabix_in = $options->{'input'}.'.tbx'; + unless(-e $tabix_in){ + # If the input has a tabix index it must have already been sorted, + # we haven't changed the order of the file so we can skip this sort + system($sort_cmd); + } + + } catch { + warn "EXECUTION ERROR: $sort_cmd\n"; + die $_; + }; + + try { + system($bgzip_cmd); + } catch { + warn "EXECUTION ERROR: $bgzip_cmd\n"; + die $_; + }; + + try { + system($tabix_cmd); + } catch { + warn "EXECUTION ERROR: $tabix_cmd\n"; + die $_; + }; + + unlink $tmpfile; +} + sub process_data { my ($in,$out,$anno,$opts) = @_; print $out generate_header($in,$opts); @@ -407,6 +461,7 @@ sub option_builder { 'i|input=s' => \$opts{'input'}, 'o|output=s' => \$opts{'output'}, 'c|cache=s' => \$opts{'cache'}, + 't|tabix' => \$opts{'tabix'}, 'p|process=n' => \$opts{'process'}, 'sp|species=s' => \$opts{'species'}, 'as|assembly=s' => \$opts{'assembly'}, @@ -443,7 +498,7 @@ =head1 NAME =head1 SYNOPSIS -AnnotateVcf.pl [-h] -i -o -c +AnnotateVcf.pl [-h] [-t] -i -o -c [-sp -as ] General Options: @@ -451,7 +506,7 @@ =head1 SYNOPSIS --input (-i) Input vcf file (expects *.bgz) - --output (-o) Output vcf + --output (-o) Output vcf file (plain text, add -t for zip and index) --cache (-c) Vagrent reference data cache file @@ -467,4 +522,6 @@ =head1 SYNOPSIS --process (-p) ID_PROCESS that generated this file + --tabix (-t) bgzip and tabix index the output file (will generate the .gz version of the -o option) + =cut From 9aaf0d75d1e09a2a571c63e11980a458510de09d Mon Sep 17 00:00:00 2001 From: Andy Menzies Date: Thu, 9 Apr 2015 16:59:47 +0100 Subject: [PATCH 2/5] added new ontology term combinations to look up --- share/SequenceOntologySummary.ini | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/share/SequenceOntologySummary.ini b/share/SequenceOntologySummary.ini index 3a3d058..15a936b 100644 --- a/share/SequenceOntologySummary.ini +++ b/share/SequenceOntologySummary.ini @@ -62,8 +62,10 @@ SO:0000010:protein_coding,SO:0000204:five_prime_UTR,SO:0000147:exon,SO:1000002:s SO:0000010:protein_coding,SO:0000204:five_prime_UTR,SO:0000147:exon,SO:1000002:substitution,SO:0001988:5_prime_UTR_premature_start_codon_gain_variant,SO:0001576:transcript_variant=5prime_UTR_variant SO:0000010:protein_coding,SO:0000204:five_prime_UTR,SO:0000147:exon,SO:0000159:deletion,SO:0001623:5_prime_UTR_variant,SO:0001576:transcript_variant=5prime_UTR_variant SO:0000010:protein_coding,SO:0000204:five_prime_UTR,SO:0000147:exon,SO:0000159:deletion,SO:0001636:2KB_upstream_variant,SO:0001623:5_prime_UTR_variant,SO:0001576:transcript_variant=5prime_UTR_variant +SO:0000010:protein_coding,SO:0000204:five_prime_UTR,SO:0000147:exon,SO:0000159:deletion,SO:0001635:5KB_upstream_variant,SO:0001636:2KB_upstream_variant,SO:0001623:5_prime_UTR_variant,SO:0001576:transcript_variant=5prime_UTR_variant SO:0000010:protein_coding,SO:0000204:five_prime_UTR,SO:0000147:exon,SO:0000667:insertion,SO:0001623:5_prime_UTR_variant,SO:0001576:transcript_variant=5prime_UTR_variant SO:0000010:protein_coding,SO:0000204:five_prime_UTR,SO:0000147:exon,SO:1000032:indel,SO:0001623:5_prime_UTR_variant,SO:0001576:transcript_variant=5prime_UTR_variant +SO:0000010:protein_coding,SO:0000204:five_prime_UTR,SO:0000147:exon,SO:1000032:indel,SO:0001636:2KB_upstream_variant,SO:0001623:5_prime_UTR_variant,SO:0001576:transcript_variant=5prime_UTR_variant SO:0000010:protein_coding,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:1000002:substitution,SO:0001624:3_prime_UTR_variant,SO:0001576:transcript_variant=3prime_UTR_variant SO:0000010:protein_coding,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0000159:deletion,SO:0001624:3_prime_UTR_variant,SO:0001576:transcript_variant=3prime_UTR_variant @@ -79,9 +81,12 @@ SO:0000011:non_protein_coding,SO:0000147:exon,SO:0000159:deletion,SO:0001619:nc_ SO:0000011:non_protein_coding,SO:0000147:exon,SO:0000159:deletion,SO:0001634:500B_downstream_variant,SO:0001619:nc_transcript_variant=nc_variant SO:0000011:non_protein_coding,SO:0000147:exon,SO:0000159:deletion,SO:0001636:2KB_upstream_variant,SO:0001619:nc_transcript_variant=nc_variant SO:0000011:non_protein_coding,SO:0000147:exon,SO:0000159:deletion,SO:0001633:5KB_downstream_variant,SO:0001634:500B_downstream_variant,SO:0001619:nc_transcript_variant=nc_variant +SO:0000011:non_protein_coding,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0000159:deletion,SO:0001577:complex_change_in_transcript,SO:0001619:nc_transcript_variant=nc_variant SO:0000011:non_protein_coding,SO:0000147:exon,SO:0000667:insertion,SO:0001619:nc_transcript_variant=nc_variant SO:0000011:non_protein_coding,SO:0000147:exon,SO:1000032:indel,SO:0001619:nc_transcript_variant=nc_variant SO:0000011:non_protein_coding,SO:0000147:exon,SO:1000032:indel,SO:0001636:2KB_upstream_variant,SO:0001619:nc_transcript_variant=nc_variant +SO:0000011:non_protein_coding,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:1000032:indel,SO:0001636:2KB_upstream_variant,SO:0001633:5KB_downstream_variant,SO:0001634:500B_downstream_variant,SO:0001577:complex_change_in_transcript,SO:0001619:nc_transcript_variant=nc_variant +SO:0000011:non_protein_coding,SO:0000147:exon,SO:1000032:indel,SO:0001634:500B_downstream_variant,SO:0001619:nc_transcript_variant=nc_variant SO:0000010:protein_coding,SO:0000316:CDS,SO:0000147:exon,SO:1000002:substitution,SO:0001581:codon_variant,SO:0001583:non_synonymous_codon=missense SO:0000010:protein_coding,SO:0000316:CDS,SO:0000147:exon,SO:1000032:indel,SO:0001650:inframe_variant,SO:1000002:substitution,SO:0001583:non_synonymous_codon=missense @@ -120,16 +125,21 @@ SO:0000010:protein_coding,SO:0000316:CDS,SO:0000147:exon,SO:0000159:deletion,SO: SO:0000010:protein_coding,SO:0000316:CDS,SO:0000147:exon,SO:0000159:deletion,SO:0001589:frameshift_variant,SO:0001576:transcript_variant=frameshift SO:0000010:protein_coding,SO:0000316:CDS,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0000159:deletion,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant,SO:0001578:stop_lost=frameshift SO:0000010:protein_coding,SO:0000316:CDS,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:0000159:deletion,SO:0001633:5KB_downstream_variant,SO:0001634:500B_downstream_variant,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant,SO:0001578:stop_lost=frameshift +SO:0000010:protein_coding,SO:0000316:CDS,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:0000159:deletion,SO:0001633:5KB_downstream_variant,SO:0001634:500B_downstream_variant,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant,SO:0001578:stop_lost=frameshift SO:0000010:protein_coding,SO:0000316:CDS,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:0000159:deletion,SO:0001634:500B_downstream_variant,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant,SO:0001578:stop_lost=frameshift SO:0000010:protein_coding,SO:0000316:CDS,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:0000159:deletion,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant,SO:0001578:stop_lost=frameshift SO:0000010:protein_coding,SO:0000316:CDS,SO:0000147:exon,SO:0000667:insertion,SO:0001589:frameshift_variant=frameshift SO:0000010:protein_coding,SO:0000316:CDS,SO:0000147:exon,SO:1000032:indel,SO:0001589:frameshift_variant=frameshift SO:0000010:protein_coding,SO:0000316:CDS,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:1000032:indel,SO:0001633:5KB_downstream_variant,SO:0001634:500B_downstream_variant,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant,SO:0001578:stop_lost=frameshift +SO:0000010:protein_coding,SO:0000316:CDS,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:1000032:indel,SO:0001634:500B_downstream_variant,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant,SO:0001578:stop_lost=frameshift +SO:0000010:protein_coding,SO:0000316:CDS,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:1000032:indel,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant,SO:0001578:stop_lost=frameshift SO:0000010:protein_coding,SO:0000316:CDS,SO:0000204:five_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:0000159:deletion,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant,SO:0001582:initiator_codon_change=cds_disrupted SO:0000010:protein_coding,SO:0000316:CDS,SO:0000204:five_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:0000159:deletion,SO:0001635:5KB_upstream_variant,SO:0001636:2KB_upstream_variant,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant,SO:0001582:initiator_codon_change=cds_disrupted SO:0000010:protein_coding,SO:0000316:CDS,SO:0000204:five_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:0000159:deletion,SO:0001636:2KB_upstream_variant,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant,SO:0001582:initiator_codon_change=cds_disrupted SO:0000010:protein_coding,SO:0000316:CDS,SO:0000204:five_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:1000032:indel,SO:0001635:5KB_upstream_variant,SO:0001636:2KB_upstream_variant,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant,SO:0001582:initiator_codon_change=cds_disrupted +SO:0000010:protein_coding,SO:0000316:CDS,SO:0000204:five_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:1000032:indel,SO:0001636:2KB_upstream_variant,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant,SO:0001582:initiator_codon_change=cds_disrupted +SO:0000010:protein_coding,SO:0000316:CDS,SO:0000204:five_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:1000032:indel,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant,SO:0001582:initiator_codon_change=cds_disrupted SO:0000011:non_protein_coding,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:1000032:indel,SO:0001635:5KB_upstream_variant,SO:0001636:2KB_upstream_variant,SO:0001577:complex_change_in_transcript,SO:0001619:nc_transcript_variant=nc_transcript_disrupted @@ -138,6 +148,8 @@ SO:0000010:protein_coding,SO:0000316:CDS,SO:0000204:five_prime_UTR,SO:0000205:th SO:0000010:protein_coding,SO:0000316:CDS,SO:0000204:five_prime_UTR,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:0000159:deletion,SO:0001636:2KB_upstream_variant,SO:0001633:5KB_downstream_variant,SO:0001634:500B_downstream_variant,SO:0001577:complex_change_in_transcript=cds_deleted SO:0000010:protein_coding,SO:0000316:CDS,SO:0000204:five_prime_UTR,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:0000159:deletion,SO:0001635:5KB_upstream_variant,SO:0001636:2KB_upstream_variant,SO:0001633:5KB_downstream_variant,SO:0001634:500B_downstream_variant,SO:0001577:complex_change_in_transcript=cds_deleted SO:0000010:protein_coding,SO:0000316:CDS,SO:0000204:five_prime_UTR,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:0000159:deletion,SO:0001634:500B_downstream_variant,SO:0001577:complex_change_in_transcript=cds_deleted +SO:0000010:protein_coding,SO:0000316:CDS,SO:0000204:five_prime_UTR,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:1000032:indel,SO:0001636:2KB_upstream_variant,SO:0001634:500B_downstream_variant,SO:0001577:complex_change_in_transcript,SO:0000159:deletion=cds_deleted +SO:0000010:protein_coding,SO:0000316:CDS,SO:0000204:five_prime_UTR,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:1000032:indel,SO:0001636:2KB_upstream_variant,SO:0001633:5KB_downstream_variant,SO:0001634:500B_downstream_variant,SO:0001577:complex_change_in_transcript,SO:0000159:deletion=cds_deleted SO:0000011:non_protein_coding,SO:0000147:exon,SO:0000159:deletion,SO:0001636:2KB_upstream_variant,SO:0001633:5KB_downstream_variant,SO:0001634:500B_downstream_variant,SO:0001619:nc_transcript_variant=nc_transcript_deleted SO:0000011:non_protein_coding,SO:0000147:exon,SO:0000159:deletion,SO:0001635:5KB_upstream_variant,SO:0001636:2KB_upstream_variant,SO:0001633:5KB_downstream_variant,SO:0001634:500B_downstream_variant,SO:0001619:nc_transcript_variant=nc_transcript_deleted @@ -177,6 +189,7 @@ SO:0000010:protein_coding,SO:0000316:CDS,SO:0000147:exon,SO:0001993:extended_cis SO:0000010:protein_coding,SO:0000316:CDS,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:1000032:indel,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant=ess_splice SO:0000010:protein_coding,SO:0000316:CDS,SO:0001993:extended_cis_splice_site,SO:1000032:indel,SO:0001629:splice_site_variant,SO:0001576:transcript_variant=ess_splice SO:0000010:protein_coding,SO:0000316:CDS,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:1000032:indel,SO:0001995:extended_intronic_splice_region_variant,SO:0001629:splice_site_variant,SO:0001576:transcript_variant=ess_splice +SO:0000010:protein_coding,SO:0000316:CDS,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:1000032:indel,SO:0001995:extended_intronic_splice_region_variant,SO:0001629:splice_site_variant,SO:0001627:intron_variant,SO:0001576:transcript_variant=ess_splice SO:0000010:protein_coding,SO:0000204:five_prime_UTR,SO:0001993:extended_cis_splice_site,SO:1000002:substitution,SO:0001629:splice_site_variant,SO:0001623:5_prime_UTR_variant,SO:0001576:transcript_variant=5prime_UTR_ess_splice SO:0000010:protein_coding,SO:0000204:five_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:0000159:deletion,SO:0001636:2KB_upstream_variant,SO:0001623:5_prime_UTR_variant,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant=5prime_UTR_ess_splice @@ -195,6 +208,7 @@ SO:0000010:protein_coding,SO:0000205:three_prime_UTR,SO:0001993:extended_cis_spl SO:0000010:protein_coding,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:0000159:deletion,SO:0001624:3_prime_UTR_variant,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant=3prime_UTR_ess_splice SO:0000010:protein_coding,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:0000159:deletion,SO:0001633:5KB_downstream_variant,SO:0001634:500B_downstream_variant,SO:0001624:3_prime_UTR_variant,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant=3prime_UTR_ess_splice SO:0000010:protein_coding,SO:0000205:three_prime_UTR,SO:0001993:extended_cis_splice_site,SO:0000159:deletion,SO:0001624:3_prime_UTR_variant,SO:0001629:splice_site_variant,SO:0001576:transcript_variant=3prime_UTR_ess_splice +SO:0000010:protein_coding,SO:0000205:three_prime_UTR,SO:0001993:extended_cis_splice_site,SO:0001996:extended_intronic_splice_region,SO:0000188:intron,SO:0000159:deletion,SO:0001624:3_prime_UTR_variant,SO:0001995:extended_intronic_splice_region_variant,SO:0001629:splice_site_variant,SO:0001627:intron_variant,SO:0001576:transcript_variant=3prime_UTR_ess_splice SO:0000010:protein_coding,SO:0000205:three_prime_UTR,SO:0000147:exon,SO:0001993:extended_cis_splice_site,SO:1000032:indel,SO:0001624:3_prime_UTR_variant,SO:0001577:complex_change_in_transcript,SO:0001576:transcript_variant=3prime_UTR_ess_splice SO:0000011:non_protein_coding,SO:0001993:extended_cis_splice_site,SO:1000002:substitution,SO:0001629:splice_site_variant=nc_ess_splice From 80c0a5059d057c2907f5a713d6361f3469b9e0cc Mon Sep 17 00:00:00 2001 From: Andy Menzies Date: Thu, 9 Apr 2015 17:00:53 +0100 Subject: [PATCH 3/5] updating reference test data, adding some new transcripts for interesting cases --- testData/test_transcript.cache.gz | Bin 3010 -> 3078 bytes testData/test_transcript.cache.gz.tbi | Bin 812 -> 843 bytes testData/test_transcript.fa | 18 ++++++++++++++++++ testData/test_transcript.fa.fai | 1 + 4 files changed, 19 insertions(+) diff --git a/testData/test_transcript.cache.gz b/testData/test_transcript.cache.gz index 4588b221efebfe42c06d37fa1fb199662e601e1d..19b7b740a10a2ca9c8871e74250a507f6459406f 100644 GIT binary patch literal 3078 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 E0I*@W9RL6T diff --git a/testData/test_transcript.cache.gz.tbi b/testData/test_transcript.cache.gz.tbi index 486a61b810c05585aa4bc7017eefd29ed252855f..ac66ee212fa7f574b0159cf98a6cdb0cd46db6ac 100644 GIT binary patch literal 843 zcmb2|=3rp}f&Xj_PR>jWyBXe|UdYSjD8PE5-o1#;(TUqaM4Cxlhp%xlTa=6POEyPF zo$Wj21m64BsabC>wvOMWXdk^VwU31q*ai&9v&bh|pt>TPOyFcvM8yt!g{N3li@A}sI=4|wSu zXx+(bC}JLPuleEO`zdDgr!tKWZ`iKP^0#^qqtMowsw7#9s`xjW>logi+Q@szL4f6esmC;hLctW5e+(0X)1Q3tlr3?7!1U+G zQ#p<_ztvagzB9GoZD$`l_entUnw?7|v%F5tDDs|JbUwNI=a-xJ%AW_nR(-qg{riny zze|BFAfNbmlPjS>DVBkOkwG5Kxl8Go=ulqs}qB zy=BM+3`5ony#j)3-WIdm7FqU@Y1+ZyN|yWwl1UQ}F;~cmt8LsMvVFoH_QUP_&*s=` z9#p#f?SAUi=T=WIxS5wtJRiHW7Q3slIfmii(F@Z~YMn1TwXr*|xM$CG`#;FaT+eKO zFn{N%;<)2`e>@bqyR^S%$&2T|KYp(ct^tNB7(}cS7p+r~$L5_03~!Hay5sZQJ|bAi5j= z?`Cx2kGhS`LD@hD83F@`gL%PGlW7yvx%4YMNU;-5ZNuiz#f*FBb6ofS$bgZ+q#2mu F$^jeL%tQbH diff --git a/testData/test_transcript.fa b/testData/test_transcript.fa index 04aa39a..e9679bb 100644 --- a/testData/test_transcript.fa +++ b/testData/test_transcript.fa @@ -847,3 +847,21 @@ TCTGACAGCTTTATGTACAGCGTATTTTTAGAAAAACTTAAATATACTTCTTTATTTAGG GTTTTATTCTGATGAGCAAGTTTGTGTGTATATGTGTGTATGAGCATTTGTATGTATATA TACTTATACAGATCTATATTATATATACAGTTTTTGTACTATCATTTAAAATAAAAATGT TTCTCAATAAAATGTCAAAGCCGA +>ENST00000335137 +ATGGTGACTGAATTCATTTTTCTGGGTCTCTCTGATTCTCAGGAACTCCAGACCTTCCTA +TTTATGTTGTTTTTTGTATTCTATGGAGGAATCGTGTTTGGAAACCTTCTTATTGTCATA +ACAGTGGTATCTGACTCCCACCTTCACTCTCCCATGTACTTCCTGCTAGCCAACCTCTCA +CTCATTGATCTGTCTCTGTCTTCAGTCACAGCCCCCAAGATGATTACTGACTTTTTCAGC +CAGCGCAAAGTCATCTCTTTCAAGGGCTGCCTTGTTCAGATATTTCTCCTTCACTTCTTT +GGTGGGAGTGAGATGGTGATCCTCATAGCCATGGGCTTTGACAGATATATAGCAATATGC +AAGCCCCTACACTACACTACAATTATGTGTGGCAACGCATGTGTCGGCATTATGGCTGTC +ACATGGGGAATTGGCTTTCTCCATTCGGTGAGCCAGTTGGCGTTTGCCGTGCACTTACTC +TTCTGTGGTCCCAATGAGGTCGATAGTTTTTATTGTGACCTTCCTAGGGTAATCAAACTT +GCCTGTACAGATACCTACAGGCTAGATATTATGGTCATTGCTAACAGTGGTGTGCTCACT +GTGTGTTCTTTTGTTCTTCTAATCATCTCATACACTATCATCCTAATGACCATCCAGCAT +CGCCCTTTAGATAAGTCGTCCAAAGCTCTGTCCACTTTGACTGCTCACATTACAGTAGTT +CTTTTGTTCTTTGGACCATGTGTCTTTATTTATGCCTGGCCATTCCCCATCAAGTCATTA +GATAAATTCCTTGCTGTATTTTATTCTGTGATCACCCCTCTCTTGAACCCAATTATATAC +ACACTGAGGAACAAAGACATGAAGACGGCAATAAGACAGCTGAGAAAATGGGATGCACAT +TCTAGTGTAAAGTTTTAG + diff --git a/testData/test_transcript.fa.fai b/testData/test_transcript.fa.fai index a97b9fb..b1b450e 100644 --- a/testData/test_transcript.fa.fai +++ b/testData/test_transcript.fa.fai @@ -7,3 +7,4 @@ ENST00000339290 3241 21445 60 61 ENST0000037195 9027 24757 60 61 ENST00000367612 7905 33952 60 61 ENST00000368918 8964 42006 60 61 +ENST00000335137 918 51137 60 68 From 38008d535fe4aa180c30cb5abb730939dd51b975 Mon Sep 17 00:00:00 2001 From: Andy Menzies Date: Fri, 10 Apr 2015 11:45:16 +0100 Subject: [PATCH 4/5] adding better handling for variants adjacent to or in the start and stop codons --- .../Vagrent/Annotators/AbstractAnnotator.pm | 68 ++- .../Annotators/SimpleSubstitutionAnnotator.pm | 4 - .../Ontology/SequenceOntologyClassifier.pm | 17 +- t/deletion.t | 495 +++++++++++++++- t/insertion.t | 558 +++++++++++++++++- t/substitution.t | 503 ++++++++++++++++ 6 files changed, 1597 insertions(+), 48 deletions(-) diff --git a/lib/Sanger/CGP/Vagrent/Annotators/AbstractAnnotator.pm b/lib/Sanger/CGP/Vagrent/Annotators/AbstractAnnotator.pm index 48cde27..b039a6a 100644 --- a/lib/Sanger/CGP/Vagrent/Annotators/AbstractAnnotator.pm +++ b/lib/Sanger/CGP/Vagrent/Annotators/AbstractAnnotator.pm @@ -462,18 +462,19 @@ sub _buildProteinAnnotation { # something has gone wrong return undef; } + my $mtDna = $self->_getMutatedCdsSequence($wtDna,$cdsMinPos,$cdsMaxPos,$cAnnot->getMt()); my $mtProt = Bio::Seq->new(-seq => $prePad . $mtDna . $postPad)->translate->seq(); # mutant protein sequence my $maxMtProt = Bio::Seq->new(-seq => $prePad . $mtDna . substr($tran->getcDNASeq,$tran->getCdsMaxPos()))->translate->seq(); # maximised protein sequence, overruns the natural stop and translates to the end of the transcript if($wtProt eq $mtProt){ # wt and mt protein sequences are the same, its silent $mutProtMin = ceil(($cAnnot->getMinPos / 3)); - $mutProtMax = ceil(($cAnnot->getMaxPos / 3)); - $wt = substr($wtProt,($mutProtMin - 1),(($mutProtMax - $mutProtMin) + 1)); - $mt = substr($mtProt,($mutProtMin - 1),(($mutProtMax - $mutProtMin) + 1)); - if(length($wt) == 1 && length($mt) == 1 && $mutProtMin == $mutProtMax){ - $desc = 'p.'.$wt.$mutProtMin.$mt; - } else { + $mutProtMax = ceil(($cAnnot->getMaxPos / 3)); + $wt = substr($wtProt,($mutProtMin - 1),(($mutProtMax - $mutProtMin) + 1)); + $mt = substr($mtProt,($mutProtMin - 1),(($mutProtMax - $mutProtMin) + 1)); + if(length($wt) == 1 && length($mt) == 1 && $mutProtMin == $mutProtMax){ + $desc = 'p.'.$wt.$mutProtMin.$mt; + } else { $desc = 'p.(=)'; } $type = $self->_getDefaultProteinAnnotationType(); @@ -495,10 +496,10 @@ sub _buildProteinAnnotation { if($mutProtMin == 1){ # its frame shifted the start codon, no idea what this is going to cause. push(@classes,$self->getStartLostVariantClass); - return $self->_buildUnknownProteinAnnotation($var,$tran,$cAnnot,length($wtProt),@classes); - } + return $self->_buildUnknownProteinAnnotation($var,$tran,$cAnnot,length($wtProt),@classes); + } $type = Sanger::CGP::Vagrent::Data::Annotation::getFrameShiftAnnotationType(); - push(@classes,$self->getFrameShiftVariantClass); + push(@classes,$self->getFrameShiftVariantClass); } else { $wt = $wtProt; $mt = $mtProt; @@ -512,7 +513,7 @@ sub _buildProteinAnnotation { substr($wt,-1,1,''); substr($mt,-1,1,''); } - + #warn "|$wt| to |$mt|\n"; if($wt ne ''){ # wild type residue has been changed @@ -617,8 +618,6 @@ sub _buildProteinAnnotation { subtype => $subtype); $anno->addClassification(@classes); return $anno; - - return undef; } sub _getMutatedCdsSequence: Abstract; @@ -637,7 +636,6 @@ sub _buildCDSAnnotation { return $self->_buildUnknownCDSAnnotation($var,$tran,$rAnnot,@classes); } my ($cdsMin,$cdsMinOffset,$cdsMax,$cdsMaxOffset) = (undef,undef,undef,undef); - if($rAnnot->getMinPos < $tran->getCdsMinPos){ $cdsMin = 1; $cdsMinOffset = 0; @@ -668,6 +666,8 @@ sub _buildCDSAnnotation { $cdsMaxOffset = $rAnnot->getMaxOffset(); } + print "CDS: $cdsMin , $cdsMinOffset - $cdsMax, $cdsMaxOffset\n" if $self->_debug(); + my $wt = $self->_getWildTypeStringForCDSAnno($var,$tran,$rAnnot); my $mt = $self->_getMutantStringForCDSAnno($var,$tran,$rAnnot); my $desc = $self->_getCDSDescriptionString($tran,$cdsMin,$cdsMax,$cdsMinOffset,$cdsMaxOffset,$wt,$mt); @@ -959,21 +959,6 @@ sub _coversStopCodon { return 1; } } - - - -# if($anno->getContext eq Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()){ -# if($anno->getMinPos <= $tran->getCdsMaxPos && $anno->getMaxPos >= $tran->getCdsMaxPos - 2){ -# return 1; -# } -# } elsif($anno->getContext eq Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext()){ -# if($anno->getMinPos <= $tran->getCdsLength && $anno->getMaxPos >= $tran->getCdsLength - 2){ -# return 1; -# } -# } else { -# # don't know, assume no -# return 0; -# } return 0; } @@ -1025,10 +1010,25 @@ sub _canAnnotateToCDS { if($anno->hasClassification($self->getInsertionClass)){ # insertions are a special case. # Coordinates are the last WT positions, and not the first variant ones like everything else - if($anno->getMaxPos <= $tran->getCdsMinPos || $anno->getMinPos >= $tran->getCdsMaxPos){ - # its outside the CDS - return 0; - } + + print 'ANNO POS: '.$anno->getMinPos.' , '.$anno->getMinOffset.' - '.$anno->getMaxPos.' , '.$anno->getMaxOffset."\n" if $self->_debug(); + print 'CDS POS: '.$tran->getCdsMinPos.' , '.$tran->getCdsMaxPos."\n" if $self->_debug(); + + if($anno->getMaxPos < $tran->getCdsMinPos || $anno->getMinPos > $tran->getCdsMaxPos){ + # ends before CDS or starts afterwards + return 0; + } elsif($anno->getMaxPos == $tran->getCdsMinPos) { + # potential start codon issues + if($anno->getMinPos == $anno->getMaxPos && $anno->getMinPos == $tran->getCdsMinPos && abs($anno->getMinOffset) + abs($anno->getMaxOffset) > 0){ + # probably start coordinate issues + unless($anno->getMaxOffset <= 0 && $self->_isIntronicOffsetDistance($anno->getMaxOffset) == 0){ + # or not + return 0; + } + } else { + return 0; + } + } } else { if($anno->getMaxPos < $tran->getCdsMinPos || $anno->getMinPos > $tran->getCdsMaxPos){ # its outside the CDS @@ -1050,6 +1050,9 @@ sub _canAnnotateToCDS { return 0; } elsif($anno->hasClassification($self->getUnknownVariantClass)){ return 0; + } elsif($anno->hasClassification($self->getInsertionClass) && $anno->hasClassification($self->get5PrimeUtrVariantClass)){ + # odd case, insertions close to the start codons can be described on the CDS even though they don't change it. + return 1; } else { my $msg = "Unable to calculate CDS relevance - UNKNOWN CLASSIFICATION: ".join(' ',$anno->getClassifications); $self->addMessage($msg); @@ -1066,6 +1069,7 @@ sub _canAnnotateToCDS { sub _canAnnotateToProtein { my ($self,$tran,$anno) = @_; + unless($tran->isProteinCoding){ # if the transcript isn't protein coding it can't be a coding change return 0; diff --git a/lib/Sanger/CGP/Vagrent/Annotators/SimpleSubstitutionAnnotator.pm b/lib/Sanger/CGP/Vagrent/Annotators/SimpleSubstitutionAnnotator.pm index b272240..4c5552d 100644 --- a/lib/Sanger/CGP/Vagrent/Annotators/SimpleSubstitutionAnnotator.pm +++ b/lib/Sanger/CGP/Vagrent/Annotators/SimpleSubstitutionAnnotator.pm @@ -190,18 +190,14 @@ sub _buildRNAAnnotation { } if($tran->isProteinCoding){ - #print "HERE\n"; if(($pos > $tran->getCdsMinPos || ($pos == $tran->getCdsMinPos && $offset >= 0)) && ($pos < $tran->getCdsMaxPos || ($pos == $tran->getCdsMaxPos && $offset <= 0))){ -# if($pos >= $tran->getCdsMinPos && $pos <= $tran->getCdsMaxPos){ # coding change push(@groupClasses,$self->getCDSClass); } elsif($pos < $tran->getCdsMinPos || ($pos == $tran->getCdsMinPos && $offset < 0)){ -# } elsif($pos < $tran->getCdsMinPos){ # 5prime UTR push(@groupClasses,$self->get5PrimeUtrClass); } elsif($pos > $tran->getCdsMaxPos || ($pos == $tran->getCdsMaxPos && $offset > 0)){ -# } elsif($pos > $tran->getCdsMaxPos){ # 3prime UTR push(@groupClasses,$self->get3PrimeUtrClass); } else { diff --git a/lib/Sanger/CGP/Vagrent/Ontology/SequenceOntologyClassifier.pm b/lib/Sanger/CGP/Vagrent/Ontology/SequenceOntologyClassifier.pm index b14e928..9562655 100644 --- a/lib/Sanger/CGP/Vagrent/Ontology/SequenceOntologyClassifier.pm +++ b/lib/Sanger/CGP/Vagrent/Ontology/SequenceOntologyClassifier.pm @@ -100,14 +100,15 @@ const my $SO_NON_PROTEIN_CODING_CLASS => 'SO:0000011:non_protein_coding'; const my $TERM_SUMMARY_INI => 'SequenceOntologySummary.ini'; -#sub DESTROY { -# my $self = shift; -# if(defined $self->{'_SOsum'}){ -# foreach my $k( sort {$self->{'_notSummary'}->{$b} <=> $self->{'_notSummary'}->{$a}} keys %{$self->{'_notSummary'}}){ -# print $self->{'_notSummary'}->{$k},' - ',$k,"\n" unless $self->{'_notSummary'}->{$k} == 1; -# } -# } -#} +# sub DESTROY { +# ##### Handy DESTROY function that will print ontology combinations that don't exist in the summary lookup at program termination. +# my $self = shift; +# if(defined $self->{'_SOsum'}){ +# foreach my $k( sort {$self->{'_notSummary'}->{$b} <=> $self->{'_notSummary'}->{$a}} keys %{$self->{'_notSummary'}}){ +# print $self->{'_notSummary'}->{$k},' - ',$k,"\n" unless $self->{'_notSummary'}->{$k} == 0; +# } +# } +# } sub _ontologyInit { my $self = shift; diff --git a/t/deletion.t b/t/deletion.t index a0b3072..aca81c0 100644 --- a/t/deletion.t +++ b/t/deletion.t @@ -45,6 +45,8 @@ testSplice(); testExonic(); testComplexCases(); testUpStreamDownStream(); +testCdsBoundry(); + done_testing(); sub testUpStreamDownStream { @@ -331,6 +333,7 @@ sub testSplice { } sub testExonic { + #5 PRIME UTR EXON 1bp DEL test5PrimeUTR_1bp_CEP350(AnnotationTestUtils::CEP350_TRANSCRIPT); test5PrimeUTR_1bp_TOR1AIP2(AnnotationTestUtils::TOR1AIP2_TRANSCRIPT); @@ -415,7 +418,6 @@ sub testExonic { testCDSExon_StartCodon_2bp_3_CEP350(AnnotationTestUtils::CEP350_TRANSCRIPT); testCDSExon_StartCodon_4bp_1_CEP350(AnnotationTestUtils::CEP350_TRANSCRIPT); - #NON-CODING TRANSCRIPT testExon_1bp_1_AC068831(AnnotationTestUtils::AC068831_TRANSCRIPT); testExon_1bp_2_AC068831(AnnotationTestUtils::AC068831_TRANSCRIPT); @@ -425,6 +427,497 @@ sub testExonic { } +sub testCdsBoundry{ + + testStartUpstream_OR4F5(); + testStartEndsUpsteam1bp_OR4F5(); + testStartEndsUpsteam0bp_OR4F5(); + testEndStarts0bp_OR4F5(); + testEndStarts1bp_OR4F5(); + testEndDownstream_OR4F5(); + + testStartUpstream_GABPB2(); + testStartIntronic_GABPB2(); + testStartSpliceRegion_GABPB2(); + testStartEssSplice_GABPB2(); + +} + +# OR4F5 protein coding gene - single exon, no UTRs, has both start and stop codons, + strand (probably wrong but great for testing) + +sub testStartUpstream_OR4F5 { + subtest 'Testing OR4F5 5 Prime UTR Upstream + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + my $sub = Sanger::CGP::Vagrent::Data::Deletion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 68091, + 'maxpos' => 68091, + 'delseq' => 'C'); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::DeletionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getDeletionClass,$a->get2KBUpStreamVariantClass); + done_testing(); + }; + +} +sub testStartEndsUpsteam1bp_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 Ends Upstream 1 + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Deletion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 69090, + 'maxpos' => 69090, + 'delseq' => 'C'); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::DeletionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getDeletionClass,$a->get2KBUpStreamVariantClass); + + done_testing(); + }; +} +sub testStartEndsUpsteam0bp_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 Ends Upstream 0 + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Deletion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 69090, + 'maxpos' => 69090, + 'delseq' => 'C'); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::DeletionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getDeletionClass,$a->get2KBUpStreamVariantClass); + + done_testing(); + }; +} +sub testEndStarts0bp_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 Starts Downstream 0 + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Deletion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 70009, + 'maxpos' => 70009, + 'delseq' => 'C'); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::DeletionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getDeletionClass,$a->get500BPDownStreamVariantClass); + + done_testing(); + }; + + + +} +sub testEndStarts1bp_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 Starts Downstream 1 + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Deletion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 70010, + 'maxpos' => 70010, + 'delseq' => 'C'); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::DeletionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getDeletionClass,$a->get500BPDownStreamVariantClass); + + done_testing(); + }; + + + +} +sub testEndDownstream_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 Starts Downstream + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Deletion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 71010, + 'maxpos' => 71010, + 'delseq' => 'C'); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::DeletionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getDeletionClass,$a->get5KBDownStreamVariantClass); + + done_testing(); + }; + + + +} + +# GABPB2 protein coding gene with both utrs on + strand of genome, start codon is at the start of an exon + +sub testStartUpstream_GABPB2 { + my $file = shift; + + subtest 'Testing GABPB2 5 Prime UTR Upstream + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Deletion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 151042080, + 'maxpos' => 151042080, + 'delseq' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::DeletionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getDeletionClass,$a->get2KBUpStreamVariantClass); + done_testing(); + }; + +} +sub testStartIntronic_GABPB2 { + my $file = shift; + + subtest 'Testing GABPB2 5 Prime UTR Intronic + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Deletion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 151060460, + 'maxpos' => 151060460, + 'delseq' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::DeletionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass,$a->get5PrimeUtrClass,$a->getIntronClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getDeletionClass,$a->getIntronVariantClass); + done_testing(); + }; + +} +sub testStartSpliceRegion_GABPB2 { + my $file = shift; + + subtest 'Testing GABPB2 5 Prime UTR Splice Region + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Deletion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 151060660, + 'maxpos' => 151060660, + 'delseq' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::DeletionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),3,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'has have CDS context annotation'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'has have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass,$a->get5PrimeUtrClass,$a->getSpliceRegionClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getDeletionAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffsetSubtype(), + 332,-6,332,-6,'C','-','r.332-6delc',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getDeletionClass,$a->getSpliceRegionVariantClass,$a->get5PrimeUtrVariantClass); + + AnnotationTestUtils::checkAnnotation('examine CDS annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getDeletionAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffsetSubtype(), + 1,-6,1,-6,'C','-','c.1-6delc',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getDeletionClass,$a->getSpliceRegionVariantClass,$a->get5PrimeUtrVariantClass); + + AnnotationTestUtils::checkAnnotation('examine Protein annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','p.?',$t[0]->getProteinAccession,$t[0]->getProteinAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getUnknownVariantClass); + done_testing(); + }; + +} +sub testStartEssSplice_GABPB2 { + my $file = shift; + + subtest 'Testing GABPB2 5 Prime UTR Ess Splice + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Deletion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 151060665, + 'maxpos' => 151060665, + 'delseq' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::DeletionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),3,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'has have CDS context annotation'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'has have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass,$a->getEssentialSpliceSiteClass,$a->get5PrimeUtrClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getDeletionAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffsetSubtype(), + 332,-1,332,-1,'C','-','r.332-1delc',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getDeletionClass,$a->get5PrimeUtrVariantClass,$a->getEssentialSpliceSiteVariantClass); + + AnnotationTestUtils::checkAnnotation('examine CDS annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getDeletionAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffsetSubtype(), + 1,-1,1,-1,'C','-','c.1-1delc',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getDeletionClass,$a->get5PrimeUtrVariantClass,$a->getEssentialSpliceSiteVariantClass); + + AnnotationTestUtils::checkAnnotation('examine Protein annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','p.?',$t[0]->getProteinAccession,$t[0]->getProteinAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getUnknownVariantClass); + done_testing(); + }; + +} + + # CEP350 protein coding gene with 5 prime utr exons on + strand of genome sub testUpsteamMilesAway_1bp_CEP350 { diff --git a/t/insertion.t b/t/insertion.t index 2b70daf..307bbd8 100644 --- a/t/insertion.t +++ b/t/insertion.t @@ -45,8 +45,27 @@ testSplice(); testExonic(); testUpStreamDownStream(); testStrangeCases(); +testCdsBoundry(); done_testing(); + +sub testCdsBoundry { + + testStartUpstream_OR4F5(); + testStartEndsUpsteam1bp_OR4F5(); + testStartEndsUpsteam0bp_OR4F5(); + testEndStarts0bp_OR4F5(); + testEndStarts1bp_OR4F5(); + testEndDownstream_OR4F5(); + + testStartUpstream_GABPB2(); + testStartIntronic_GABPB2(); + testStartSpliceRegion_GABPB2(); + testStartEssSplice_GABPB2(); + testStartEssSplice2_GABPB2(); + +} + sub testUpStreamDownStream { testUpsteamMilesAway_CEP350(AnnotationTestUtils::CEP350_TRANSCRIPT); testEndsUpsteam5001bp_CEP350(AnnotationTestUtils::CEP350_TRANSCRIPT); @@ -85,9 +104,7 @@ sub testUpStreamDownStream { testStartsDownstreamMilesAway_TOR1AIP2(AnnotationTestUtils::TOR1AIP2_TRANSCRIPT); } - sub testStrangeCases { -#CENTRE OF INTRONS ' => sub { testIntronic_DeadCenterOfEvenSizedIntron_CEP350(AnnotationTestUtils::CEP350_TRANSCRIPT); testIntronic_StartingDeadCenterOfOddSizedIntron_CEP350(AnnotationTestUtils::CEP350_TRANSCRIPT); testIntronic_EndingDeadCenterOfOddSizedIntron_CEP350(AnnotationTestUtils::CEP350_TRANSCRIPT); @@ -319,6 +336,541 @@ sub testExonic { } +# OR4F5 protein coding gene - single exon, no UTRs, has both start and stop codons, + strand (probably wrong but great for testing) + +sub testStartUpstream_OR4F5 { + subtest 'Testing OR4F5 5 Prime UTR Upstream + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + my $sub = Sanger::CGP::Vagrent::Data::Insertion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 68091, + 'maxpos' => 68092, + 'insseq' => 'C'); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::InsertionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getInsertionClass,$a->get2KBUpStreamVariantClass); + done_testing(); + }; + +} +sub testStartEndsUpsteam1bp_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 Ends Upstream 1 + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Insertion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 69089, + 'maxpos' => 69090, + 'insseq' => 'C'); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::InsertionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getInsertionClass,$a->get2KBUpStreamVariantClass); + + done_testing(); + }; +} +sub testStartEndsUpsteam0bp_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 Ends Upstream 0 + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Insertion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 69090, + 'maxpos' => 69091, + 'insseq' => 'C'); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::InsertionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getInsertionClass,$a->get2KBUpStreamVariantClass); + + done_testing(); + }; +} +sub testEndStarts0bp_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 Starts Downstream 0 + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Insertion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 70008, + 'maxpos' => 70009, + 'insseq' => 'C'); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::InsertionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getInsertionClass,$a->get500BPDownStreamVariantClass); + + done_testing(); + }; + + + +} +sub testEndStarts1bp_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 Starts Downstream 1 + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Insertion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 70009, + 'maxpos' => 70010, + 'insseq' => 'C'); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::InsertionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getInsertionClass,$a->get500BPDownStreamVariantClass); + + done_testing(); + }; + + + +} +sub testEndDownstream_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 Starts Downstream + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Insertion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 71009, + 'maxpos' => 71010, + 'insseq' => 'C'); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::InsertionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getInsertionClass,$a->get5KBDownStreamVariantClass); + + done_testing(); + }; + + + +} + + +# GABPB2 protein coding gene with both utrs on + strand of genome, start codon is at the start of an exon + +sub testStartUpstream_GABPB2 { + my $file = shift; + + subtest 'Testing GABPB2 5 Prime UTR Upstream + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Insertion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 151042080, + 'maxpos' => 151042081, + 'insseq' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::InsertionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getInsertionClass,$a->get2KBUpStreamVariantClass); + done_testing(); + }; + +} +sub testStartIntronic_GABPB2 { + my $file = shift; + + subtest 'Testing GABPB2 5 Prime UTR Intronic + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Insertion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 151060460, + 'maxpos' => 151060461, + 'insseq' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::InsertionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass,$a->get5PrimeUtrClass,$a->getIntronClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getInsertionClass,$a->getIntronVariantClass); + done_testing(); + }; + +} +sub testStartSpliceRegion_GABPB2 { + my $file = shift; + + subtest 'Testing GABPB2 5 Prime UTR Splice Region + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Insertion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 151060660, + 'maxpos' => 151060661, + 'insseq' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::InsertionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),3,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'has have CDS context annotation'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'has have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass,$a->get5PrimeUtrClass,$a->getSpliceRegionClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getInsertionAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffsetSubtype(), + 332,-6,332,-5,'-','C','r.332-6_332-5insc',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getInsertionClass,$a->getSpliceRegionVariantClass,$a->get5PrimeUtrVariantClass); + + AnnotationTestUtils::checkAnnotation('examine CDS annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getInsertionAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffsetSubtype(), + 1,-6,1,-5,'-','C','c.1-6_1-5insC',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getInsertionClass,$a->getSpliceRegionVariantClass,$a->get5PrimeUtrVariantClass); + + AnnotationTestUtils::checkAnnotation('examine Protein annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','p.?',$t[0]->getProteinAccession,$t[0]->getProteinAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getUnknownVariantClass); + done_testing(); + }; + +} +sub testStartEssSplice_GABPB2 { + my $file = shift; + + subtest 'Testing GABPB2 5 Prime UTR Ess Splice + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Insertion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 151060664, + 'maxpos' => 151060665, + 'insseq' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::InsertionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),3,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'has have CDS context annotation'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'has have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass,$a->getEssentialSpliceSiteClass,$a->get5PrimeUtrClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getInsertionAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffsetSubtype(), + 332,-2,332,-1,'-','C','r.332-2_332-1insc',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getInsertionClass,$a->get5PrimeUtrVariantClass,$a->getEssentialSpliceSiteVariantClass); + + AnnotationTestUtils::checkAnnotation('examine CDS annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getInsertionAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffsetSubtype(), + 1,-2,1,-1,'-','C','c.1-2_1-1insC',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getInsertionClass,$a->get5PrimeUtrVariantClass,$a->getEssentialSpliceSiteVariantClass); + + AnnotationTestUtils::checkAnnotation('examine Protein annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','p.?',$t[0]->getProteinAccession,$t[0]->getProteinAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getUnknownVariantClass); + done_testing(); + }; + +} +sub testStartEssSplice2_GABPB2 { + my $file = shift; + + subtest 'Testing GABPB2 5 Prime UTR Ess Splice + strand 2' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Insertion->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 151060665, + 'maxpos' => 151060666, + 'insseq' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::InsertionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),3,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'has have CDS context annotation'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'has have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass,$a->getExonClass,$a->get5PrimeUtrClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getInsertionAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffsetSubtype(), + 332,-1,332,0,'-','C','r.332-1_332insc',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getInsertionClass,$a->get5PrimeUtrVariantClass); + + AnnotationTestUtils::checkAnnotation('examine CDS annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getInsertionAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffsetSubtype(), + 1,-1,1,0,'-','C','c.1-1_1insC',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getInsertionClass,$a->get5PrimeUtrVariantClass); + + AnnotationTestUtils::checkAnnotation('examine Protein annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','p.?',$t[0]->getProteinAccession,$t[0]->getProteinAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getUnknownVariantClass); + done_testing(); + }; + +} + + # CEP350 protein coding gene with 5 prime utr exons on + strand of genome @@ -5062,7 +5614,7 @@ sub testCDSStartAdjacent_1bp_TOR1AIP2 { sub testCDSStartAdjacent_3bp_TOR1AIP2 { my $file = shift; - subtest 'Testing TOR1AIP2 5 prime UTR 1bp - strand CDS start adjacent' => sub { + subtest 'Testing TOR1AIP2 5 prime UTR 3bp - strand CDS start adjacent' => sub { my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); diff --git a/t/substitution.t b/t/substitution.t index 4aa0344..8f16b4d 100755 --- a/t/substitution.t +++ b/t/substitution.t @@ -45,6 +45,7 @@ testIntronic(); testSplice(); testExonic(); testUpStreamDownStream(); +testCDSBoundry(); done_testing(); @@ -261,6 +262,508 @@ sub testExonic { done_testing(); }; } +sub testCDSBoundry { + subtest 'Testing Start ' => sub { + testStartUpstream_GABPB2(); + testStartIntronic_GABPB2(); + testStartSpliceRegion_GABPB2(); + testStartEssSplice_GABPB2(); + + testStartUpstream_OR4F5(); + testStartSpliceRegion_OR4F5(); + testStartEssSplice_OR4F5(); + + done_testing(); + }; + + subtest 'Testing End ' => sub { + + testEndEssSplice_OR4F5(); + testEndSpliceRegion_OR4F5(); + testEndDownstream_OR4F5(); + + done_testing(); + }; +} + +# GABPB2 protein coding gene with both utrs on + strand of genome, start codon is at the start of an exon + +sub testStartUpstream_GABPB2 { + my $file = shift; + + subtest 'Testing GABPB2 5 Prime UTR Upstream + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Substitution->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 151042080, + 'maxpos' => 151042080, + 'wt' => 'T', + 'mt' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::SimpleSubstitutionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getSubstitutionClass,$a->get2KBUpStreamVariantClass); + done_testing(); + }; + +} +sub testStartIntronic_GABPB2 { + my $file = shift; + + subtest 'Testing GABPB2 5 Prime UTR Intronic + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Substitution->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 151060460, + 'maxpos' => 151060460, + 'wt' => 'T', + 'mt' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::SimpleSubstitutionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass,$a->get5PrimeUtrClass,$a->getIntronClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getSubstitutionClass,$a->getIntronVariantClass); + done_testing(); + }; + +} +sub testStartSpliceRegion_GABPB2 { + my $file = shift; + + subtest 'Testing GABPB2 5 Prime UTR Splice Region + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Substitution->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 151060660, + 'maxpos' => 151060660, + 'wt' => 'T', + 'mt' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::SimpleSubstitutionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),3,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'has have CDS context annotation'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'has have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass,$a->get5PrimeUtrClass,$a->getSpliceRegionClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getSubstitutionAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffsetSubtype(), + 332,-6,332,-6,'U','C','r.332-6u>c',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getSubstitutionClass,$a->getSpliceRegionVariantClass,$a->get5PrimeUtrVariantClass); + + AnnotationTestUtils::checkAnnotation('examine CDS annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getSubstitutionAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffsetSubtype(), + 1,-6,1,-6,'T','C','c.1-6T>C',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getSubstitutionClass,$a->getSpliceRegionVariantClass,$a->get5PrimeUtrVariantClass); + + AnnotationTestUtils::checkAnnotation('examine Protein annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','p.?',$t[0]->getProteinAccession,$t[0]->getProteinAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getUnknownVariantClass); + done_testing(); + }; + +} +sub testStartEssSplice_GABPB2 { + my $file = shift; + + subtest 'Testing GABPB2 5 Prime UTR Ess Splice + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Substitution->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 151060665, + 'maxpos' => 151060665, + 'wt' => 'G', + 'mt' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::SimpleSubstitutionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),3,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'has have CDS context annotation'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'has have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass,$a->get5PrimeUtrClass,$a->getEssentialSpliceSiteClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getSubstitutionAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffsetSubtype(), + 332,-1,332,-1,'G','C','r.332-1g>c',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getSubstitutionClass,$a->getEssentialSpliceSiteVariantClass,$a->get5PrimeUtrVariantClass); + + AnnotationTestUtils::checkAnnotation('examine CDS annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getSubstitutionAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffsetSubtype(), + 1,-1,1,-1,'G','C','c.1-1G>C',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getSubstitutionClass,$a->getEssentialSpliceSiteVariantClass,$a->get5PrimeUtrVariantClass); + + AnnotationTestUtils::checkAnnotation('examine Protein annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','p.?',$t[0]->getProteinAccession,$t[0]->getProteinAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getUnknownVariantClass); + done_testing(); + }; + +} + +# OR4F5 protein coding gene - single exon, no UTRs, has both start and stop codons, + strand (probably wrong but great for testing) + +sub testStartUpstream_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 5 Prime UTR Upstream + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Substitution->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 68091, + 'maxpos' => 68091, + 'wt' => 'T', + 'mt' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::SimpleSubstitutionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getSubstitutionClass,$a->get2KBUpStreamVariantClass); + done_testing(); + }; + +} +sub testStartSpliceRegion_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 5 Prime UTR Splice Region + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Substitution->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 69085, + 'maxpos' => 69085, + 'wt' => 'T', + 'mt' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::SimpleSubstitutionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getSubstitutionClass,$a->get2KBUpStreamVariantClass); + done_testing(); + }; + +} +sub testStartEssSplice_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 5 Prime UTR Ess Splice + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Substitution->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 69090, + 'maxpos' => 69090, + 'wt' => 'T', + 'mt' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::SimpleSubstitutionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getSubstitutionClass,$a->get2KBUpStreamVariantClass); + done_testing(); + }; + +} +sub testEndEssSplice_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 3 Prime UTR Ess Splice + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Substitution->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 70009, + 'maxpos' => 70009, + 'wt' => 'T', + 'mt' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::SimpleSubstitutionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getSubstitutionClass,$a->get500BPDownStreamVariantClass); + done_testing(); + }; + +} +sub testEndSpliceRegion_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 3 Prime UTR Splice Region + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Substitution->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 70015, + 'maxpos' => 70015, + 'wt' => 'T', + 'mt' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::SimpleSubstitutionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getSubstitutionClass,$a->get500BPDownStreamVariantClass); + done_testing(); + }; + +} +sub testEndDownstream_OR4F5 { + my $file = shift; + + subtest 'Testing OR4F5 Downstream + strand 1' => sub { + my $ts = Sanger::CGP::Vagrent::TranscriptSource::FileBasedTranscriptSource->new('cache' => AnnotationTestUtils::TRANSCRIPT_CACHE); + + + my $sub = Sanger::CGP::Vagrent::Data::Substitution->new( + 'species' => 'human', + 'genomeVersion' => 'GRCh37', + 'chr' => 1, + 'minpos' => 72015, + 'maxpos' => 72015, + 'wt' => 'T', + 'mt' => 'C',); + + my @t = $ts->getTranscripts($sub); + + my $a = Sanger::CGP::Vagrent::Annotators::SimpleSubstitutionAnnotator->new(transcriptSource => $ts); + + my @res = $a->getAnnotation($sub); + + is(scalar(@res),1,'annotation group count'); + is($res[0]->getType,Sanger::CGP::Vagrent::Data::Transcript::getProteinCodingType(),'annotation group type - proteincoding'); + is(scalar(@{$res[0]->getAllAnnotations}),1,'annotation count for group'); + ok(defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext())),'has mRNA context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getCDSAnnotationContext())),'doesnt have CDS context annotation'); + ok(!defined($res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getProteinAnnotationContext())),'doesnt have protein context annotation'); + + AnnotationTestUtils::checkAnnotationGroup('examine annotation group in detail',$res[0], + $t[0]->getGeneName,$t[0]->getCCDS,$t[0]->getAccession,$t[0]->getGeneType, + $a->getProteinCodingClass); + + AnnotationTestUtils::checkAnnotation('examine mRNA annotation in detail', + $res[0]->getAnnotationByContext(Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext()), + Sanger::CGP::Vagrent::Data::Annotation::getmRNAAnnotationContext(), + Sanger::CGP::Vagrent::Data::Annotation::getUnknownAnnotationType(), + Sanger::CGP::Vagrent::Data::Annotation::getPositionOffSequenceSubtype(), + 0,0,0,0,'?','?','r.?',$t[0]->getAccession,$t[0]->getAccessionVersion,$t[0]->getDatabase,$t[0]->getDatabaseVersion, + $a->getSubstitutionClass,$a->get5KBDownStreamVariantClass); + done_testing(); + }; + +} + # CEP350 protein coding gene with 5 prime utr exons on + strand of genome From 9b84208e25c696e6def5d3d6bf946cacd74fd308 Mon Sep 17 00:00:00 2001 From: Andy Menzies Date: Fri, 10 Apr 2015 15:14:13 +0100 Subject: [PATCH 5/5] updating docs and version number --- docs.tar.gz | Bin 53929 -> 39858 bytes lib/Sanger/CGP/Vagrent.pm | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs.tar.gz b/docs.tar.gz index 14787bb21f63d09ba5b95c7ef21b4ff5773c9bcc..1ce30a422c780c3295ff70e062ef086665d7b159 100644 GIT binary patch literal 39858 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 ATL1t6 literal 53929 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