📄 straps.pm
字号:
# -*- Mode: cperl; cperl-indent-level: 4 -*-package Test::Harness::Straps;use strict;use vars qw($VERSION);$VERSION = '0.26';use Config;use Test::Harness::Assert;use Test::Harness::Iterator;use Test::Harness::Point;# Flags used as return values from our methods. Just for internal # clarification.my $YES = (1==1);my $NO = !$YES;=head1 NAMETest::Harness::Straps - detailed analysis of test results=head1 SYNOPSIS use Test::Harness::Straps; my $strap = Test::Harness::Straps->new; # Various ways to interpret a test my %results = $strap->analyze($name, \@test_output); my %results = $strap->analyze_fh($name, $test_filehandle); my %results = $strap->analyze_file($test_file); # UNIMPLEMENTED my %total = $strap->total_results; # Altering the behavior of the strap UNIMPLEMENTED my $verbose_output = $strap->dump_verbose(); $strap->dump_verbose_fh($output_filehandle);=head1 DESCRIPTIONB<THIS IS ALPHA SOFTWARE> in that the interface is subject to changein incompatible ways. It is otherwise stable.Test::Harness is limited to printing out its results. This makesanalysis of the test results difficult for anything but a human. Tomake it easier for programs to work with test results, we provideTest::Harness::Straps. Instead of printing the results, strapsprovide them as raw data. You can also configure how the tests are tobe run.The interface is currently incomplete. I<Please> contact the authorif you'd like a feature added or something change or just havecomments.=head1 CONSTRUCTION=head2 new() my $strap = Test::Harness::Straps->new;Initialize a new strap.=cutsub new { my $class = shift; my $self = bless {}, $class; $self->_init; return $self;}=head2 $strap->_init $strap->_init;Initialize the internal state of a strap to make it ready for parsing.=cutsub _init { my($self) = shift; $self->{_is_vms} = ( $^O eq 'VMS' ); $self->{_is_win32} = ( $^O =~ /^(MS)?Win32$/ ); $self->{_is_macos} = ( $^O eq 'MacOS' );}=head1 ANALYSIS=head2 $strap->analyze( $name, \@output_lines ) my %results = $strap->analyze($name, \@test_output);Analyzes the output of a single test, assigning it the given C<$name>for use in the total report. Returns the C<%results> of the test.See L<Results>.C<@test_output> should be the raw output from the test, includingnewlines.=cutsub analyze { my($self, $name, $test_output) = @_; my $it = Test::Harness::Iterator->new($test_output); return $self->_analyze_iterator($name, $it);}sub _analyze_iterator { my($self, $name, $it) = @_; $self->_reset_file_state; $self->{file} = $name; my %totals = ( max => 0, seen => 0, ok => 0, todo => 0, skip => 0, bonus => 0, details => [] ); # Set them up here so callbacks can have them. $self->{totals}{$name} = \%totals; while( defined(my $line = $it->next) ) { $self->_analyze_line($line, \%totals); last if $self->{saw_bailout}; } $totals{skip_all} = $self->{skip_all} if defined $self->{skip_all}; my $passed = ($totals{max} == 0 && defined $totals{skip_all}) || ($totals{max} && $totals{seen} && $totals{max} == $totals{seen} && $totals{max} == $totals{ok}); $totals{passing} = $passed ? 1 : 0; return %totals;}sub _analyze_line { my $self = shift; my $line = shift; my $totals = shift; $self->{line}++; my $linetype; my $point = Test::Harness::Point->from_test_line( $line ); if ( $point ) { $linetype = 'test'; $totals->{seen}++; $point->set_number( $self->{'next'} ) unless $point->number; # sometimes the 'not ' and the 'ok' are on different lines, # happens often on VMS if you do: # print "not " unless $test; # print "ok $num\n"; if ( $self->{lone_not_line} && ($self->{lone_not_line} == $self->{line} - 1) ) { $point->set_ok( 0 ); } if ( $self->{todo}{$point->number} ) { $point->set_directive_type( 'todo' ); } if ( $point->is_todo ) { $totals->{todo}++; $totals->{bonus}++ if $point->ok; } elsif ( $point->is_skip ) { $totals->{skip}++; } $totals->{ok}++ if $point->pass; if ( ($point->number > 100_000) && ($point->number > ($self->{max}||100_000)) ) { if ( !$self->{too_many_tests}++ ) { warn "Enormous test number seen [test ", $point->number, "]\n"; warn "Can't detailize, too big.\n"; } } else { my $details = { ok => $point->pass, actual_ok => $point->ok, name => _def_or_blank( $point->description ), type => _def_or_blank( $point->directive_type ), reason => _def_or_blank( $point->directive_reason ), }; assert( defined( $details->{ok} ) && defined( $details->{actual_ok} ) ); $totals->{details}[$point->number - 1] = $details; } } # test point elsif ( $line =~ /^not\s+$/ ) { $linetype = 'other'; # Sometimes the "not " and "ok" will be on separate lines on VMS. # We catch this and remember we saw it. $self->{lone_not_line} = $self->{line}; } elsif ( $self->_is_header($line) ) { $linetype = 'header'; $self->{saw_header}++; $totals->{max} += $self->{max}; } elsif ( $self->_is_bail_out($line, \$self->{bailout_reason}) ) { $linetype = 'bailout'; $self->{saw_bailout} = 1; } elsif (my $diagnostics = $self->_is_diagnostic_line( $line )) { $linetype = 'other'; my $test = $totals->{details}[-1]; $test->{diagnostics} ||= ''; $test->{diagnostics} .= $diagnostics; } else { $linetype = 'other'; } $self->{callback}->($self, $line, $linetype, $totals) if $self->{callback}; $self->{'next'} = $point->number + 1 if $point;} # _analyze_linesub _is_diagnostic_line { my ($self, $line) = @_; return if index( $line, '# Looks like you failed' ) == 0; $line =~ s/^#\s//; return $line;}=head2 $strap->analyze_fh( $name, $test_filehandle ) my %results = $strap->analyze_fh($name, $test_filehandle);Like C<analyze>, but it reads from the given filehandle.=cutsub analyze_fh { my($self, $name, $fh) = @_; my $it = Test::Harness::Iterator->new($fh); return $self->_analyze_iterator($name, $it);}=head2 $strap->analyze_file( $test_file ) my %results = $strap->analyze_file($test_file);Like C<analyze>, but it runs the given C<$test_file> and parses itsresults. It will also use that name for the total report.=cutsub analyze_file { my($self, $file) = @_; unless( -e $file ) { $self->{error} = "$file does not exist"; return; } unless( -r $file ) { $self->{error} = "$file is not readable"; return; } local $ENV{PERL5LIB} = $self->_INC2PERL5LIB; if ( $Test::Harness::Debug ) { local $^W=0; # ignore undef warnings print "# PERL5LIB=$ENV{PERL5LIB}\n"; } # *sigh* this breaks under taint, but open -| is unportable. my $line = $self->_command_line($file); unless ( open(FILE, "$line|" )) { print "can't run $file. $!\n"; return; } my %results = $self->analyze_fh($file, \*FILE); my $exit = close FILE; $results{'wait'} = $?; if( $? && $self->{_is_vms} ) { eval q{use vmsish "status"; $results{'exit'} = $?}; } else { $results{'exit'} = _wait2exit($?); } $results{passing} = 0 unless $? == 0; $self->_restore_PERL5LIB(); return %results;}eval { require POSIX; &POSIX::WEXITSTATUS(0) };if( $@ ) { *_wait2exit = sub { $_[0] >> 8 };}else { *_wait2exit = sub { POSIX::WEXITSTATUS($_[0]) }}=head2 $strap->_command_line( $file )Returns the full command line that will be run to test I<$file>.=cutsub _command_line { my $self = shift; my $file = shift; my $command = $self->_command(); my $switches = $self->_switches($file); $file = qq["$file"] if ($file =~ /\s/) && ($file !~ /^".*"$/); my $line = "$command $switches $file"; return $line;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -