📄 builder.pm
字号:
unless( $Have_Plan ) { die "You tried to run tests without a plan! Gotta have a plan.\n"; } $Curr_Test++; $Test_Results[$Curr_Test-1] = 1; my $out = "not ok"; $out .= " $Curr_Test" if $self->use_numbers; $out .= " # TODO $why\n"; $Test->_print($out); return 1;}=begin _unimplemented=item B<skip_rest> $Test->skip_rest; $Test->skip_rest($reason);Like skip(), only it skips all the rest of the tests you plan to runand terminates the test.If you're running under no_plan, it skips once and terminates thetest.=end _unimplemented=back=head2 Test style=over 4=item B<level> $Test->level($how_high);How far up the call stack should $Test look when reporting where thetest failed.Defaults to 1.Setting $Test::Builder::Level overrides. This is typically usefullocalized: { local $Test::Builder::Level = 2; $Test->ok($test); }=cutsub level { my($self, $level) = @_; if( defined $level ) { $Level = $level; } return $Level;}$CLASS->level(1);=item B<use_numbers> $Test->use_numbers($on_or_off);Whether or not the test should output numbers. That is, this if true: ok 1 ok 2 ok 3or this if false ok ok okMost useful when you can't depend on the test output order, such aswhen threads or forking is involved.Test::Harness will accept either, but avoid mixing the two styles.Defaults to on.=cutmy $Use_Nums = 1;sub use_numbers { my($self, $use_nums) = @_; if( defined $use_nums ) { $Use_Nums = $use_nums; } return $Use_Nums;}=item B<no_header> $Test->no_header($no_header);If set to true, no "1..N" header will be printed.=item B<no_ending> $Test->no_ending($no_ending);Normally, Test::Builder does some extra diagnostics when the testends. It also changes the exit code as described in Test::Simple.If this is true, none of that will be done.=cutmy($No_Header, $No_Ending) = (0,0);sub no_header { my($self, $no_header) = @_; if( defined $no_header ) { $No_Header = $no_header; } return $No_Header;}sub no_ending { my($self, $no_ending) = @_; if( defined $no_ending ) { $No_Ending = $no_ending; } return $No_Ending;}=back=head2 OutputControlling where the test output goes.It's ok for your test to change where STDOUT and STDERR point to,Test::Builder's default output settings will not be affected.=over 4=item B<diag> $Test->diag(@msgs);Prints out the given $message. Normally, it uses the failure_output()handle, but if this is for a TODO test, the todo_output() handle isused.Output will be indented and marked with a # so as not to interferewith test output. A newline will be put on the end if there isn't onealready.We encourage using this rather than calling print directly.=cutsub diag { my($self, @msgs) = @_; return unless @msgs; # Prevent printing headers when compiling (i.e. -c) return if $^C; # Escape each line with a #. foreach (@msgs) { s/^/# /gms; } push @msgs, "\n" unless $msgs[-1] =~ /\n\Z/; local $Level = $Level + 1; my $fh = $self->todo ? $self->todo_output : $self->failure_output; local($\, $", $,) = (undef, ' ', ''); print $fh @msgs;}=begin _private=item B<_print> $Test->_print(@msgs);Prints to the output() filehandle.=end _private=cutsub _print { my($self, @msgs) = @_; # Prevent printing headers when only compiling. Mostly for when # tests are deparsed with B::Deparse return if $^C; local($\, $", $,) = (undef, ' ', ''); my $fh = $self->output; print $fh @msgs;}=item B<output> $Test->output($fh); $Test->output($file);Where normal "ok/not ok" test output should go.Defaults to STDOUT.=item B<failure_output> $Test->failure_output($fh); $Test->failure_output($file);Where diagnostic output on test failures and diag() should go.Defaults to STDERR.=item B<todo_output> $Test->todo_output($fh); $Test->todo_output($file);Where diagnostics about todo test failures and diag() should go.Defaults to STDOUT.=cutmy($Out_FH, $Fail_FH, $Todo_FH);sub output { my($self, $fh) = @_; if( defined $fh ) { $Out_FH = _new_fh($fh); } return $Out_FH;}sub failure_output { my($self, $fh) = @_; if( defined $fh ) { $Fail_FH = _new_fh($fh); } return $Fail_FH;}sub todo_output { my($self, $fh) = @_; if( defined $fh ) { $Todo_FH = _new_fh($fh); } return $Todo_FH;}sub _new_fh { my($file_or_fh) = shift; my $fh; unless( UNIVERSAL::isa($file_or_fh, 'GLOB') ) { $fh = do { local *FH }; open $fh, ">$file_or_fh" or die "Can't open test output log $file_or_fh: $!"; } else { $fh = $file_or_fh; } return $fh;}unless( $^C ) { # We dup STDOUT and STDERR so people can change them in their # test suites while still getting normal test output. open(TESTOUT, ">&STDOUT") or die "Can't dup STDOUT: $!"; open(TESTERR, ">&STDERR") or die "Can't dup STDERR: $!"; # Set everything to unbuffered else plain prints to STDOUT will # come out in the wrong order from our own prints. _autoflush(\*TESTOUT); _autoflush(\*STDOUT); _autoflush(\*TESTERR); _autoflush(\*STDERR); $CLASS->output(\*TESTOUT); $CLASS->failure_output(\*TESTERR); $CLASS->todo_output(\*TESTOUT);}sub _autoflush { my($fh) = shift; my $old_fh = select $fh; $| = 1; select $old_fh;}=back=head2 Test Status and Info=over 4=item B<current_test> my $curr_test = $Test->current_test; $Test->current_test($num);Gets/sets the current test # we're on.You usually shouldn't have to set this.=cutsub current_test { my($self, $num) = @_; if( defined $num ) { $Curr_Test = $num; if( $num > @Test_Results ) { for ($#Test_Results..$num-1) { $Test_Results[$_] = 1; } } } return $Curr_Test;}=item B<summary> my @tests = $Test->summary;A simple summary of the tests so far. True for pass, false for fail.This is a logical pass/fail, so todos are passes.Of course, test #1 is $tests[0], etc...=cutsub summary { my($self) = shift; return @Test_Results;}=item B<details> I<UNIMPLEMENTED> my @tests = $Test->details;Like summary(), but with a lot more detail. $tests[$test_num - 1] = { ok => is the test considered ok? actual_ok => did it literally say 'ok'? name => name of the test (if any) type => 'skip' or 'todo' (if any) reason => reason for the above (if any) };=item B<todo> my $todo_reason = $Test->todo; my $todo_reason = $Test->todo($pack);todo() looks for a $TODO variable in your tests. If set, all testswill be considered 'todo' (see Test::More and Test::Harness fordetails). Returns the reason (ie. the value of $TODO) if running astodo tests, false otherwise.todo() is pretty part about finding the right package to look for$TODO in. It uses the exported_to() package to find it. If that'snot set, it's pretty good at guessing the right package to look at.Sometimes there is some confusion about where todo() should be lookingfor the $TODO variable. If you want to be sure, tell it explicitlywhat $pack to use.=cutsub todo { my($self, $pack) = @_; $pack = $pack || $self->exported_to || $self->caller(1); no strict 'refs'; return defined ${$pack.'::TODO'} ? ${$pack.'::TODO'} : 0;}=item B<caller> my $package = $Test->caller; my($pack, $file, $line) = $Test->caller; my($pack, $file, $line) = $Test->caller($height);Like the normal caller(), except it reports according to your level().=cutsub caller { my($self, $height) = @_; $height ||= 0; my @caller = CORE::caller($self->level + $height + 1); return wantarray ? @caller : $caller[0];}=back=cut=begin _private=over 4=item B<_sanity_check> _sanity_check();Runs a bunch of end of test sanity checks to make sure reality camethrough ok. If anything is wrong it will die with a fairly friendlyerror message.=cut#'#sub _sanity_check { _whoa($Curr_Test < 0, 'Says here you ran a negative number of tests!'); _whoa(!$Have_Plan and $Curr_Test, 'Somehow your tests ran without a plan!'); _whoa($Curr_Test != @Test_Results, 'Somehow you got a different number of results than tests ran!');}=item B<_whoa> _whoa($check, $description);A sanity check, similar to assert(). If the $check is true, somethinghas gone horribly wrong. It will die with the given $description anda note to contact the author.=cutsub _whoa { my($check, $desc) = @_; if( $check ) { die <<WHOA;WHOA! $descThis should never happen! Please contact the author immediately!WHOA }}=item B<_my_exit> _my_exit($exit_num);Perl seems to have some trouble with exiting inside an END block. 5.005_03and 5.6.1 both seem to do odd things. Instead, this function edits $?directly. It should ONLY be called from inside an END block. Itdoesn't actually exit, that's your job.=cutsub _my_exit { $? = $_[0]; return 1;}=back=end _private=cut$SIG{__DIE__} = sub { # We don't want to muck with death in an eval, but $^S isn't # totally reliable. 5.005_03 and 5.6.1 both do the wrong thing # with it. Instead, we use caller. This also means it runs under # 5.004! my $in_eval = 0; for( my $stack = 1; my $sub = (CORE::caller($stack))[3]; $stack++ ) { $in_eval = 1 if $sub =~ /^\(eval\)/; } $Test_Died = 1 unless $in_eval;};sub _ending { my $self = shift; _sanity_check(); # Bailout if plan() was never called. This is so # "require Test::Simple" doesn't puke. do{ _my_exit(0) && return } if !$Have_Plan; # Figure out if we passed or failed and print helpful messages. if( @Test_Results ) { # The plan? We have no plan. if( $No_Plan ) { $self->_print("1..$Curr_Test\n") unless $self->no_header; $Expected_Tests = $Curr_Test; } my $num_failed = grep !$_, @Test_Results[0..$Expected_Tests-1]; $num_failed += abs($Expected_Tests - @Test_Results); if( $Curr_Test < $Expected_Tests ) { $self->diag(<<"FAIL");Looks like you planned $Expected_Tests tests but only ran $Curr_Test.FAIL } elsif( $Curr_Test > $Expected_Tests ) { my $num_extra = $Curr_Test - $Expected_Tests; $self->diag(<<"FAIL");Looks like you planned $Expected_Tests tests but ran $num_extra extra.FAIL } elsif ( $num_failed ) { $self->diag(<<"FAIL");Looks like you failed $num_failed tests of $Expected_Tests.FAIL } if( $Test_Died ) { $self->diag(<<"FAIL");Looks like your test died just after $Curr_Test.FAIL _my_exit( 255 ) && return; } _my_exit( $num_failed <= 254 ? $num_failed : 254 ) && return; } elsif ( $Skip_All ) { _my_exit( 0 ) && return; } else { $self->diag("No tests run!\n"); _my_exit( 255 ) && return; }}END { $Test->_ending if defined $Test and !$Test->no_ending;}=head1 EXAMPLESAt this point, Test::Simple and Test::More are your best examples.=head1 SEE ALSOTest::Simple, Test::More, Test::Harness=head1 AUTHORSOriginal code by chromatic, maintained by Michael G SchwernE<lt>schwern@pobox.comE<gt>=head1 COPYRIGHTCopyright 2001 by chromatic E<lt>chromatic@wgz.orgE<gt>, Michael G Schwern E<lt>schwern@pobox.comE<gt>.This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.See F<http://www.perl.com/perl/misc/Artistic.html>=cut1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -