3 # Copyright (C) 2012-2013 Genome Research Ltd.
5 # Author: Petr Danecek <pd3@sanger.ac.uk>
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to deal
9 # in the Software without restriction, including without limitation the rights
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 # copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 # DEALINGS IN THE SOFTWARE.
29 use lib
"$FindBin::Bin";
31 use File
::Temp qw
/ tempfile tempdir /;
34 my $opts = parse_params
();
39 test_vcf_api
($opts,out
=>'test-vcf-api.out');
40 test_vcf_sweep
($opts,out
=>'test-vcf-sweep.out');
41 test_vcf_various
($opts);
42 test_bcf_sr_sort
($opts);
43 test_convert_padded_header
($opts);
47 print "\nNumber of tests:\n";
48 printf " total .. %d\n", $$opts{nok
}+$$opts{nfailed
};
49 printf " passed .. %d\n", $$opts{nok
};
50 printf " failed .. %d\n", $$opts{nfailed
};
53 exit ($$opts{nfailed
} > 0);
60 if ( scalar @msg ) { confess
@msg; }
62 "About: samtools/htslib consistency test script\n",
63 "Usage: test.pl [OPTIONS]\n",
65 " -r, --redo-outputs Recreate expected output files.\n",
66 " -t, --temp-dir <path> When given, temporary files will not be removed.\n",
67 " -h, -?, --help This help message.\n",
73 my $opts = { keep_files
=>0, nok
=>0, nfailed
=>0 };
75 Getopt
::Long
::Configure
('bundling');
76 my $ret = GetOptions
(
77 't|temp-dir:s' => \
$$opts{keep_files
},
78 'r|redo-outputs' => \
$$opts{redo_outputs
},
81 if ( !$ret or $help ) { error
(); }
82 $$opts{tmp
} = $$opts{keep_files
} ?
$$opts{keep_files
} : tempdir
(CLEANUP
=>1);
83 if ( $$opts{keep_files
} ) { cmd
("mkdir -p $$opts{keep_files}"); }
84 $$opts{path
} = $FindBin::RealBin
;
85 $$opts{bin
} = $FindBin::RealBin
;
86 $$opts{bin
} =~ s
{/test
/?
$}{};
94 my $pid = open($kid_io, "-|");
95 if ( !defined $pid ) { error
("Cannot fork: $!"); }
105 exec('bash', '-o','pipefail','-c', $cmd) or error
("Cannot execute the command [/bin/sh -o pipefail -c $cmd]: $!");
107 return ($?
>> 8, join('',@out));
112 my ($ret,$out) = _cmd
($cmd);
113 if ( $ret ) { error
("The command failed [$ret]: $cmd\n", $out); }
118 my ($opts,%args) = @_;
119 if ( !exists($args{out
}) )
121 if ( !exists($args{in}) ) { error
("FIXME: expected out or in key\n"); }
122 $args{out
} = "$args{in}.out";
124 my ($package, $filename, $line, $test)=caller(1);
128 print "\t$args{cmd}\n";
130 my ($ret,$out) = _cmd
("$args{cmd}");
131 if ( $ret ) { failed
($opts,$test); return; }
132 if ( $$opts{redo_outputs
} && -e
"$$opts{path}/$args{out}" )
134 rename("$$opts{path}/$args{out}","$$opts{path}/$args{out}.old");
135 open(my $fh,'>',"$$opts{path}/$args{out}") or error
("$$opts{path}/$args{out}: $!");
138 my ($ret,$out) = _cmd
("diff -q $$opts{path}/$args{out} $$opts{path}/$args{out}.old");
139 if ( !$ret && $out eq '' ) { unlink("$$opts{path}/$args{out}.old"); }
142 print "\tthe expected output changed, saving:\n";
143 print "\t old .. $$opts{path}/$args{out}.old\n";
144 print "\t new .. $$opts{path}/$args{out}\n";
148 if ( open(my $fh,'<',"$$opts{path}/$args{out}") )
151 $exp = join('',@exp);
154 elsif ( !$$opts{redo_outputs
} ) { failed
($opts,$test,"$$opts{path}/$args{out}: $!"); return; }
158 open(my $fh,'>',"$$opts{path}/$args{out}.new") or error
("$$opts{path}/$args{out}.new");
161 if ( !-e
"$$opts{path}/$args{out}" )
163 rename("$$opts{path}/$args{out}.new","$$opts{path}/$args{out}") or error
("rename $$opts{path}/$args{out}.new $$opts{path}/$args{out}: $!");
164 print "\tthe file with expected output does not exist, creating new one:\n";
165 print "\t\t$$opts{path}/$args{out}\n";
169 failed
($opts,$test,"The outputs differ:\n\t\t$$opts{path}/$args{out}\n\t\t$$opts{path}/$args{out}.new");
177 my ($opts,$test,$reason) = @_;
181 if ( defined $reason ) { print STDERR
"\t$reason\n"; }
182 print STDERR
".. failed ...\n\n";
187 my ($opts,$test) = @_;
193 my ($afile,$bfile) = @_;
194 my (@astat) = stat($afile) or return 0;
195 my (@bstat) = stat($bfile) or return 0;
196 if ( $astat[9]>$bstat[9] ) { return 1 }
201 # The tests --------------------------
203 my $test_view_failures;
207 my ($ret, $out) = _cmd
($cmd);
210 print STDERR
"FAILED\n$out\n";
212 $test_view_failures++;
218 my ($opts, $nthreads) = @_;
219 my $tv_args = $nthreads ?
"-\@$nthreads" : "";
221 foreach my $sam (glob("*#*.sam")) {
222 my ($base, $ref) = ($sam =~ /((.*)#.*)\.sam/);
225 my $bam = "$base.tmp.bam";
226 my $cram = "$base.tmp.cram";
233 print "test_view testing $sam, ref $ref:\n";
234 $test_view_failures = 0;
237 testv
"./test_view $tv_args -S -b $sam > $bam";
238 testv
"./test_view $tv_args $bam > $bam.sam_";
239 testv
"./compare_sam.pl $sam $bam.sam_";
242 testv
"./test_view $tv_args -t $ref -S -C $sam > $cram";
243 testv
"./test_view $tv_args -D $cram > $cram.sam_";
244 testv
"./compare_sam.pl $md $sam $cram.sam_";
246 # BAM -> CRAM -> BAM -> SAM
248 testv
"./test_view $tv_args -t $ref -C $bam > $cram";
249 testv
"./test_view $tv_args -b -D $cram > $cram.bam";
250 testv
"./test_view $tv_args $cram.bam > $cram.bam.sam_";
251 testv
"./compare_sam.pl $md $sam $cram.bam.sam_";
253 # SAM -> CRAM3 -> SAM
254 $cram = "$base.tmp.cram";
255 testv
"./test_view $tv_args -t $ref -S -C -o VERSION=3.0 $sam > $cram";
256 testv
"./test_view $tv_args -D $cram > $cram.sam_";
257 testv
"./compare_sam.pl $md $sam $cram.sam_";
259 # BAM -> CRAM3 -> BAM -> SAM
261 testv
"./test_view $tv_args -t $ref -C -o VERSION=3.0 $bam > $cram";
262 testv
"./test_view $tv_args -b -D $cram > $cram.bam";
263 testv
"./test_view $tv_args $cram.bam > $cram.bam.sam_";
264 testv
"./compare_sam.pl $md $sam $cram.bam.sam_";
267 $cram = "$base.tmp.cram";
268 testv
"./test_view $tv_args -t $ref -C -o VERSION=2.1 $cram > $cram.cram";
271 testv
"./test_view $tv_args -t $ref -C -o VERSION=3.0 $cram.cram > $cram";
272 testv
"./test_view $tv_args $cram > $cram.sam_";
273 testv
"./compare_sam.pl $md $sam $cram.sam_";
275 # Java pre-made CRAM -> SAM
276 my $jcram = "${base}_java.cram";
278 my $jsam = "${base}_java.tmp.sam_";
279 testv
"./test_view $tv_args -i reference=$ref $jcram > $jsam";
280 testv
"./compare_sam.pl -Baux $md $sam $jsam";
283 if ($test_view_failures == 0)
285 passed
($opts, "$sam conversions");
289 failed
($opts, "$sam conversions", "$test_view_failures subtests failed");
296 my ($opts,%args) = @_;
297 test_cmd
($opts,%args,cmd
=>"$$opts{path}/test-vcf-api $$opts{tmp}/test-vcf-api.bcf");
302 my ($opts,%args) = @_;
303 test_cmd
($opts,%args,cmd
=>"$$opts{path}/test-vcf-sweep $$opts{tmp}/test-vcf-api.bcf");
308 my ($opts, %args) = @_;
310 # Excess spaces in header lines
311 test_cmd
($opts, %args, out
=> "test-vcf-hdr.out",
312 cmd
=> "$$opts{bin}/htsfile -ch $$opts{path}/test-vcf-hdr-in.vcf");
314 # Various VCF parsing issues
315 test_cmd
($opts, %args, out
=> "formatcols.vcf",
316 cmd
=> "$$opts{bin}/htsfile -c $$opts{path}/formatcols.vcf");
317 test_cmd
($opts, %args, out
=> "noroundtrip-out.vcf",
318 cmd
=> "$$opts{bin}/htsfile -c $$opts{path}/noroundtrip.vcf");
319 test_cmd
($opts, %args, out
=> "formatmissing-out.vcf",
320 cmd
=> "$$opts{bin}/htsfile -c $$opts{path}/formatmissing.vcf");
325 my ($opts, %args) = @_;
327 test_cmd
($opts, %args, out
=> "bgziptest.txt.gz",
328 cmd
=> "$$opts{bin}/bgzip -I $$opts{path}/bgziptest.txt.gz.gzi -c -g $$opts{path}/bgziptest.txt");
331 sub test_convert_padded_header
333 my ($opts, %args) = @_;
335 $args{out
} = "headernul.tmp.cram";
336 cmd
("$$opts{path}/test_view -t ce.fa -C ce#1.sam > $args{out}");
338 foreach my $nuls (0, 1, 678) {
339 my $nulsbam = "$$opts{tmp}/headernul$nuls.bam";
340 cmd
("$$opts{path}/test_view -b -Z $nuls ce#1.sam > $nulsbam");
341 test_cmd
($opts, %args,
342 cmd
=> "$$opts{path}/test_view -t ce.fa -C $nulsbam");
348 my ($opts, %args) = @_;
349 for (my $i=0; $i<10; $i++)
351 my $seed = int(rand(time));
352 my $test = 'test-bcf-sr';
353 my $cmd = "$$opts{path}/test-bcf-sr.pl -t $$opts{tmp} -s $seed";
356 my ($ret,$out) = _cmd
($cmd);
357 if ( $ret ) { failed
($opts,$test); }
358 else { passed
($opts,$test); }
365 my $test = 'test-logging';
366 my $cmd = "$$opts{path}/test-logging.pl";
369 my ($ret,$out) = _cmd
($cmd);
370 if ( $ret ) { failed
($opts,$test); }
371 else { passed
($opts,$test); }