diff options
author | Chad Granum <chad.granum@dreamhost.com> | 2014-08-15 08:40:10 -0700 |
---|---|---|
committer | James E Keenan <jkeenan@cpan.org> | 2014-08-16 23:19:29 +0200 |
commit | 6bdb88770f849c47b5c09e733ac460ce3e9dbc97 (patch) | |
tree | 3eda7f11aea1019f7a802c1caecfb81ab26e7761 /cpan/Test-Simple/lib/Test/Builder.pm | |
parent | 7d16fb5f4895e672484c0b7490722d46df82b099 (diff) | |
download | perl-6bdb88770f849c47b5c09e733ac460ce3e9dbc97.tar.gz |
Update to include latest Test::Builder alpha
Also updated some tests that the new builder broke
Diffstat (limited to 'cpan/Test-Simple/lib/Test/Builder.pm')
-rw-r--r-- | cpan/Test-Simple/lib/Test/Builder.pm | 3172 |
1 files changed, 1456 insertions, 1716 deletions
diff --git a/cpan/Test-Simple/lib/Test/Builder.pm b/cpan/Test-Simple/lib/Test/Builder.pm index 00a3ec51ea..bc88477dbd 100644 --- a/cpan/Test-Simple/lib/Test/Builder.pm +++ b/cpan/Test-Simple/lib/Test/Builder.pm @@ -1,153 +1,74 @@ package Test::Builder; -use 5.006; +use 5.008001; use strict; use warnings; -our $VERSION = '1.001003'; +use Test::Builder::Util qw/try protect/; +use Scalar::Util(); +use Test::Builder::Stream; +use Test::Builder::Result; +use Test::Builder::Result::Ok; +use Test::Builder::Result::Diag; +use Test::Builder::Result::Note; +use Test::Builder::Result::Plan; +use Test::Builder::Result::Bail; +use Test::Builder::Result::Child; +use Test::Builder::Trace; + +our $VERSION = '1.301001_034'; $VERSION = eval $VERSION; ## no critic (BuiltinFunctions::ProhibitStringyEval) -BEGIN { - if( $] < 5.008 ) { - require Test::Builder::IO::Scalar; - } -} +# The mostly-singleton, and other package vars. +our $Test = Test::Builder->new; +our $Level = 1; +our $BLevel = 1; +#################### +# {{{ MAGIC things # +#################### -# Make Test::Builder thread-safe for ithreads. -BEGIN { - use Config; - # Load threads::shared when threads are turned on. - # 5.8.0's threads are so busted we no longer support them. - if( $] >= 5.008001 && $Config{useithreads} && $INC{'threads.pm'} ) { - require threads::shared; - - # Hack around YET ANOTHER threads::shared bug. It would - # occasionally forget the contents of the variable when sharing it. - # So we first copy the data, then share, then put our copy back. - *share = sub (\[$@%]) { - my $type = ref $_[0]; - my $data; - - if( $type eq 'HASH' ) { - %$data = %{ $_[0] }; - } - elsif( $type eq 'ARRAY' ) { - @$data = @{ $_[0] }; - } - elsif( $type eq 'SCALAR' ) { - $$data = ${ $_[0] }; - } - else { - die( "Unknown type: " . $type ); - } - - $_[0] = &threads::shared::share( $_[0] ); - - if( $type eq 'HASH' ) { - %{ $_[0] } = %$data; - } - elsif( $type eq 'ARRAY' ) { - @{ $_[0] } = @$data; - } - elsif( $type eq 'SCALAR' ) { - ${ $_[0] } = $$data; - } - else { - die( "Unknown type: " . $type ); - } - - return $_[0]; - }; - } - # 5.8.0's threads::shared is busted when threads are off - # and earlier Perls just don't have that module at all. - else { - *share = sub { return $_[0] }; - *lock = sub { 0 }; +sub DESTROY { + my $self = shift; + if ( $self->parent and $$ == $self->{Original_Pid} ) { + my $name = $self->name; + $self->parent->{In_Destroy} = 1; + $self->parent->ok(0, $name, "Child ($name) exited without calling finalize()\n"); } } -=head1 NAME - -Test::Builder - Backend for building test libraries - -=head1 SYNOPSIS - - package My::Test::Module; - use base 'Test::Builder::Module'; - - my $CLASS = __PACKAGE__; - - sub ok { - my($test, $name) = @_; - my $tb = $CLASS->builder; - - $tb->ok($test, $name); - } - - -=head1 DESCRIPTION - -Test::Simple and Test::More have proven to be popular testing modules, -but they're not always flexible enough. Test::Builder provides a -building block upon which to write your own test libraries I<which can -work together>. - -=head2 Construction - -=over 4 - -=item B<new> - - my $Test = Test::Builder->new; - -Returns a Test::Builder object representing the current state of the -test. - -Since you only run one test per program C<new> always returns the same -Test::Builder object. No matter how many times you call C<new()>, you're -getting the same object. This is called a singleton. This is done so that -multiple modules share such global information as the test counter and -where test output is going. - -If you want a completely new Test::Builder object different from the -singleton, use C<create>. +require Test::Builder::ExitMagic; +my $final = Test::Builder::ExitMagic->new( + tb => Test::Builder->create(shared_stream => 1), +); +END { $final->do_magic() } -=cut +#################### +# }}} MAGIC things # +#################### -our $Test = Test::Builder->new; +#################### +# {{{ Constructors # +#################### sub new { - my($class) = shift; - $Test ||= $class->create; + my $class = shift; + my %params = @_; + $Test ||= $class->create(shared_stream => 1); + return $Test; } -=item B<create> - - my $Test = Test::Builder->create; - -Ok, so there can be more than one Test::Builder object and this is how -you get it. You might use this instead of C<new()> if you're testing -a Test::Builder based module, but otherwise you probably want C<new>. - -B<NOTE>: the implementation is not complete. C<level>, for example, is -still shared amongst B<all> Test::Builder objects, even ones created using -this method. Also, the method name may change in the future. - -=cut - sub create { my $class = shift; + my %params = @_; my $self = bless {}, $class; - $self->reset; + $self->reset(%params); return $self; } - # Copy an object, currently a shallow. # This does *not* bless the destination. This keeps the destructor from # firing when we're just storing a copy of the object to restore later. @@ -155,114 +76,154 @@ sub _copy { my($src, $dest) = @_; %$dest = %$src; - _share_keys($dest); + #_share_keys($dest); # Not sure the implications here. return; } +#################### +# }}} Constructors # +#################### -=item B<child> +############################################## +# {{{ Simple accessors/generators/deligators # +############################################## - my $child = $builder->child($name_of_child); - $child->plan( tests => 4 ); - $child->ok(some_code()); - ... - $child->finalize; +sub listen { shift->stream->listen(@_) } +sub munge { shift->stream->munge(@_) } +sub tap { shift->stream->tap } +sub lresults { shift->stream->lresults } +sub is_passing { shift->stream->is_passing(@_) } +sub use_fork { shift->stream->use_fork } +sub no_fork { shift->stream->no_fork } -Returns a new instance of C<Test::Builder>. Any output from this child will -be indented four spaces more than the parent's indentation. When done, the -C<finalize> method I<must> be called explicitly. +BEGIN { + Test::Builder::Util::accessors(qw/Parent Name _old_level _bailed_out default_name/); + Test::Builder::Util::accessor(modern => sub {$ENV{TB_MODERN} || 0}); + Test::Builder::Util::accessor(depth => sub { 0 }); +} -Trying to create a new child with a previous child still active (i.e., -C<finalize> not called) will C<croak>. +############################################## +# }}} Simple accessors/generators/deligators # +############################################## -Trying to run a test when you have an open child will also C<croak> and cause -the test suite to fail. +######################### +# {{{ Stream Management # +######################### + +sub stream { + my $self = shift; + + ($self->{stream}) = @_ if @_; + + # If no stream is set use shared. We do not want to cache that we use + # shared cause shared is a stack, not a constant, and we always want the + # top. + return $self->{stream} || Test::Builder::Stream->shared; +} + +sub intercept { + my $self = shift; + my ($code) = @_; + + Carp::croak("argument to intercept must be a coderef, got: $code") + unless reftype $code eq 'CODE'; -=cut + my $stream = Test::Builder::Stream->new(no_follow => 1) || die "Internal Error!"; + $stream->exception_followup; + + local $self->{stream} = $stream; + + my @results; + $stream->listen(INTERCEPTOR => sub { + my ($item) = @_; + push @results => $item; + }); + $code->($stream); + + return \@results; +} + +######################### +# }}} Stream Management # +######################### + +############################# +# {{{ Children and subtests # +############################# sub child { - my( $self, $name ) = @_; + my( $self, $name, $is_subtest ) = @_; - if( $self->{Child_Name} ) { - $self->croak("You already have a child named ($self->{Child_Name}) running"); - } + $self->croak("You already have a child named ($self->{Child_Name}) running") + if $self->{Child_Name}; my $parent_in_todo = $self->in_todo; # Clear $TODO for the child. my $orig_TODO = $self->find_TODO(undef, 1, undef); - my $class = ref $self; + my $class = Scalar::Util::blessed($self); my $child = $class->create; - # Add to our indentation - $child->_indent( $self->_indent . ' ' ); - - # Make the child use the same outputs as the parent - for my $method (qw(output failure_output todo_output)) { - $child->$method( $self->$method ); - } + $child->{stream} = $self->stream->spawn; # Ensure the child understands if they're inside a TODO - if( $parent_in_todo ) { - $child->failure_output( $self->todo_output ); - } + $child->tap->failure_output($self->tap->todo_output) + if $parent_in_todo && $self->tap; # This will be reset in finalize. We do this here lest one child failure # cause all children to fail. $child->{Child_Error} = $?; $? = 0; + $child->{Parent} = $self; $child->{Parent_TODO} = $orig_TODO; $child->{Name} = $name || "Child of " . $self->name; - $self->{Child_Name} = $child->name; - return $child; -} - -=item B<subtest> + $self->{Child_Name} = $child->name; - $builder->subtest($name, \&subtests); + $child->depth($self->depth + 1); -See documentation of C<subtest> in Test::More. + my $res = Test::Builder::Result::Child->new( + $self->context, + name => $child->name, + action => 'push', + in_todo => $self->in_todo || 0, + is_subtest => $is_subtest || 0, + ); + $self->stream->send($res); -=cut + return $child; +} sub subtest { my $self = shift; - my($name, $subtests) = @_; + my($name, $subtests, @args) = @_; - if ('CODE' ne ref $subtests) { - $self->croak("subtest()'s second argument must be a code ref"); - } + $self->croak("subtest()'s second argument must be a code ref") + unless $subtests && 'CODE' eq Scalar::Util::reftype($subtests); # Turn the child into the parent so anyone who has stored a copy of # the Test::Builder singleton will get the child. - my $error; - my $child; + my ($success, $error, $child); my $parent = {}; { - # child() calls reset() which sets $Level to 1, so we localize - # $Level first to limit the scope of the reset to the subtest. - local $Test::Builder::Level = $Test::Builder::Level + 1; + local $Level = $Level + 1; local $BLevel = $BLevel + 1; # Store the guts of $self as $parent and turn $child into $self. - $child = $self->child($name); + $child = $self->child($name, 1); + _copy($self, $parent); _copy($child, $self); my $run_the_subtests = sub { - # Add subtest name for clarification of starting point - $self->note("Subtest: $name"); - $subtests->(); - $self->done_testing unless $self->_plan_handled; + $subtests->(@args); + $self->done_testing unless defined $self->stream->plan; 1; }; - if( !eval { $run_the_subtests->() } ) { - $error = $@; - } + ($success, $error) = try { Test::Builder::Trace->nest($run_the_subtests) }; } # Restore the parent and the copied child. @@ -273,68 +234,19 @@ sub subtest { $self->find_TODO(undef, 1, $child->{Parent_TODO}); # Die *after* we restore the parent. - die $error if $error and !eval { $error->isa('Test::Builder::Exception') }; + die $error if $error && !(Scalar::Util::blessed($error) && $error->isa('Test::Builder::Exception')); - local $Test::Builder::Level = $Test::Builder::Level + 1; - my $finalize = $child->finalize; + local $Level = $Level + 1; local $BLevel = $BLevel + 1; + my $finalize = $child->finalize(1); - $self->BAIL_OUT($child->{Bailed_Out_Reason}) if $child->{Bailed_Out}; + $self->BAIL_OUT($child->{Bailed_Out_Reason}) if $child->_bailed_out; return $finalize; } -=begin _private - -=item B<_plan_handled> - - if ( $Test->_plan_handled ) { ... } - -Returns true if the developer has explicitly handled the plan via: - -=over 4 - -=item * Explicitly setting the number of tests - -=item * Setting 'no_plan' - -=item * Set 'skip_all'. - -=back - -This is currently used in subtests when we implicitly call C<< $Test->done_testing >> -if the developer has not set a plan. - -=end _private - -=cut - -sub _plan_handled { - my $self = shift; - return $self->{Have_Plan} || $self->{No_Plan} || $self->{Skip_All}; -} - - -=item B<finalize> - - my $ok = $child->finalize; - -When your child is done running tests, you must call C<finalize> to clean up -and tell the parent your pass/fail status. - -Calling finalize on a child with open children will C<croak>. - -If the child falls out of scope before C<finalize> is called, a failure -diagnostic will be issued and the child is considered to have failed. - -No attempt to call methods on a child after C<finalize> is called is -guaranteed to succeed. - -Calling this on the root builder is a no-op. - -=cut - sub finalize { my $self = shift; + my ($is_subtest) = @_; return unless $self->parent; if( $self->{Child_Name} ) { @@ -344,568 +256,720 @@ sub finalize { local $? = 0; # don't fail if $subtests happened to set $? nonzero $self->_ending; - # XXX This will only be necessary for TAP envelopes (we think) - #$self->_print( $self->is_passing ? "PASS\n" : "FAIL\n" ); - - local $Test::Builder::Level = $Test::Builder::Level + 1; + local $Level = $Level + 1; local $BLevel = $BLevel + 1; my $ok = 1; $self->parent->{Child_Name} = undef; - unless ($self->{Bailed_Out}) { + + unless ($self->_bailed_out) { if ( $self->{Skip_All} ) { $self->parent->skip($self->{Skip_All}); } - elsif ( not @{ $self->{Test_Results} } ) { + elsif ( ! $self->stream->tests_run ) { $self->parent->ok( 0, sprintf q[No tests run for subtest "%s"], $self->name ); } else { $self->parent->ok( $self->is_passing, $self->name ); } } + $? = $self->{Child_Error}; - delete $self->{Parent}; + my $parent = delete $self->{Parent}; + + my $res = Test::Builder::Result::Child->new( + $self->context, + name => $self->{Name} || undef, + action => 'pop', + in_todo => $self->in_todo || 0, + is_subtest => $is_subtest || 0, + ); + $parent->stream->send($res); return $self->is_passing; } -sub _indent { - my $self = shift; +############################# +# }}} Children and subtests # +############################# - if( @_ ) { - $self->{Indent} = shift; - } +##################################### +# {{{ Finding Testers and Providers # +##################################### - return $self->{Indent}; +sub trace_test { + my $out; + protect { $out = Test::Builder::Trace->new }; + return $out; } -=item B<parent> - - if ( my $parent = $builder->parent ) { - ... - } +sub find_TODO { + my( $self, $pack, $set, $new_value ) = @_; -Returns the parent C<Test::Builder> instance, if any. Only used with child -builders for nested TAP. + $pack ||= $self->trace_test->todo_package || $self->exported_to; + return unless $pack; -=cut + no strict 'refs'; ## no critic + no warnings 'once'; + my $old_value = ${ $pack . '::TODO' }; + $set and ${ $pack . '::TODO' } = $new_value; + return $old_value; +} -sub parent { shift->{Parent} } +##################################### +# }}} Finding Testers and Providers # +##################################### -=item B<name> +################ +# {{{ Planning # +################ - diag $builder->name; +my %PLAN_CMDS = ( + no_plan => 'no_plan', + skip_all => 'skip_all', + tests => '_plan_tests', +); -Returns the name of the current builder. Top level builders default to C<$0> -(the name of the executable). Child builders are named via the C<child> -method. If no name is supplied, will be named "Child of $parent->name". +sub plan { + my( $self, $cmd, $arg ) = @_; -=cut + return unless $cmd; -sub name { shift->{Name} } + local $Level = $Level + 1; local $BLevel = $BLevel + 1; -sub DESTROY { - my $self = shift; - if ( $self->parent and $$ == $self->{Original_Pid} ) { - my $name = $self->name; - $self->diag(<<"FAIL"); -Child ($name) exited without calling finalize() -FAIL - $self->parent->{In_Destroy} = 1; - $self->parent->ok(0, $name); + if( my $method = $PLAN_CMDS{$cmd} ) { + local $Level = $Level + 1; local $BLevel = $BLevel + 1; + $self->$method($arg); + } + else { + my @args = grep { defined } ( $cmd, $arg ); + $self->croak("plan() doesn't understand @args"); } + + return 1; } -=item B<reset> +sub skip_all { + my( $self, $reason ) = @_; - $Test->reset; + $self->{Skip_All} = $self->parent ? $reason : 1; -Reinitializes the Test::Builder singleton to its original state. -Mostly useful for tests run in persistent environments where the same -test might be run multiple times in the same process. + die bless {} => 'Test::Builder::Exception' if $self->parent; + $self->_issue_plan(0, "SKIP", $reason); +} -=cut +sub no_plan { + my($self, $arg) = @_; -our $Level; + $self->carp("no_plan takes no arguments") if $arg; -sub reset { ## no critic (Subroutines::ProhibitBuiltinHomonyms) - my($self) = @_; + $self->_issue_plan(undef, "NO_PLAN"); - # We leave this a global because it has to be localized and localizing - # hash keys is just asking for pain. Also, it was documented. - $Level = 1; + return 1; +} - $self->{Name} = $0; - $self->is_passing(1); - $self->{Ending} = 0; - $self->{Have_Plan} = 0; - $self->{No_Plan} = 0; - $self->{Have_Output_Plan} = 0; - $self->{Done_Testing} = 0; +sub _plan_tests { + my($self, $arg) = @_; - $self->{Original_Pid} = $$; - $self->{Child_Name} = undef; - $self->{Indent} ||= ''; + if($arg) { + $self->croak("Number of tests must be a positive integer. You gave it '$arg'") + unless $arg =~ /^\+?\d+$/; - $self->{Curr_Test} = 0; - $self->{Test_Results} = &share( [] ); + $self->_issue_plan($arg); + } + elsif( !defined $arg ) { + $self->croak("Got an undefined number of tests"); + } + else { + $self->croak("You said to run 0 tests"); + } - $self->{Exported_To} = undef; - $self->{Expected_Tests} = 0; + return; +} - $self->{Skip_All} = 0; +sub _issue_plan { + my($self, $max, $directive, $reason) = @_; - $self->{Use_Nums} = 1; + if ($directive && $directive eq 'OVERRIDE') { + $directive = undef; + } + elsif ($self->stream->plan) { + $self->croak("You tried to plan twice"); + } - $self->{No_Header} = 0; - $self->{No_Ending} = 0; + my $plan = Test::Builder::Result::Plan->new( + $self->context, + directive => $directive || undef, + reason => $reason || undef, + in_todo => $self->in_todo || 0, - $self->{Todo} = undef; - $self->{Todo_Stack} = []; - $self->{Start_Todo} = 0; - $self->{Opened_Testhandles} = 0; + max => defined($max) ? $max : undef, + ); - $self->_share_keys; - $self->_dup_stdhandles; + $self->stream->send($plan); - return; + return $plan; } +sub done_testing { + my($self, $num_tests) = @_; -# Shared scalar values are lost when a hash is copied, so we have -# a separate method to restore them. -# Shared references are retained across copies. -sub _share_keys { - my $self = shift; + my $expected = $self->stream->expected_tests; + my $total = $self->stream->tests_run; - share( $self->{Curr_Test} ); + # If done_testing() specified the number of tests, shut off no_plan. + if(defined $num_tests && !defined $expected) { + $self->_issue_plan($num_tests, 'OVERRIDE'); + $expected = $num_tests; + } - return; -} + if( $self->{Done_Testing} ) { + my($file, $line) = @{$self->{Done_Testing}}[1,2]; + my $ok = Test::Builder::Result::Ok->new( + $self->context, + real_bool => 0, + name => "done_testing() was already called at $file line $line", + bool => $self->in_todo ? 1 : 0, + in_todo => $self->in_todo || 0, + todo => $self->in_todo ? $self->todo() || "" : "", + ); + $self->stream->send($ok); + $self->is_passing(0) unless $self->in_todo; + return; + } -=back + $self->{Done_Testing} = [caller]; -=head2 Setting up tests + if ($expected && defined($num_tests) && $num_tests != $expected) { + my $ok = Test::Builder::Result::Ok->new( + $self->context, + real_bool => 0, + name => "planned to run $expected but done_testing() expects $num_tests", + bool => $self->in_todo ? 1 : 0, + in_todo => $self->in_todo || 0, + todo => $self->in_todo ? $self->todo() || "" : "", + ); + $self->stream->send($ok); + $self->is_passing(0) unless $self->in_todo; + } -These methods are for setting up tests and declaring how many there -are. You usually only want to call one of these methods. -=over 4 + $self->_issue_plan($total) unless $expected; -=item B<plan> + # The wrong number of tests were run + $self->is_passing(0) if defined $expected && $expected != $total; - $Test->plan('no_plan'); - $Test->plan( skip_all => $reason ); - $Test->plan( tests => $num_tests ); + # No tests were run + $self->is_passing(0) unless $total; -A convenient way to set up your tests. Call this and Test::Builder -will print the appropriate headers and take the appropriate actions. + return 1; +} -If you call C<plan()>, don't call any of the other methods below. +################ +# }}} Planning # +################ -If a child calls "skip_all" in the plan, a C<Test::Builder::Exception> is -thrown. Trap this error, call C<finalize()> and don't run any more tests on -the child. +############################# +# {{{ Base Result Producers # +############################# - my $child = $Test->child('some child'); - eval { $child->plan( $condition ? ( skip_all => $reason ) : ( tests => 3 ) ) }; - if ( eval { $@->isa('Test::Builder::Exception') } ) { - $child->finalize; - return; - } - # run your tests +sub _ok_obj { + my $self = shift; + my( $test, $name, @diag ) = @_; -=cut + if ( $self->{Child_Name} and not $self->{In_Destroy} ) { + $name = 'unnamed test' unless defined $name; + $self->is_passing(0); + $self->croak("Cannot run test ($name) with active children"); + } -my %plan_cmds = ( - no_plan => \&no_plan, - skip_all => \&skip_all, - tests => \&_plan_tests, -); + # $test might contain an object which we don't want to accidentally + # store, so we turn it into a boolean. + $test = $test ? 1 : 0; -sub plan { - my( $self, $cmd, $arg ) = @_; + # In case $name is a string overloaded object, force it to stringify. + $self->_unoverload_str( \$name ); - return unless $cmd; + # Capture the value of $TODO for the rest of this ok() call + # so it can more easily be found by other routines. + my $todo = $self->todo(); + my $in_todo = $self->in_todo; + local $self->{Todo} = $todo if $in_todo; + + $self->_unoverload_str( \$todo ); - local $Level = $Level + 1; + my $ok = Test::Builder::Result::Ok->new( + $self->context, + real_bool => $test, + bool => $self->in_todo ? 1 : $test, + name => $name || $self->default_name || undef, + in_todo => $self->in_todo || 0, + diag => \@diag, + ); - $self->croak("You tried to plan twice") if $self->{Have_Plan}; + # # in a name can confuse Test::Harness. + $name =~ s|#|\\#|g if defined $name; - if( my $method = $plan_cmds{$cmd} ) { - local $Level = $Level + 1; - $self->$method($arg); + if( $self->in_todo ) { + $ok->todo($todo); + $ok->in_todo(1); } - else { - my @args = grep { defined } ( $cmd, $arg ); - $self->croak("plan() doesn't understand @args"); + + if (defined $name and $name =~ /^[\d\s]+$/) { + $ok->diag(<<" ERR"); + You named your test '$name'. You shouldn't use numbers for your test names. + Very confusing. + ERR } - return 1; + return $ok; } +sub ok { + my $self = shift; + my( $test, $name, @diag ) = @_; -sub _plan_tests { - my($self, $arg) = @_; + my $ok = $self->_ok_obj($test, $name, @diag); + $self->_record_ok($ok); - if($arg) { - local $Level = $Level + 1; - return $self->expected_tests($arg); - } - elsif( !defined $arg ) { - $self->croak("Got an undefined number of tests"); - } - else { - $self->croak("You said to run 0 tests"); - } - - return; + return $test ? 1 : 0; } -=item B<expected_tests> - - my $max = $Test->expected_tests; - $Test->expected_tests($max); +sub _record_ok { + my $self = shift; + my ($ok) = @_; -Gets/sets the number of tests we expect this test to run and prints out -the appropriate headers. + $self->stream->send($ok); -=cut + $self->is_passing(0) unless $ok->real_bool || $self->in_todo; -sub expected_tests { - my $self = shift; - my($max) = @_; + # Check that we haven't violated the plan + $self->_check_is_passing_plan(); +} - if(@_) { - $self->croak("Number of tests must be a positive integer. You gave it '$max'") - unless $max =~ /^\+?\d+$/; +sub BAIL_OUT { + my( $self, $reason ) = @_; - $self->{Expected_Tests} = $max; - $self->{Have_Plan} = 1; + $self->_bailed_out(1); - $self->_output_plan($max) unless $self->no_header; + if ($self->parent) { + $self->{Bailed_Out_Reason} = $reason; + $self->no_ending(1); + die bless {} => 'Test::Builder::Exception'; } - return $self->{Expected_Tests}; + + my $bail = Test::Builder::Result::Bail->new( + $self->context, + reason => $reason, + in_todo => $self->in_todo || 0, + ); + $self->stream->send($bail); } -=item B<no_plan> +sub skip { + my( $self, $why ) = @_; + $why ||= ''; + $self->_unoverload_str( \$why ); - $Test->no_plan; + my $ok = Test::Builder::Result::Ok->new( + $self->context, + real_bool => 1, + bool => 1, + in_todo => $self->in_todo || 0, + skip => $why, + ); -Declares that this test will run an indeterminate number of tests. + $self->stream->send($ok); +} -=cut +sub todo_skip { + my( $self, $why ) = @_; + $why ||= ''; -sub no_plan { - my($self, $arg) = @_; + my $ok = Test::Builder::Result::Ok->new( + $self->context, + real_bool => 0, + bool => 1, + in_todo => $self->in_todo || 0, + skip => $why, + todo => $why, + ); - $self->carp("no_plan takes no arguments") if $arg; + $self->stream->send($ok); +} - $self->{No_Plan} = 1; - $self->{Have_Plan} = 1; +sub diag { + my $self = shift; - return 1; -} + my $msg = join '', map { defined($_) ? $_ : 'undef' } @_; -=begin private + my $r = Test::Builder::Result::Diag->new( + $self->context, + in_todo => $self->in_todo || 0, + message => $msg, + ); + $self->stream->send($r); +} -=item B<_output_plan> +sub note { + my $self = shift; - $tb->_output_plan($max); - $tb->_output_plan($max, $directive); - $tb->_output_plan($max, $directive => $reason); + my $msg = join '', map { defined($_) ? $_ : 'undef' } @_; -Handles displaying the test plan. + my $r = Test::Builder::Result::Note->new( + $self->context, + in_todo => $self->in_todo || 0, + message => $msg, + ); + $self->stream->send($r); +} -If a C<$directive> and/or C<$reason> are given they will be output with the -plan. So here's what skipping all tests looks like: +############################# +# }}} Base Result Producers # +############################# - $tb->_output_plan(0, "SKIP", "Because I said so"); +################################# +# {{{ Advanced Result Producers # +################################# -It sets C<< $tb->{Have_Output_Plan} >> and will croak if the plan was already -output. +my %numeric_cmps = map { ( $_, 1 ) } ( "<", "<=", ">", ">=", "==", "!=", "<=>" ); -=end private +# Bad, these are not comparison operators. Should we include more? +my %cmp_ok_bl = map { ( $_, 1 ) } ( "=", "+=", ".=", "x=", "^=", "|=", "||=", "&&=", "..."); -=cut +sub cmp_ok { + my( $self, $got, $type, $expect, $name ) = @_; -sub _output_plan { - my($self, $max, $directive, $reason) = @_; + if ($cmp_ok_bl{$type}) { + $self->croak("$type is not a valid comparison operator in cmp_ok()"); + } - $self->carp("The plan was already output") if $self->{Have_Output_Plan}; + my $test; + my $error; + my @diag; - my $plan = "1..$max"; - $plan .= " # $directive" if defined $directive; - $plan .= " $reason" if defined $reason; + my($pack, $file, $line) = $self->trace_test->report->call; - $self->_print("$plan\n"); + (undef, $error) = try { + # This is so that warnings come out at the caller's level + ## no critic (BuiltinFunctions::ProhibitStringyEval) + eval qq[ +#line $line "(eval in cmp_ok) $file" +\$test = \$got $type \$expect; +1; + ] || die $@; + }; - $self->{Have_Output_Plan} = 1; + # Treat overloaded objects as numbers if we're asked to do a + # numeric comparison. + my $unoverload + = $numeric_cmps{$type} + ? '_unoverload_num' + : '_unoverload_str'; - return; -} + push @diag => <<"END" if $error; +An error occurred while using $type: +------------------------------------ +$error +------------------------------------ +END + unless($test) { + $self->$unoverload( \$got, \$expect ); -=item B<done_testing> + if( $type =~ /^(eq|==)$/ ) { + push @diag => $self->_is_diag( $got, $type, $expect ); + } + elsif( $type =~ /^(ne|!=)$/ ) { + push @diag => $self->_isnt_diag( $got, $type ); + } + else { + push @diag => $self->_cmp_diag( $got, $type, $expect ); + } + } - $Test->done_testing(); - $Test->done_testing($num_tests); + local $Level = $Level + 1; local $BLevel = $BLevel + 1; + $self->ok($test, $name, @diag); -Declares that you are done testing, no more tests will be run after this point. + return $test ? 1 : 0; +} -If a plan has not yet been output, it will do so. -$num_tests is the number of tests you planned to run. If a numbered -plan was already declared, and if this contradicts, a failing test -will be run to reflect the planning mistake. If C<no_plan> was declared, -this will override. +sub is_eq { + my( $self, $got, $expect, $name ) = @_; + local $Level = $Level + 1; local $BLevel = $BLevel + 1; -If C<done_testing()> is called twice, the second call will issue a -failing test. + if( !defined $got || !defined $expect ) { + # undef only matches undef and nothing else + my $test = !defined $got && !defined $expect; -If C<$num_tests> is omitted, the number of tests run will be used, like -no_plan. + $self->ok($test, $name, $test ? () : $self->_is_diag( $got, 'eq', $expect )); + return $test; + } -C<done_testing()> is, in effect, used when you'd want to use C<no_plan>, but -safer. You'd use it like so: + return $self->cmp_ok( $got, 'eq', $expect, $name ); +} - $Test->ok($a == $b); - $Test->done_testing(); +sub is_num { + my( $self, $got, $expect, $name ) = @_; + local $Level = $Level + 1; local $BLevel = $BLevel + 1; -Or to plan a variable number of tests: + if( !defined $got || !defined $expect ) { + # undef only matches undef and nothing else + my $test = !defined $got && !defined $expect; - for my $test (@tests) { - $Test->ok($test); + $self->ok($test, $name, $test ? () : $self->_is_diag( $got, '==', $expect )); + return $test; } - $Test->done_testing(scalar @tests); -=cut + return $self->cmp_ok( $got, '==', $expect, $name ); +} -sub done_testing { - my($self, $num_tests) = @_; +sub isnt_eq { + my( $self, $got, $dont_expect, $name ) = @_; + local $Level = $Level + 1; local $BLevel = $BLevel + 1; - # If done_testing() specified the number of tests, shut off no_plan. - if( defined $num_tests ) { - $self->{No_Plan} = 0; - } - else { - $num_tests = $self->current_test; - } + if( !defined $got || !defined $dont_expect ) { + # undef only matches undef and nothing else + my $test = defined $got || defined $dont_expect; - if( $self->{Done_Testing} ) { - my($file, $line) = @{$self->{Done_Testing}}[1,2]; - $self->ok(0, "done_testing() was already called at $file line $line"); - return; + $self->ok( $test, $name, $test ? () : $self->_isnt_diag( $got, 'ne' )); + return $test; } - $self->{Done_Testing} = [caller]; + return $self->cmp_ok( $got, 'ne', $dont_expect, $name ); +} - if( $self->expected_tests && $num_tests != $self->expected_tests ) { - $self->ok(0, "planned to run @{[ $self->expected_tests ]} ". - "but done_testing() expects $num_tests"); - } - else { - $self->{Expected_Tests} = $num_tests; - } +sub isnt_num { + my( $self, $got, $dont_expect, $name ) = @_; + local $Level = $Level + 1; local $BLevel = $BLevel + 1; - $self->_output_plan($num_tests) unless $self->{Have_Output_Plan}; + if( !defined $got || !defined $dont_expect ) { + # undef only matches undef and nothing else + my $test = defined $got || defined $dont_expect; - $self->{Have_Plan} = 1; + $self->ok( $test, $name, $test ? () : $self->_isnt_diag( $got, '!=' )); + return $test; + } - # The wrong number of tests were run - $self->is_passing(0) if $self->{Expected_Tests} != $self->{Curr_Test}; + return $self->cmp_ok( $got, '!=', $dont_expect, $name ); +} - # No tests were run - $self->is_passing(0) if $self->{Curr_Test} == 0; +sub like { + my( $self, $thing, $regex, $name ) = @_; + local $Level = $Level + 1; local $BLevel = $BLevel + 1; - return 1; + return $self->_regex_ok( $thing, $regex, '=~', $name ); } +sub unlike { + my( $self, $thing, $regex, $name ) = @_; + local $Level = $Level + 1; local $BLevel = $BLevel + 1; -=item B<has_plan> + return $self->_regex_ok( $thing, $regex, '!~', $name ); +} - $plan = $Test->has_plan -Find out whether a plan has been defined. C<$plan> is either C<undef> (no plan -has been set), C<no_plan> (indeterminate # of tests) or an integer (the number -of expected tests). -=cut +################################# +# }}} Advanced Result Producers # +################################# -sub has_plan { - my $self = shift; +####################### +# {{{ Public helpers # +####################### - return( $self->{Expected_Tests} ) if $self->{Expected_Tests}; - return('no_plan') if $self->{No_Plan}; - return(undef); -} +sub explain { + my $self = shift; -=item B<skip_all> + return map { + ref $_ + ? do { + $self->_try(sub { require Data::Dumper }, die_on_fail => 1); - $Test->skip_all; - $Test->skip_all($reason); + my $dumper = Data::Dumper->new( [$_] ); + $dumper->Indent(1)->Terse(1); + $dumper->Sortkeys(1) if $dumper->can("Sortkeys"); + $dumper->Dump; + } + : $_ + } @_; +} -Skips all the tests, using the given C<$reason>. Exits immediately with 0. +sub carp { + my $self = shift; + return warn $self->_message_at_caller(@_); +} -=cut +sub croak { + my $self = shift; + return die $self->_message_at_caller(@_); +} -sub skip_all { - my( $self, $reason ) = @_; +sub context { + my $self = shift; - $self->{Skip_All} = $self->parent ? $reason : 1; + my $trace = $self->trace_test; - $self->_output_plan(0, "SKIP", $reason) unless $self->no_header; - if ( $self->parent ) { - die bless {} => 'Test::Builder::Exception'; - } - exit(0); + return ( + depth => $self->depth, + source => $self->name || "", + trace => $trace, + ); } -=item B<exported_to> +sub has_plan { + my $self = shift; - my $pack = $Test->exported_to; - $Test->exported_to($pack); + return($self->stream->expected_tests) if $self->stream->expected_tests; + return('no_plan') if $self->stream->plan; + return(undef); +} -Tells Test::Builder what package you exported your functions to. +sub reset { ## no critic (Subroutines::ProhibitBuiltinHomonyms) + my $self = shift; + my %params; -This method isn't terribly useful since modules which share the same -Test::Builder object might get exported to different packages and only -the last one will be honored. + if (@_) { + %params = @_; + $self->{reset_params} = \%params; + } + else { + %params = %{$self->{reset_params} || {}}; + } -=cut + my $modern = $params{modern} || $self->modern || 0; + $self->modern($modern); -sub exported_to { - my( $self, $pack ) = @_; + # We leave this a global because it has to be localized and localizing + # hash keys is just asking for pain. Also, it was documented. + $Level = 1; + $BLevel = 1; - if( defined $pack ) { - $self->{Exported_To} = $pack; + if ($params{new_stream} || !$params{shared_stream}) { + my $olds = $self->stream; + $self->{stream} = Test::Builder::Stream->new; + $self->{stream}->use_lresults if $olds->lresults; } - return $self->{Exported_To}; -} -=back - -=head2 Running tests + $final->pid($$) if $final; -These actually run the tests, analogous to the functions in Test::More. + $self->stream->use_tap unless $params{no_tap} || $ENV{TB_NO_TAP}; -They all return true if the test passed, false if the test failed. + $self->stream->plan(undef) unless $params{no_reset_plan}; -C<$name> is always optional. + # Don't reset stream stuff when reseting/creating a modern TB object + unless ($modern) { + $self->stream->no_ending(0); + $self->tap->reset if $self->tap; + $self->lresults->reset if $self->lresults; + } -=over 4 + $self->{Name} = $0; -=item B<ok> + $self->{Have_Issued_Plan} = 0; + $self->{Done_Testing} = 0; + $self->{Skip_All} = 0; - $Test->ok($test, $name); + $self->{Original_Pid} = $$; + $self->{Child_Name} = undef; + $self->{Indent} ||= ''; + $self->{Depth} = 0; -Your basic test. Pass if C<$test> is true, fail if $test is false. Just -like Test::Simple's C<ok()>. + $self->{Exported_To} = undef; + $self->{Expected_Tests} = 0; -=cut + $self->{Todo} = undef; + $self->{Todo_Stack} = []; + $self->{Start_Todo} = 0; + $self->{Opened_Testhandles} = 0; -sub ok { - my( $self, $test, $name ) = @_; + return; +} - if ( $self->{Child_Name} and not $self->{In_Destroy} ) { - $name = 'unnamed test' unless defined $name; - $self->is_passing(0); - $self->croak("Cannot run test ($name) with active children"); - } - # $test might contain an object which we don't want to accidentally - # store, so we turn it into a boolean. - $test = $test ? 1 : 0; - lock $self->{Curr_Test}; - $self->{Curr_Test}++; +####################### +# }}} Public helpers # +####################### - # In case $name is a string overloaded object, force it to stringify. - $self->_unoverload_str( \$name ); +#################### +# {{{ TODO related # +#################### - $self->diag(<<"ERR") if defined $name and $name =~ /^[\d\s]+$/; - You named your test '$name'. You shouldn't use numbers for your test names. - Very confusing. -ERR +sub todo { + my( $self, $pack ) = @_; - # Capture the value of $TODO for the rest of this ok() call - # so it can more easily be found by other routines. - my $todo = $self->todo(); - my $in_todo = $self->in_todo; - local $self->{Todo} = $todo if $in_todo; + return $self->{Todo} if defined $self->{Todo}; - $self->_unoverload_str( \$todo ); + local $Level = $Level + 1; local $BLevel = $BLevel + 1; + my $todo = $self->find_TODO($pack); + return $todo if defined $todo; - my $out; - my $result = &share( {} ); + return ''; +} - unless($test) { - $out .= "not "; - @$result{ 'ok', 'actual_ok' } = ( ( $self->in_todo ? 1 : 0 ), 0 ); - } - else { - @$result{ 'ok', 'actual_ok' } = ( 1, $test ); - } +sub in_todo { + my $self = shift; - $out .= "ok"; - $out .= " $self->{Curr_Test}" if $self->use_numbers; + local $Level = $Level + 1; local $BLevel = $BLevel + 1; + return( defined $self->{Todo} || $self->find_TODO ) ? 1 : 0; +} - if( defined $name ) { - $name =~ s|#|\\#|g; # # in a name can confuse Test::Harness. - $out .= " - $name"; - $result->{name} = $name; - } - else { - $result->{name} = ''; - } +sub todo_start { + my $self = shift; + my $message = @_ ? shift : ''; + $self->{Start_Todo}++; if( $self->in_todo ) { - $out .= " # TODO $todo"; - $result->{reason} = $todo; - $result->{type} = 'todo'; - } - else { - $result->{reason} = ''; - $result->{type} = ''; + push @{ $self->{Todo_Stack} } => $self->todo; } + $self->{Todo} = $message; - $self->{Test_Results}[ $self->{Curr_Test} - 1 ] = $result; - $out .= "\n"; - - $self->_print($out); + return; +} - unless($test) { - my $msg = $self->in_todo ? "Failed (TODO)" : "Failed"; - $self->_print_to_fh( $self->_diag_fh, "\n" ) if $ENV{HARNESS_ACTIVE}; +sub todo_end { + my $self = shift; - my( undef, $file, $line ) = $self->caller; - if( defined $name ) { - $self->diag(qq[ $msg test '$name'\n]); - $self->diag(qq[ at $file line $line.\n]); - } - else { - $self->diag(qq[ $msg test at $file line $line.\n]); - } + if( !$self->{Start_Todo} ) { + $self->croak('todo_end() called without todo_start()'); } - $self->is_passing(0) unless $test || $self->in_todo; + $self->{Start_Todo}--; - # Check that we haven't violated the plan - $self->_check_is_passing_plan(); + if( $self->{Start_Todo} && @{ $self->{Todo_Stack} } ) { + $self->{Todo} = pop @{ $self->{Todo_Stack} }; + } + else { + delete $self->{Todo}; + } - return $test ? 1 : 0; + return; } +#################### +# }}} TODO related # +#################### + +####################### +# {{{ Private helpers # +####################### # Check that we haven't yet violated the plan and set # is_passing() accordingly sub _check_is_passing_plan { my $self = shift; - my $plan = $self->has_plan; + my $plan = $self->stream->expected_tests; return unless defined $plan; # no plan yet defined return unless $plan !~ /\D/; # no numeric plan - $self->is_passing(0) if $plan < $self->{Curr_Test}; + $self->is_passing(0) if $plan < $self->stream->tests_run; } +sub _is_object { + my( $self, $thing ) = @_; + + return $self->_try( sub { ref $thing && $thing->isa('UNIVERSAL') } ) ? 1 : 0; +} sub _unoverload { my $self = shift; @@ -924,12 +988,6 @@ sub _unoverload { return; } -sub _is_object { - my( $self, $thing ) = @_; - - return $self->_try( sub { ref $thing && $thing->isa('UNIVERSAL') } ) ? 1 : 0; -} - sub _unoverload_str { my $self = shift; @@ -961,58 +1019,6 @@ sub _is_dualvar { return ($numval != 0 and $numval ne $val ? 1 : 0); } -=item B<is_eq> - - $Test->is_eq($got, $expected, $name); - -Like Test::More's C<is()>. Checks if C<$got eq $expected>. This is the -string version. - -C<undef> only ever matches another C<undef>. - -=item B<is_num> - - $Test->is_num($got, $expected, $name); - -Like Test::More's C<is()>. Checks if C<$got == $expected>. This is the -numeric version. - -C<undef> only ever matches another C<undef>. - -=cut - -sub is_eq { - my( $self, $got, $expect, $name ) = @_; - local $Level = $Level + 1; - - if( !defined $got || !defined $expect ) { - # undef only matches undef and nothing else - my $test = !defined $got && !defined $expect; - - $self->ok( $test, $name ); - $self->_is_diag( $got, 'eq', $expect ) unless $test; - return $test; - } - - return $self->cmp_ok( $got, 'eq', $expect, $name ); -} - -sub is_num { - my( $self, $got, $expect, $name ) = @_; - local $Level = $Level + 1; - - if( !defined $got || !defined $expect ) { - # undef only matches undef and nothing else - my $test = !defined $got && !defined $expect; - - $self->ok( $test, $name ); - $self->_is_diag( $got, '==', $expect ) unless $test; - return $test; - } - - return $self->cmp_ok( $got, '==', $expect, $name ); -} - sub _diag_fmt { my( $self, $type, $val ) = @_; @@ -1035,1084 +1041,996 @@ sub _diag_fmt { sub _is_diag { my( $self, $got, $type, $expect ) = @_; + local $Level = $Level + 1; local $BLevel = $BLevel + 1; $self->_diag_fmt( $type, $_ ) for \$got, \$expect; - local $Level = $Level + 1; - return $self->diag(<<"DIAGNOSTIC"); + return <<"DIAGNOSTIC"; got: $got expected: $expect DIAGNOSTIC - } sub _isnt_diag { my( $self, $got, $type ) = @_; + local $Level = $Level + 1; local $BLevel = $BLevel + 1; $self->_diag_fmt( $type, \$got ); - local $Level = $Level + 1; - return $self->diag(<<"DIAGNOSTIC"); + return <<"DIAGNOSTIC"; got: $got expected: anything else DIAGNOSTIC } -=item B<isnt_eq> - - $Test->isnt_eq($got, $dont_expect, $name); - -Like Test::More's C<isnt()>. Checks if C<$got ne $dont_expect>. This is -the string version. - -=item B<isnt_num> - $Test->isnt_num($got, $dont_expect, $name); +sub _cmp_diag { + my( $self, $got, $type, $expect ) = @_; -Like Test::More's C<isnt()>. Checks if C<$got ne $dont_expect>. This is -the numeric version. + $got = defined $got ? "'$got'" : 'undef'; + $expect = defined $expect ? "'$expect'" : 'undef'; -=cut + local $Level = $Level + 1; local $BLevel = $BLevel + 1; + return <<"DIAGNOSTIC"; + $got + $type + $expect +DIAGNOSTIC +} -sub isnt_eq { - my( $self, $got, $dont_expect, $name ) = @_; - local $Level = $Level + 1; +sub _caller_context { + my $self = shift; - if( !defined $got || !defined $dont_expect ) { - # undef only matches undef and nothing else - my $test = defined $got || defined $dont_expect; + my($pack, $file, $line) = $self->trace_test->report->call; - $self->ok( $test, $name ); - $self->_isnt_diag( $got, 'ne' ) unless $test; - return $test; - } + my $code = ''; + $code .= "#line $line $file\n" if defined $file and defined $line; - return $self->cmp_ok( $got, 'ne', $dont_expect, $name ); + return $code; } -sub isnt_num { - my( $self, $got, $dont_expect, $name ) = @_; - local $Level = $Level + 1; - - if( !defined $got || !defined $dont_expect ) { - # undef only matches undef and nothing else - my $test = defined $got || defined $dont_expect; +sub _regex_ok { + my( $self, $thing, $regex, $cmp, $name ) = @_; - $self->ok( $test, $name ); - $self->_isnt_diag( $got, '!=' ) unless $test; - return $test; + my $ok = 0; + my $usable_regex = _is_qr($regex) ? $regex : $self->maybe_regex($regex); + unless( defined $usable_regex ) { + local $Level = $Level + 1; local $BLevel = $BLevel + 1; + $ok = $self->ok( 0, $name, " '$regex' doesn't look much like a regex to me."); + return $ok; } - return $self->cmp_ok( $got, '!=', $dont_expect, $name ); -} + my $test; + my $context = $self->_caller_context; -=item B<like> + try { + # No point in issuing an uninit warning, they'll see it in the diagnostics + no warnings 'uninitialized'; + ## no critic (BuiltinFunctions::ProhibitStringyEval) + $test = eval $context . q{$test = $thing =~ /$usable_regex/ ? 1 : 0}; + }; - $Test->like($thing, qr/$regex/, $name); - $Test->like($thing, '/$regex/', $name); + $test = !$test if $cmp eq '!~'; -Like Test::More's C<like()>. Checks if $thing matches the given C<$regex>. + my @diag; + unless($test) { + $thing = defined $thing ? "'$thing'" : 'undef'; + my $match = $cmp eq '=~' ? "doesn't match" : "matches"; -=item B<unlike> + push @diag => sprintf( <<'DIAGNOSTIC', $thing, $match, $regex ); + %s + %13s '%s' +DIAGNOSTIC + } - $Test->unlike($thing, qr/$regex/, $name); - $Test->unlike($thing, '/$regex/', $name); + local $Level = $Level + 1; local $BLevel = $BLevel + 1; + $self->ok( $test, $name, @diag ); -Like Test::More's C<unlike()>. Checks if $thing B<does not match> the -given C<$regex>. + return $test; +} -=cut +# I'm not ready to publish this. It doesn't deal with array return +# values from the code or context. +sub _try { + my( $self, $code, %opts ) = @_; -sub like { - my( $self, $thing, $regex, $name ) = @_; + my $result; + my ($ok, $error) = try { $result = $code->() }; - local $Level = $Level + 1; - return $self->_regex_ok( $thing, $regex, '=~', $name ); + die $error if $opts{die_on_fail} && !$ok; + + return wantarray ? ( $result, $error ) : $result; } -sub unlike { - my( $self, $thing, $regex, $name ) = @_; +sub _message_at_caller { + my $self = shift; - local $Level = $Level + 1; - return $self->_regex_ok( $thing, $regex, '!~', $name ); + local $Level = $Level + 1; local $BLevel = $BLevel + 1; + my $trace = $self->trace_test; + my( $pack, $file, $line ) = $trace->report->call; + return join( "", @_ ) . " at $file line $line.\n"; } -=item B<cmp_ok> - - $Test->cmp_ok($thing, $type, $that, $name); +#'# +sub _sanity_check { + my $self = shift; -Works just like Test::More's C<cmp_ok()>. + $self->_whoa( $self->stream->tests_run < 0, 'Says here you ran a negative number of tests!' ); - $Test->cmp_ok($big_num, '!=', $other_big_num); + $self->lresults->sanity_check($self) if $self->lresults; -=cut + return; +} -my %numeric_cmps = map { ( $_, 1 ) } ( "<", "<=", ">", ">=", "==", "!=", "<=>" ); +sub _whoa { + my( $self, $check, $desc ) = @_; + if($check) { + local $Level = $Level + 1; local $BLevel = $BLevel + 1; + $self->croak(<<"WHOA"); +WHOA! $desc +This should never happen! Please contact the author immediately! +WHOA + } -# Bad, these are not comparison operators. Should we include more? -my %cmp_ok_bl = map { ( $_, 1 ) } ( "=", "+=", ".=", "x=", "^=", "|=", "||=", "&&=", "..."); + return; +} -sub cmp_ok { - my( $self, $got, $type, $expect, $name ) = @_; +sub _ending { + my $self = shift; + require Test::Builder::ExitMagic; + my $ending = Test::Builder::ExitMagic->new(tb => $self, stream => $self->stream); + $ending->do_magic; +} - if ($cmp_ok_bl{$type}) { - $self->croak("$type is not a valid comparison operator in cmp_ok()"); - } +sub _is_qr { + my $regex = shift; - my $test; - my $error; - { - ## no critic (BuiltinFunctions::ProhibitStringyEval) + # is_regexp() checks for regexes in a robust manner, say if they're + # blessed. + return re::is_regexp($regex) if defined &re::is_regexp; + return ref $regex eq 'Regexp'; +} - local( $@, $!, $SIG{__DIE__} ); # isolate eval +####################### +# }}} Private helpers # +####################### - my($pack, $file, $line) = $self->caller(); +################################################ +# {{{ Everything below this line is deprecated # +# But it must be maintained for legacy... # +################################################ - # This is so that warnings come out at the caller's level - $test = eval qq[ -#line $line "(eval in cmp_ok) $file" -\$got $type \$expect; -]; - $error = $@; - } - local $Level = $Level + 1; - my $ok = $self->ok( $test, $name ); +BEGIN { + my %generate = ( + lresults => [qw/summary details/], + stream => [qw/no_ending/], + tap => [qw/ + no_header no_diag output failure_output todo_output reset_outputs + use_numbers _new_fh + /], + ); - # Treat overloaded objects as numbers if we're asked to do a - # numeric comparison. - my $unoverload - = $numeric_cmps{$type} - ? '_unoverload_num' - : '_unoverload_str'; + for my $delegate (keys %generate) { + for my $method (@{$generate{$delegate}}) { + #print STDERR "Adding: $method ($delegate)\n"; + my $code = sub { + my $self = shift; - $self->diag(<<"END") if $error; -An error occurred while using $type: ------------------------------------- -$error ------------------------------------- -END + $self->carp("Use of \$TB->$method() is deprecated.") if $self->modern; + my $d = $self->$delegate || $self->croak("$method() method only applies when $delegate is in use"); - unless($ok) { - $self->$unoverload( \$got, \$expect ); + $d->$method(@_); + }; - if( $type =~ /^(eq|==)$/ ) { - $self->_is_diag( $got, $type, $expect ); - } - elsif( $type =~ /^(ne|!=)$/ ) { - $self->_isnt_diag( $got, $type ); - } - else { - $self->_cmp_diag( $got, $type, $expect ); + no strict 'refs'; ## no critic + *{$method} = $code; } } - return $ok; } -sub _cmp_diag { - my( $self, $got, $type, $expect ) = @_; +sub exported_to { + my($self, $pack) = @_; + $self->carp("exported_to() is deprecated") if $self->modern; + $self->{Exported_To} = $pack if defined $pack; + return $self->{Exported_To}; +} - $got = defined $got ? "'$got'" : 'undef'; - $expect = defined $expect ? "'$expect'" : 'undef'; +sub _indent { + my $self = shift; + $self->carp("_indent() is deprecated") if $self->modern; + return '' unless $self->depth; + return ' ' x $self->depth +} - local $Level = $Level + 1; - return $self->diag(<<"DIAGNOSTIC"); - $got - $type - $expect -DIAGNOSTIC +sub _output_plan { + my ($self) = @_; + $self->carp("_output_plan() is deprecated") if $self->modern; + goto &_issue_plan; } -sub _caller_context { +sub _diag_fh { my $self = shift; - my( $pack, $file, $line ) = $self->caller(1); - - my $code = ''; - $code .= "#line $line $file\n" if defined $file and defined $line; + $self->carp("Use of \$TB->_diag_fh() is deprecated.") if $self->modern; + my $tap = $self->tap || $self->croak("_diag_fh() method only applies when TAP is in use"); - return $code; + local $Level = $Level + 1; local $BLevel = $BLevel + 1; + return $tap->_diag_fh($self->in_todo) } -=back +sub _print { + my $self = shift; + $self->carp("Use of \$TB->_print() is deprecated.") if $self->modern; + my $tap = $self->tap || $self->croak("_print() method only applies when TAP is in use"); -=head2 Other Testing Methods + return $tap->_print($self->_indent, @_); +} -These are methods which are used in the course of writing a test but are not themselves tests. +sub _print_to_fh { + my( $self, $fh, @msgs ) = @_; -=over 4 + $self->carp("Use of \$TB->_print_to_fh() is deprecated.") if $self->modern; + my $tap = $self->tap || $self->croak("_print_to_fh() method only applies when TAP is in use"); -=item B<BAIL_OUT> + return $tap->_print_to_fh($fh, $self->_indent, @msgs); +} - $Test->BAIL_OUT($reason); +sub is_fh { + my $self = shift; -Indicates to the Test::Harness that things are going so badly all -testing should terminate. This includes running any additional test -scripts. + $self->carp("Use of \$TB->is_fh() is deprecated.") + if Scalar::Util::blessed($self) && $self->modern; -It will exit with 255. + require Test::Builder::Formatter::TAP; + return Test::Builder::Formatter::TAP->is_fh(@_); +} -=cut +sub current_test { + my $self = shift; -sub BAIL_OUT { - my( $self, $reason ) = @_; + my $tap = $self->tap; + my $lresults = $self->lresults; - $self->{Bailed_Out} = 1; + if (@_) { + my ($num) = @_; - if ($self->parent) { - $self->{Bailed_Out_Reason} = $reason; - $self->no_ending(1); - die bless {} => 'Test::Builder::Exception'; + $lresults->current_test($num) if $lresults; + $tap->current_test($num) if $tap; + + $self->stream->tests_run(0 - $self->stream->tests_run + $num); } - $self->_print("Bail out! $reason"); - exit 255; + return $self->stream->tests_run; } -=for deprecated -BAIL_OUT() used to be BAILOUT() - -=cut - -{ - no warnings 'once'; - *BAILOUT = \&BAIL_OUT; +sub BAILOUT { + my ($self) = @_; + $self->carp("Use of \$TB->BAILOUT() is deprecated.") if $self->modern; + goto &BAIL_OUT; } -=item B<skip> - - $Test->skip; - $Test->skip($why); - -Skips the current test, reporting C<$why>. - -=cut +sub expected_tests { + my $self = shift; -sub skip { - my( $self, $why ) = @_; - $why ||= ''; - $self->_unoverload_str( \$why ); + if(@_) { + my ($max) = @_; + $self->carp("Use of \$TB->expected_tests(\$max) is deprecated.") if $self->modern; + $self->_issue_plan($max); + } - lock( $self->{Curr_Test} ); - $self->{Curr_Test}++; + return $self->stream->expected_tests || 0; +} - $self->{Test_Results}[ $self->{Curr_Test} - 1 ] = &share( - { - 'ok' => 1, - actual_ok => 1, - name => '', - type => 'skip', - reason => $why, - } - ); +sub caller { ## no critic (Subroutines::ProhibitBuiltinHomonyms) + my $self = shift; - my $out = "ok"; - $out .= " $self->{Curr_Test}" if $self->use_numbers; - $out .= " # skip"; - $out .= " $why" if length $why; - $out .= "\n"; + Carp::confess("Use of Test::Builder->caller() is deprecated.\n") if $self->modern; - $self->_print($out); + local $Level = $Level + 1; local $BLevel = $BLevel + 1; + my $trace = $self->trace_test; + return unless $trace && $trace->report; + my @call = $trace->report->call; - return 1; + return wantarray ? @call : $call[0]; } -=item B<todo_skip> +sub level { + my( $self, $level ) = @_; + $Level = $level if defined $level; + return $Level; +} - $Test->todo_skip; - $Test->todo_skip($why); +sub maybe_regex { + my ($self, $regex) = @_; + my $usable_regex = undef; -Like C<skip()>, only it will declare the test as failing and TODO. Similar -to + $self->carp("Use of \$TB->maybe_regex() is deprecated.") if $self->modern; - print "not ok $tnum # TODO $why\n"; + return $usable_regex unless defined $regex; -=cut + my( $re, $opts ); -sub todo_skip { - my( $self, $why ) = @_; - $why ||= ''; + # Check for qr/foo/ + if( _is_qr($regex) ) { + $usable_regex = $regex; + } + # Check for '/foo/' or 'm,foo,' + elsif(( $re, $opts ) = $regex =~ m{^ /(.*)/ (\w*) $ }sx or + ( undef, $re, $opts ) = $regex =~ m,^ m([^\w\s]) (.+) \1 (\w*) $,sx + ) + { + $usable_regex = length $opts ? "(?$opts)$re" : $re; + } - lock( $self->{Curr_Test} ); - $self->{Curr_Test}++; + return $usable_regex; +} - $self->{Test_Results}[ $self->{Curr_Test} - 1 ] = &share( - { - 'ok' => 1, - actual_ok => 0, - name => '', - type => 'todo_skip', - reason => $why, - } - ); - my $out = "not ok"; - $out .= " $self->{Curr_Test}" if $self->use_numbers; - $out .= " # TODO & SKIP $why\n"; +################################### +# }}} End of deprecations section # +################################### - $self->_print($out); +#################### +# {{{ TB1.5 stuff # +#################### - return 1; -} +# This is just a list of method Test::Builder current does not have that Test::Builder 1.5 does. +my %TB15_METHODS = map {$_ => 1} qw{ + _file_and_line _join_message _make_default _my_exit _reset_todo_state + _result_to_hash _results _todo_state formatter history in_subtest in_test + no_change_exit_code post_event post_result set_formatter set_plan test_end + test_exit_code test_start test_state +}; -=begin _unimplemented +our $AUTOLOAD; +sub AUTOLOAD { + $AUTOLOAD =~ m/^(.*)::([^:]+)$/; + my ($package, $sub) = ($1, $2); -=item B<skip_rest> + my @caller = CORE::caller(); + my $msg = qq{Can't locate object method "$sub" via package "$package" at $caller[1] line $caller[2]\n}; - $Test->skip_rest; - $Test->skip_rest($reason); + $msg .= <<" EOT" if $TB15_METHODS{$sub}; -Like C<skip()>, only it skips all the rest of the tests you plan to run -and terminates the test. + ************************************************************************* + '$sub' is a Test::Builder 1.5 method. Test::Builder 1.5 is a dead branch. + You need to update your code so that it no longer treats Test::Builders + over a specific version number as anything special. -If you're running under C<no_plan>, it skips once and terminates the -test. + See: http://blogs.perl.org/users/chad_exodist_granum/2014/03/testmore---new-maintainer-also-stop-version-checking.html + ************************************************************************* + EOT -=end _unimplemented + die $msg; +} -=back +#################### +# }}} TB1.5 stuff # +#################### +1; -=head2 Test building utility methods +__END__ -These methods are useful when writing your own test methods. +=head1 NAME -=over 4 +Test::Builder - Backend for building test libraries -=item B<maybe_regex> +=head1 NOTE ON DEPRECATIONS - $Test->maybe_regex(qr/$regex/); - $Test->maybe_regex('/$regex/'); +With version 1.301001 many old methods and practices have been deprecated. What +we mean when we say "deprecated" is that the practices or methods are not to be +used in any new code. Old code that uses them will still continue to work, +possibly forever, but new code should use the newer and better alternatives. -This method used to be useful back when Test::Builder worked on Perls -before 5.6 which didn't have qr//. Now its pretty useless. +In the future, if enough (read: pretty much everything) is updated and few if +any modules still use these old items, they will be removed completely. This is +not super likely to happen just because of the sheer number of modules that use +Test::Builder. -Convenience method for building testing functions that take regular -expressions as arguments. +=head1 SYNOPSIS -Takes a quoted regular expression produced by C<qr//>, or a string -representing a regular expression. +In general you probably do not want to use this module directly, but instead +want to use L<Test::Builder::Provider> which will help you roll out a testing +library. -Returns a Perl value which may be used instead of the corresponding -regular expression, or C<undef> if its argument is not recognised. + package My::Test::Module; + use Test::Builder::Provider; -For example, a version of C<like()>, sans the useful diagnostic messages, -could be written as: + # Export a test tool from an anonymous sub + provide ok => sub { + my ($test, $name) = @_; + builder()->ok($test, $name); + }; - sub laconic_like { - my ($self, $thing, $regex, $name) = @_; - my $usable_regex = $self->maybe_regex($regex); - die "expecting regex, found '$regex'\n" - unless $usable_regex; - $self->ok($thing =~ m/$usable_regex/, $name); - } + # Export tools that are package subs + provides qw/is is_deeply/; + sub is { ... } + sub is_deeply { ... } -=cut +See L<Test::Builder::Provider> for more details. -sub maybe_regex { - my( $self, $regex ) = @_; - my $usable_regex = undef; +B<Note:> You MUST use 'provide', or 'provides' to export testing tools, this +allows you to use the C<< builder()->trace_test >> tools to determine what +file/line a failed test came from. - return $usable_regex unless defined $regex; +=head2 LOW-LEVEL - my( $re, $opts ); + use Test::Builder; + my $tb = Test::Builder->create(modern => 1, shared_stream => 1); + $tb->ok(1); + .... - # Check for qr/foo/ - if( _is_qr($regex) ) { - $usable_regex = $regex; - } - # Check for '/foo/' or 'm,foo,' - elsif(( $re, $opts ) = $regex =~ m{^ /(.*)/ (\w*) $ }sx or - ( undef, $re, $opts ) = $regex =~ m,^ m([^\w\s]) (.+) \1 (\w*) $,sx - ) - { - $usable_regex = length $opts ? "(?$opts)$re" : $re; - } +=head2 DEPRECATED - return $usable_regex; -} + use Test::Builder; + my $tb = Test::Builder->new; + $tb->ok(1); + ... -sub _is_qr { - my $regex = shift; +=head1 DESCRIPTION - # is_regexp() checks for regexes in a robust manner, say if they're - # blessed. - return re::is_regexp($regex) if defined &re::is_regexp; - return ref $regex eq 'Regexp'; -} +L<Test::Simple> and L<Test::More> have proven to be popular testing modules, +but they're not always flexible enough. Test::Builder provides a +building block upon which to write your own test libraries I<which can +work together>. -sub _regex_ok { - my( $self, $thing, $regex, $cmp, $name ) = @_; +=head1 TEST COMPONENT MAP - my $ok = 0; - my $usable_regex = $self->maybe_regex($regex); - unless( defined $usable_regex ) { - local $Level = $Level + 1; - $ok = $self->ok( 0, $name ); - $self->diag(" '$regex' doesn't look much like a regex to me."); - return $ok; - } + [Test Script] > [Test Tool] > [Test::Builder] > [Test::Bulder::Stream] > [Result Formatter] + ^ + You are here - { - my $test; - my $context = $self->_caller_context; +A test script uses a test tool such as L<Test::More>, which uses Test::Builder +to produce results. The results are sent to L<Test::Builder::Stream> which then +forwards them on to one or more formatters. The default formatter is +L<Test::Builder::Fromatter::TAP> which produces TAP output. - { - ## no critic (BuiltinFunctions::ProhibitStringyEval) +=head1 METHODS - local( $@, $!, $SIG{__DIE__} ); # isolate eval +=head2 CONSTRUCTION - # No point in issuing an uninit warning, they'll see it in the diagnostics - no warnings 'uninitialized'; +=over 4 - $test = eval $context . q{$test = $thing =~ /$usable_regex/ ? 1 : 0}; - } +=item $Test = Test::Builder->create(%params) - $test = !$test if $cmp eq '!~'; +Create a completely independant Test::Builder object. - local $Level = $Level + 1; - $ok = $self->ok( $test, $name ); - } + my $Test = Test::Builder->create; - unless($ok) { - $thing = defined $thing ? "'$thing'" : 'undef'; - my $match = $cmp eq '=~' ? "doesn't match" : "matches"; +Create a Test::Builder object that sends results to the shared output stream +(usually what you want). - local $Level = $Level + 1; - $self->diag( sprintf <<'DIAGNOSTIC', $thing, $match, $regex ); - %s - %13s '%s' -DIAGNOSTIC + my $Test = Test::Builder->create(shared_stream => 1); - } +Create a Test::Builder object that does not include any legacy cruft. - return $ok; -} + my $Test = Test::Builder->create(modern => 1); -# I'm not ready to publish this. It doesn't deal with array return -# values from the code or context. +=item $Test = Test::Builder->new B<***DEPRECATED***> -=begin private + my $Test = Test::Builder->new; -=item B<_try> +B<This usage is DEPRECATED!> - my $return_from_code = $Test->try(sub { code }); - my($return_from_code, $error) = $Test->try(sub { code }); +Returns the Test::Builder singleton object representing the current state of +the test. -Works like eval BLOCK except it ensures it has no effect on the rest -of the test (ie. C<$@> is not set) nor is effected by outside -interference (ie. C<$SIG{__DIE__}>) and works around some quirks in older -Perls. +Since you only run one test per program C<new> always returns the same +Test::Builder object. No matter how many times you call C<new()>, you're +getting the same object. This is called a singleton. This is done so that +multiple modules share such global information as the test counter and +where test output is going. B<No longer necessary> -C<$error> is what would normally be in C<$@>. +If you want a completely new Test::Builder object different from the +singleton, use C<create>. -It is suggested you use this in place of eval BLOCK. +=back -=cut +=head2 SIMPLE ACCESSORS AND SHORTCUTS -sub _try { - my( $self, $code, %opts ) = @_; +=head3 READ/WRITE ATTRIBUTES - my $error; - my $return; - { - local $!; # eval can mess up $! - local $@; # don't set $@ in the test - local $SIG{__DIE__}; # don't trip an outside DIE handler. - $return = eval { $code->() }; - $error = $@; - } +=over 4 - die $error if $error and $opts{die_on_fail}; +=item $parent = $Test->parent - return wantarray ? ( $return, $error ) : $return; -} +Returns the parent C<Test::Builder> instance, if any. Only used with child +builders for nested TAP. -=end private +=item $Test->name +Defaults to $0, but subtests and child tests will set this. -=item B<is_fh> +=item $Test->modern - my $is_fh = $Test->is_fh($thing); +Defaults to $ENV{TB_MODERN}, or 0. True when the builder object was constructed +with modern practices instead of deprecated ones. -Determines if the given C<$thing> can be used as a filehandle. +=item $Test->depth -=cut +Get/Set the depth. This is usually set for Child tests. -sub is_fh { - my $self = shift; - my $maybe_fh = shift; - return 0 unless defined $maybe_fh; +=item $Test->default_name - return 1 if ref $maybe_fh eq 'GLOB'; # its a glob ref - return 1 if ref \$maybe_fh eq 'GLOB'; # its a glob - - return eval { $maybe_fh->isa("IO::Handle") } || - eval { tied($maybe_fh)->can('TIEHANDLE') }; -} +Get/Set the default name for tests where no name was provided. Typically this +should be set to undef, there are very few real-world use cases for this. +B<Note:> This functionality was added specifically for L<Test::Exception>, +which has one of the few real-world use cases. =back +=head3 DELEGATES TO STREAM -=head2 Test style +Each of these is a shortcut to C<< $Test->stream->NAME >> +See the L<Test::Builder::Stream> documentation for details. =over 4 -=item B<level> +=item $Test->is_passing(...) - $Test->level($how_high); +=item $Test->listen(...) -How far up the call stack should C<$Test> look when reporting where the -test failed. +=item $Test->munge(...) -Defaults to 1. +=item $Test->tap -Setting L<$Test::Builder::Level> overrides. This is typically useful -localized: +=item $Test->lresults - sub my_ok { - my $test = shift; +=item $Test->use_fork - local $Test::Builder::Level = $Test::Builder::Level + 1; - $TB->ok($test); - } +=item $Test->no_fork -To be polite to other functions wrapping your own you usually want to increment C<$Level> rather than set it to a constant. +=back -=cut +=head2 CHILDREN AND SUBTESTS -sub level { - my( $self, $level ) = @_; +=over 4 - if( defined $level ) { - $Level = $level; - } - return $Level; -} +=item $Test->subtest($name, \&subtests, @args) -=item B<use_numbers> +See documentation of C<subtest> in Test::More. - $Test->use_numbers($on_or_off); +C<subtest> also, and optionally, accepts arguments which will be passed to the +subtests reference. -Whether or not the test should output numbers. That is, this if true: +=item $child = $Test->child($name) - ok 1 - ok 2 - ok 3 + my $child = $builder->child($name_of_child); + $child->plan( tests => 4 ); + $child->ok(some_code()); + ... + $child->finalize; -or this if false +Returns a new instance of C<Test::Builder>. Any output from this child will +be indented four spaces more than the parent's indentation. When done, the +C<finalize> method I<must> be called explicitly. - ok - ok - ok +Trying to create a new child with a previous child still active (i.e., +C<finalize> not called) will C<croak>. -Most useful when you can't depend on the test output order, such as -when threads or forking is involved. +Trying to run a test when you have an open child will also C<croak> and cause +the test suite to fail. -Defaults to on. +=item $ok = $Child->finalize -=cut +When your child is done running tests, you must call C<finalize> to clean up +and tell the parent your pass/fail status. -sub use_numbers { - my( $self, $use_nums ) = @_; +Calling C<finalize> on a child with open children will C<croak>. - if( defined $use_nums ) { - $self->{Use_Nums} = $use_nums; - } - return $self->{Use_Nums}; -} +If the child falls out of scope before C<finalize> is called, a failure +diagnostic will be issued and the child is considered to have failed. -=item B<no_diag> +No attempt to call methods on a child after C<finalize> is called is +guaranteed to succeed. - $Test->no_diag($no_diag); +Calling this on the root builder is a no-op. -If set true no diagnostics will be printed. This includes calls to -C<diag()>. +=back -=item B<no_ending> +=head2 STREAM MANAGEMENT - $Test->no_ending($no_ending); +=over 4 -Normally, Test::Builder does some extra diagnostics when the test -ends. It also changes the exit code as described below. +=item $stream = $Test->stream -If this is true, none of that will be done. +=item $Test->stream($stream) -=item B<no_header> +=item $Test->stream(undef) - $Test->no_header($no_header); +Get/Set the stream. When no stream is set, or is undef it will return the +shared stream. -If set to true, no "1..N" header will be printed. +B<Note:> Do not set this to the shared stream yourself, set it to undef. This +is because the shared stream is actually a stack, and this always returns the +top of the stack. -=cut +=item $results = $Test->intercept(\&code) -foreach my $attribute (qw(No_Header No_Ending No_Diag)) { - my $method = lc $attribute; +Any tests run inside the codeblock will be intercepted and not sent to the +normal stream. Instead they will be added to C<$results> which is an array of +L<Test::Builder::Result> objects. - my $code = sub { - my( $self, $no ) = @_; +B<Note:> This will also intercept BAIL_OUT and skipall. - if( defined $no ) { - $self->{$attribute} = $no; - } - return $self->{$attribute}; - }; +B<Note:> This will only intercept results generated with the Test::Builder +object on which C<intercept()> was called. Other builders will still send to +the normal places. - no strict 'refs'; ## no critic - *{ __PACKAGE__ . '::' . $method } = $code; -} +See L<Test::Tester2> for a method of capturing results sent to the global +stream. =back -=head2 Output +=head2 TRACING THE TEST/PROVIDER BOUNDRY -Controlling where the test output goes. +When a test fails it will report the filename and line where the failure +occured. In order to do this it needs to look at the stack and figure out where +your tests stop, and the tools you are using begin. These methods help you find +the desired caller frame. -It's ok for your test to change where STDOUT and STDERR point to, -Test::Builder's default output settings will not be affected. +See the L<Test::Builder::Trace> module for more details. =over 4 -=item B<diag> +=item $trace = $Test->trace_test() - $Test->diag(@msgs); +Returns an L<Test::Builder::Trace> object. -Prints out the given C<@msgs>. Like C<print>, arguments are simply -appended together. +=item $reason = $Test->find_TODO -Normally, it uses the C<failure_output()> handle, but if this is for a -TODO test, the C<todo_output()> handle is used. +=item $reason = $Test->find_TODO($pack) -Output will be indented and marked with a # so as not to interfere -with test output. A newline will be put on the end if there isn't one -already. +=item $old_reason = $Test->find_TODO($pack, 1, $new_reason); -We encourage using this rather than calling print directly. +Like C<todo()> but only returns the value of C<$TODO> ignoring +C<todo_start()>. -Returns false. Why? Because C<diag()> is often used in conjunction with -a failing test (C<ok() || diag()>) it "passes through" the failure. +Can also be used to set C<$TODO> to a new value while returning the +old value. - return ok(...) || diag(...); +=back -=for blame transfer -Mark Fowler <mark@twoshortplanks.com> +=head2 TEST PLAN -=cut +=over 4 -sub diag { - my $self = shift; +=item $Test->plan('no_plan'); - $self->_print_comment( $self->_diag_fh, @_ ); -} +=item $Test->plan( skip_all => $reason ); -=item B<note> +=item $Test->plan( tests => $num_tests ); - $Test->note(@msgs); +A convenient way to set up your tests. Call this and Test::Builder +will print the appropriate headers and take the appropriate actions. -Like C<diag()>, but it prints to the C<output()> handle so it will not -normally be seen by the user except in verbose mode. +If you call C<plan()>, don't call any of the other methods below. -=cut +If a child calls "skip_all" in the plan, a C<Test::Builder::Exception> is +thrown. Trap this error, call C<finalize()> and don't run any more tests on +the child. -sub note { - my $self = shift; + my $child = $Test->child('some child'); + eval { $child->plan( $condition ? ( skip_all => $reason ) : ( tests => 3 ) ) }; + if ( eval { $@->isa('Test::Builder::Exception') } ) { + $child->finalize; + return; + } + # run your tests - $self->_print_comment( $self->output, @_ ); -} +=item $Test->no_plan; -sub _diag_fh { - my $self = shift; +Declares that this test will run an indeterminate number of tests. - local $Level = $Level + 1; - return $self->in_todo ? $self->todo_output : $self->failure_output; -} +=item $Test->skip_all -sub _print_comment { - my( $self, $fh, @msgs ) = @_; +=item $Test->skip_all($reason) - return if $self->no_diag; - return unless @msgs; +Skips all the tests, using the given C<$reason>. Exits immediately with 0. - # Prevent printing headers when compiling (i.e. -c) - return if $^C; +=item $Test->done_testing - # Smash args together like print does. - # Convert undef to 'undef' so its readable. - my $msg = join '', map { defined($_) ? $_ : 'undef' } @msgs; +=item $Test->done_testing($count) - # Escape the beginning, _print will take care of the rest. - $msg =~ s/^/# /; +Declares that you are done testing, no more tests will be run after this point. - local $Level = $Level + 1; - $self->_print_to_fh( $fh, $msg ); +If a plan has not yet been output, it will do so. - return 0; -} +$num_tests is the number of tests you planned to run. If a numbered +plan was already declared, and if this contradicts, a failing result +will be run to reflect the planning mistake. If C<no_plan> was declared, +this will override. -=item B<explain> +If C<done_testing()> is called twice, the second call will issue a +failing result. - my @dump = $Test->explain(@msgs); +If C<$num_tests> is omitted, the number of tests run will be used, like +no_plan. -Will dump the contents of any references in a human readable format. -Handy for things like... +C<done_testing()> is, in effect, used when you'd want to use C<no_plan>, but +safer. You'd use it like so: - is_deeply($have, $want) || diag explain $have; + $Test->ok($a == $b); + $Test->done_testing(); -or +Or to plan a variable number of tests: - is_deeply($have, $want) || note explain $have; + for my $test (@tests) { + $Test->ok($test); + } + $Test->done_testing(scalar @tests); -=cut +=back -sub explain { - my $self = shift; +=head2 SIMPLE RESULT PRODUCERS - return map { - ref $_ - ? do { - $self->_try(sub { require Data::Dumper }, die_on_fail => 1); +Each of these produces 1 or more L<Test::Builder::Result> objects which are fed +into the result stream. - my $dumper = Data::Dumper->new( [$_] ); - $dumper->Indent(1)->Terse(1); - $dumper->Sortkeys(1) if $dumper->can("Sortkeys"); - $dumper->Dump; - } - : $_ - } @_; -} +=over 4 -=begin _private +=item $Test->ok($test) -=item B<_print> +=item $Test->ok($test, $name) - $Test->_print(@msgs); +=item $Test->ok($test, $name, @diag) -Prints to the C<output()> filehandle. +Your basic test. Pass if C<$test> is true, fail if $test is false. Just +like L<Test::Simple>'s C<ok()>. -=end _private +You may also specify diagnostics messages in the form of simple strings, or +complete <Test::Builder::Result> objects. Typically you would only do this in a +failure, but you are allowed to add diags to passes as well. -=cut +=item $Test->BAIL_OUT($reason); -sub _print { - my $self = shift; - return $self->_print_to_fh( $self->output, @_ ); -} +Indicates to the L<Test::Harness> that things are going so badly all +testing should terminate. This includes running any additional test +scripts. -sub _print_to_fh { - my( $self, $fh, @msgs ) = @_; +It will exit with 255. - # Prevent printing headers when only compiling. Mostly for when - # tests are deparsed with B::Deparse - return if $^C; +=item $Test->skip - my $msg = join '', @msgs; - my $indent = $self->_indent; +=item $Test->skip($why) - local( $\, $", $, ) = ( undef, ' ', '' ); +Skips the current test, reporting C<$why>. - # Escape each line after the first with a # so we don't - # confuse Test::Harness. - $msg =~ s{\n(?!\z)}{\n$indent# }sg; +=item $Test->todo_skip - # Stick a newline on the end if it needs it. - $msg .= "\n" unless $msg =~ /\n\z/; +=item $Test->todo_skip($why) - return print $fh $indent, $msg; -} +Like C<skip()>, only it will declare the test as failing and TODO. Similar +to -=item B<output> + print "not ok $tnum # TODO $why\n"; -=item B<failure_output> +=item $Test->diag(@msgs) -=item B<todo_output> +Prints out the given C<@msgs>. Like C<print>, arguments are simply +appended together. - my $filehandle = $Test->output; - $Test->output($filehandle); - $Test->output($filename); - $Test->output(\$scalar); +Normally, it uses the C<failure_output()> handle, but if this is for a +TODO test, the C<todo_output()> handle is used. -These methods control where Test::Builder will print its output. -They take either an open C<$filehandle>, a C<$filename> to open and write to -or a C<$scalar> reference to append to. It will always return a C<$filehandle>. +Output will be indented and marked with a # so as not to interfere +with test output. A newline will be put on the end if there isn't one +already. -B<output> is where normal "ok/not ok" test output goes. +We encourage using this rather than calling print directly. -Defaults to STDOUT. +Returns false. Why? Because C<diag()> is often used in conjunction with +a failing test (C<ok() || diag()>) it "passes through" the failure. -B<failure_output> is where diagnostic output on test failures and -C<diag()> goes. It is normally not read by Test::Harness and instead is -displayed to the user. + return ok(...) || diag(...); -Defaults to STDERR. +=item $Test->note(@msgs) -C<todo_output> is used instead of C<failure_output()> for the -diagnostics of a failing TODO test. These will not be seen by the -user. +Like C<diag()>, but it prints to the C<output()> handle so it will not +normally be seen by the user except in verbose mode. -Defaults to STDOUT. +=back -=cut +=head2 ADVANCED RESULT PRODUCERS -sub output { - my( $self, $fh ) = @_; +=over 4 - if( defined $fh ) { - $self->{Out_FH} = $self->_new_fh($fh); - } - return $self->{Out_FH}; -} +=item $Test->is_eq($got, $expected, $name) -sub failure_output { - my( $self, $fh ) = @_; +Like Test::More's C<is()>. Checks if C<$got eq $expected>. This is the +string version. - if( defined $fh ) { - $self->{Fail_FH} = $self->_new_fh($fh); - } - return $self->{Fail_FH}; -} +C<undef> only ever matches another C<undef>. -sub todo_output { - my( $self, $fh ) = @_; +=item $Test->is_num($got, $expected, $name) - if( defined $fh ) { - $self->{Todo_FH} = $self->_new_fh($fh); - } - return $self->{Todo_FH}; -} +Like Test::More's C<is()>. Checks if C<$got == $expected>. This is the +numeric version. -sub _new_fh { - my $self = shift; - my($file_or_fh) = shift; +C<undef> only ever matches another C<undef>. - my $fh; - if( $self->is_fh($file_or_fh) ) { - $fh = $file_or_fh; - } - elsif( ref $file_or_fh eq 'SCALAR' ) { - # Scalar refs as filehandles was added in 5.8. - if( $] >= 5.008 ) { - open $fh, ">>", $file_or_fh - or $self->croak("Can't open scalar ref $file_or_fh: $!"); - } - # Emulate scalar ref filehandles with a tie. - else { - $fh = Test::Builder::IO::Scalar->new($file_or_fh) - or $self->croak("Can't tie scalar ref $file_or_fh"); - } - } - else { - open $fh, ">", $file_or_fh - or $self->croak("Can't open test output log $file_or_fh: $!"); - _autoflush($fh); - } +=item $Test->isnt_eq($got, $dont_expect, $name) - return $fh; -} +Like L<Test::More>'s C<isnt()>. Checks if C<$got ne $dont_expect>. This is +the string version. -sub _autoflush { - my($fh) = shift; - my $old_fh = select $fh; - $| = 1; - select $old_fh; +=item $Test->isnt_num($got, $dont_expect, $name) - return; -} +Like L<Test::More>'s C<isnt()>. Checks if C<$got ne $dont_expect>. This is +the numeric version. -my( $Testout, $Testerr ); +=item $Test->like($thing, qr/$regex/, $name) -sub _dup_stdhandles { - my $self = shift; +=item $Test->like($thing, '/$regex/', $name) - $self->_open_testhandles; +Like L<Test::More>'s C<like()>. Checks if $thing matches the given C<$regex>. - # 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 ); +=item $Test->unlike($thing, qr/$regex/, $name) - $self->reset_outputs; +=item $Test->unlike($thing, '/$regex/', $name) - return; -} +Like L<Test::More>'s C<unlike()>. Checks if $thing $Test->does not match the +given C<$regex>. -sub _open_testhandles { - my $self = shift; +=item $Test->cmp_ok($thing, $type, $that, $name) - return if $self->{Opened_Testhandles}; +Works just like L<Test::More>'s C<cmp_ok()>. - # 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: $!"; + $Test->cmp_ok($big_num, '!=', $other_big_num); - $self->_copy_io_layers( \*STDOUT, $Testout ); - $self->_copy_io_layers( \*STDERR, $Testerr ); +=back - $self->{Opened_Testhandles} = 1; +=head2 PUBLIC HELPERS - return; -} +=over 4 -sub _copy_io_layers { - my( $self, $src, $dst ) = @_; +=item @dump = $Test->explain(@msgs) - $self->_try( - sub { - require PerlIO; - my @src_layers = PerlIO::get_layers($src); +Will dump the contents of any references in a human readable format. +Handy for things like... - _apply_layers($dst, @src_layers) if @src_layers; - } - ); + is_deeply($have, $want) || diag explain $have; - return; -} +or -sub _apply_layers { - my ($fh, @layers) = @_; - my %seen; - my @unique = grep { $_ ne 'unix' and !$seen{$_}++ } @layers; - binmode($fh, join(":", "", "raw", @unique)); -} + is_deeply($have, $want) || note explain $have; +=item $tb->carp(@message) -=item reset_outputs +Warns with C<@message> but the message will appear to come from the +point where the original test function was called (C<< $tb->caller >>). - $tb->reset_outputs; +=item $tb->croak(@message) -Resets all the output filehandles back to their defaults. +Dies with C<@message> but the message will appear to come from the +point where the original test function was called (C<< $tb->caller >>). -=cut +=item $plan = $Test->has_plan -sub reset_outputs { - my $self = shift; +Find out whether a plan has been defined. C<$plan> is either C<undef> (no plan +has been set), C<no_plan> (indeterminate # of tests) or an integer (the number +of expected tests). - $self->output ($Testout); - $self->failure_output($Testerr); - $self->todo_output ($Testout); +=item $Test->reset - return; -} +Reinitializes the Test::Builder singleton to its original state. +Mostly useful for tests run in persistent environments where the same +test might be run multiple times in the same process. -=item carp +=item %context = $Test->context - $tb->carp(@message); +Returns a hash of contextual info. -Warns with C<@message> but the message will appear to come from the -point where the original test function was called (C<< $tb->caller >>). + ( + depth => DEPTH, + source => NAME, + trace => TRACE, + ) -=item croak +=back - $tb->croak(@message); +=head2 TODO MANAGEMENT -Dies with C<@message> but the message will appear to come from the -point where the original test function was called (C<< $tb->caller >>). +=over 4 -=cut +=item $todo_reason = $Test->todo -sub _message_at_caller { - my $self = shift; +=item $todo_reason = $Test->todo($pack) - local $Level = $Level + 1; - my( $pack, $file, $line ) = $self->caller; - return join( "", @_ ) . " at $file line $line.\n"; -} +If the current tests are considered "TODO" it will return the reason, +if any. This reason can come from a C<$TODO> variable or the last call +to C<todo_start()>. -sub carp { - my $self = shift; - return warn $self->_message_at_caller(@_); -} +Since a TODO test does not need a reason, this function can return an +empty string even when inside a TODO block. Use C<< $Test->in_todo >> +to determine if you are currently inside a TODO block. -sub croak { - my $self = shift; - return die $self->_message_at_caller(@_); -} +C<todo()> is about finding the right package to look for C<$TODO> in. It's +pretty good at guessing the right package to look at. It considers the stack +trace, C<$Level>, and metadata associated with various packages. +Sometimes there is some confusion about where C<todo()> should be looking +for the C<$TODO> variable. If you want to be sure, tell it explicitly +what $pack to use. -=back +=item $in_todo = $Test->in_todo +Returns true if the test is currently inside a TODO block. -=head2 Test Status and Info +=item $Test->todo_start() -=over 4 +=item $Test->todo_start($message) -=item B<current_test> +This method allows you declare all subsequent tests as TODO tests, up until +the C<todo_end> method has been called. - my $curr_test = $Test->current_test; - $Test->current_test($num); +The C<TODO:> and C<$TODO> syntax is generally pretty good about figuring out +whether or not we're in a TODO test. However, often we find that this is not +possible to determine (such as when we want to use C<$TODO> but +the tests are being executed in other packages which can't be inferred +beforehand). -Gets/sets the current test number we're on. You usually shouldn't -have to set this. +Note that you can use this to nest "todo" tests -If set forward, the details of the missing tests are filled in as 'unknown'. -if set backward, the details of the intervening tests are deleted. You -can erase history if you really want to. + $Test->todo_start('working on this'); + # lots of code + $Test->todo_start('working on that'); + # more code + $Test->todo_end; + $Test->todo_end; -=cut +This is generally not recommended, but large testing systems often have weird +internal needs. -sub current_test { - my( $self, $num ) = @_; - - lock( $self->{Curr_Test} ); - if( defined $num ) { - $self->{Curr_Test} = $num; - - # If the test counter is being pushed forward fill in the details. - my $test_results = $self->{Test_Results}; - if( $num > @$test_results ) { - my $start = @$test_results ? @$test_results : 0; - for( $start .. $num - 1 ) { - $test_results->[$_] = &share( - { - 'ok' => 1, - actual_ok => undef, - reason => 'incrementing test number', - type => 'unknown', - name => undef - } - ); - } - } - # If backward, wipe history. Its their funeral. - elsif( $num < @$test_results ) { - $#{$test_results} = $num - 1; - } - } - return $self->{Curr_Test}; -} +We've tried to make this also work with the TODO: syntax, but it's not +guaranteed and its use is also discouraged: + + TODO: { + local $TODO = 'We have work to do!'; + $Test->todo_start('working on this'); + # lots of code + $Test->todo_start('working on that'); + # more code + $Test->todo_end; + $Test->todo_end; + } -=item B<is_passing> +Pick one style or another of "TODO" to be on the safe side. + +=item $Test->todo_end - my $ok = $builder->is_passing; +Stops running tests as "TODO" tests. This method is fatal if called without a +preceding C<todo_start> method call. -Indicates if the test suite is currently passing. +=back -More formally, it will be false if anything has happened which makes -it impossible for the test suite to pass. True otherwise. +=head2 DEPRECATED/LEGACY -For example, if no tests have run C<is_passing()> will be true because -even though a suite with no tests is a failure you can add a passing -test to it and start passing. +All of these will issue warnings if called on a modern Test::Builder object. +That is any Test::Builder instance that was created with the 'modern' flag. -Don't think about it too much. +=over -=cut +=item $self->no_ending -sub is_passing { - my $self = shift; +B<Deprecated:> Moved to the L<Test::Builder::Stream> object. - if( @_ ) { - $self->{Is_Passing} = shift; - } + $Test->no_ending($no_ending); - return $self->{Is_Passing}; -} +Normally, Test::Builder does some extra diagnostics when the test +ends. It also changes the exit code as described below. + +If this is true, none of that will be done. + +=item $self->summary +B<Deprecated:> Moved to the L<Test::Builder::Stream> object. -=item B<summary> +The style of result recording used here is deprecated. The functionality was +moved to its own object to contain the legacy code. my @tests = $Test->summary; @@ -2121,21 +2039,18 @@ This is a logical pass/fail, so todos are passes. Of course, test #1 is $tests[0], etc... -=cut - -sub summary { - my($self) = shift; +=item $self->details - return map { $_->{'ok'} } @{ $self->{Test_Results} }; -} +B<Deprecated:> Moved to the L<Test::Builder::Formatter::LegacyResults> object. -=item B<details> +The style of result recording used here is deprecated. The functionality was +moved to its own object to contain the legacy code. my @tests = $Test->details; Like C<summary()>, but with a lot more detail. - $tests[$test_num - 1] = + $tests[$test_num - 1] = { 'ok' => is the test considered a pass? actual_ok => did it literally say 'ok'? name => name of the test (if any) @@ -2176,180 +2091,133 @@ result in this structure: reason => 'insufficient donuts' }; -=cut - -sub details { - my $self = shift; - return @{ $self->{Test_Results} }; -} +=item $self->no_header -=item B<todo> +B<Deprecated:> moved to the L<Test::Builder::Formatter::TAP> object. - my $todo_reason = $Test->todo; - my $todo_reason = $Test->todo($pack); + $Test->no_header($no_header); -If the current tests are considered "TODO" it will return the reason, -if any. This reason can come from a C<$TODO> variable or the last call -to C<todo_start()>. +If set to true, no "1..N" header will be printed. -Since a TODO test does not need a reason, this function can return an -empty string even when inside a TODO block. Use C<< $Test->in_todo >> -to determine if you are currently inside a TODO block. +=item $self->no_diag -C<todo()> is about finding the right package to look for C<$TODO> in. It's -pretty good at guessing the right package to look at. It first looks for -the caller based on C<$Level + 1>, since C<todo()> is usually called inside -a test function. As a last resort it will use C<exported_to()>. +B<Deprecated:> moved to the L<Test::Builder::Formatter::TAP> object. -Sometimes there is some confusion about where todo() should be looking -for the C<$TODO> variable. If you want to be sure, tell it explicitly -what $pack to use. +If set true no diagnostics will be printed. This includes calls to +C<diag()>. -=cut +=item $self->output -sub todo { - my( $self, $pack ) = @_; +=item $self->failure_output - return $self->{Todo} if defined $self->{Todo}; +=item $self->todo_output - local $Level = $Level + 1; - my $todo = $self->find_TODO($pack); - return $todo if defined $todo; +B<Deprecated:> moved to the L<Test::Builder::Formatter::TAP> object. - return ''; -} + my $filehandle = $Test->output; + $Test->output($filehandle); + $Test->output($filename); + $Test->output(\$scalar); -=item B<find_TODO> +These methods control where Test::Builder will print its output. +They take either an open C<$filehandle>, a C<$filename> to open and write to +or a C<$scalar> reference to append to. It will always return a C<$filehandle>. - my $todo_reason = $Test->find_TODO(); - my $todo_reason = $Test->find_TODO($pack); +B<output> is where normal "ok/not ok" test output goes. -Like C<todo()> but only returns the value of C<$TODO> ignoring -C<todo_start()>. +Defaults to STDOUT. -Can also be used to set C<$TODO> to a new value while returning the -old value: +B<failure_output> is where diagnostic output on test failures and +C<diag()> goes. It is normally not read by Test::Harness and instead is +displayed to the user. - my $old_reason = $Test->find_TODO($pack, 1, $new_reason); +Defaults to STDERR. -=cut +C<todo_output> is used instead of C<failure_output()> for the +diagnostics of a failing TODO test. These will not be seen by the +user. -sub find_TODO { - my( $self, $pack, $set, $new_value ) = @_; +Defaults to STDOUT. - $pack = $pack || $self->caller(1) || $self->exported_to; - return unless $pack; +=item $self->reset_outputs - no strict 'refs'; ## no critic - my $old_value = ${ $pack . '::TODO' }; - $set and ${ $pack . '::TODO' } = $new_value; - return $old_value; -} +B<Deprecated:> moved to the L<Test::Builder::Formatter::TAP> object. -=item B<in_todo> + $tb->reset_outputs; - my $in_todo = $Test->in_todo; +Resets all the output filehandles back to their defaults. -Returns true if the test is currently inside a TODO block. +=item $self->use_numbers -=cut +B<Deprecated:> moved to the L<Test::Builder::Formatter::TAP> object. -sub in_todo { - my $self = shift; + $Test->use_numbers($on_or_off); - local $Level = $Level + 1; - return( defined $self->{Todo} || $self->find_TODO ) ? 1 : 0; -} +Whether or not the test should output numbers. That is, this if true: -=item B<todo_start> + ok 1 + ok 2 + ok 3 - $Test->todo_start(); - $Test->todo_start($message); +or this if false -This method allows you declare all subsequent tests as TODO tests, up until -the C<todo_end> method has been called. + ok + ok + ok -The C<TODO:> and C<$TODO> syntax is generally pretty good about figuring out -whether or not we're in a TODO test. However, often we find that this is not -possible to determine (such as when we want to use C<$TODO> but -the tests are being executed in other packages which can't be inferred -beforehand). +Most useful when you can't depend on the test output order, such as +when threads or forking is involved. -Note that you can use this to nest "todo" tests +Defaults to on. - $Test->todo_start('working on this'); - # lots of code - $Test->todo_start('working on that'); - # more code - $Test->todo_end; - $Test->todo_end; +=item $pack = $Test->exported_to -This is generally not recommended, but large testing systems often have weird -internal needs. +=item $Test->exported_to($pack) -We've tried to make this also work with the TODO: syntax, but it's not -guaranteed and its use is also discouraged: +B<Deprecated:> Use C<< Test::Builder::Trace->anoint($package) >> and +C<< $Test->trace_anointed >> instead. - TODO: { - local $TODO = 'We have work to do!'; - $Test->todo_start('working on this'); - # lots of code - $Test->todo_start('working on that'); - # more code - $Test->todo_end; - $Test->todo_end; - } +Tells Test::Builder what package you exported your functions to. -Pick one style or another of "TODO" to be on the safe side. +This method isn't terribly useful since modules which share the same +Test::Builder object might get exported to different packages and only +the last one will be honored. -=cut +=item $is_fh = $Test->is_fh($thing); -sub todo_start { - my $self = shift; - my $message = @_ ? shift : ''; +Determines if the given C<$thing> can be used as a filehandle. - $self->{Start_Todo}++; - if( $self->in_todo ) { - push @{ $self->{Todo_Stack} } => $self->todo; - } - $self->{Todo} = $message; +=item $curr_test = $Test->current_test; - return; -} +=item $Test->current_test($num); -=item C<todo_end> +Gets/sets the current test number we're on. You usually shouldn't +have to set this. - $Test->todo_end; +If set forward, the details of the missing tests are filled in as 'unknown'. +if set backward, the details of the intervening tests are deleted. You +can erase history if you really want to. -Stops running tests as "TODO" tests. This method is fatal if called without a -preceding C<todo_start> method call. +=item $Test->BAIL_OUT($reason); -=cut +Indicates to the L<Test::Harness> that things are going so badly all +testing should terminate. This includes running any additional test +scripts. -sub todo_end { - my $self = shift; +It will exit with 255. - if( !$self->{Start_Todo} ) { - $self->croak('todo_end() called without todo_start()'); - } +=item $max = $Test->expected_tests - $self->{Start_Todo}--; +=item $Test->expected_tests($max) - if( $self->{Start_Todo} && @{ $self->{Todo_Stack} } ) { - $self->{Todo} = pop @{ $self->{Todo_Stack} }; - } - else { - delete $self->{Todo}; - } +Gets/sets the number of tests we expect this test to run and prints out +the appropriate headers. - return; -} +=item $package = $Test->caller -=item B<caller> +=item ($pack, $file, $line) = $Test->caller - my $package = $Test->caller; - my($pack, $file, $line) = $Test->caller; - my($pack, $file, $line) = $Test->caller($height); +=item ($pack, $file, $line) = $Test->caller($height) Like the normal C<caller()>, except it reports according to your C<level()>. @@ -2357,232 +2225,103 @@ C<$height> will be added to the C<level()>. If C<caller()> winds up off the top of the stack it report the highest context. -=cut - -sub caller { ## no critic (Subroutines::ProhibitBuiltinHomonyms) - my( $self, $height ) = @_; - $height ||= 0; - - my $level = $self->level + $height + 1; - my @caller; - do { - @caller = CORE::caller( $level ); - $level--; - } until @caller; - return wantarray ? @caller : $caller[0]; -} - -=back - -=cut - -=begin _private - -=over 4 - -=item B<_sanity_check> +=item $Test->level($how_high) - $self->_sanity_check(); +B<DEPRECATED> See deprecation notes at the top. The use of C<level()> is +deprecated. -Runs a bunch of end of test sanity checks to make sure reality came -through ok. If anything is wrong it will die with a fairly friendly -error message. - -=cut - -#'# -sub _sanity_check { - my $self = shift; - - $self->_whoa( $self->{Curr_Test} < 0, 'Says here you ran a negative number of tests!' ); - $self->_whoa( $self->{Curr_Test} != @{ $self->{Test_Results} }, - 'Somehow you got a different number of results than tests ran!' ); - - return; -} - -=item B<_whoa> +How far up the call stack should C<$Test> look when reporting where the +test failed. - $self->_whoa($check, $description); +Defaults to 1. -A sanity check, similar to C<assert()>. If the C<$check> is true, something -has gone horribly wrong. It will die with the given C<$description> and -a note to contact the author. +Setting L<$Test::Builder::Level> overrides. This is typically useful +localized: -=cut + sub my_ok { + my $test = shift; -sub _whoa { - my( $self, $check, $desc ) = @_; - if($check) { - local $Level = $Level + 1; - $self->croak(<<"WHOA"); -WHOA! $desc -This should never happen! Please contact the author immediately! -WHOA + local $Test::Builder::Level = $Test::Builder::Level + 1; + $TB->ok($test); } - return; -} - -=item B<_my_exit> - - _my_exit($exit_num); +To be polite to other functions wrapping your own you usually want to increment +C<$Level> rather than set it to a constant. -Perl seems to have some trouble with exiting inside an C<END> block. -5.6.1 does some odd things. Instead, this function edits C<$?> -directly. It should B<only> be called from inside an C<END> block. -It doesn't actually exit, that's your job. +=item $Test->maybe_regex(qr/$regex/) -=cut +=item $Test->maybe_regex('/$regex/') -sub _my_exit { - $? = $_[0]; ## no critic (Variables::RequireLocalizedPunctuationVars) - - return 1; -} +This method used to be useful back when Test::Builder worked on Perls +before 5.6 which didn't have qr//. Now its pretty useless. -=back +Convenience method for building testing functions that take regular +expressions as arguments. -=end _private +Takes a quoted regular expression produced by C<qr//>, or a string +representing a regular expression. -=cut +Returns a Perl value which may be used instead of the corresponding +regular expression, or C<undef> if its argument is not recognised. -sub _ending { - my $self = shift; - return if $self->no_ending; - return if $self->{Ending}++; +For example, a version of C<like()>, sans the useful diagnostic messages, +could be written as: - my $real_exit_code = $?; + sub laconic_like { + my ($self, $thing, $regex, $name) = @_; + my $usable_regex = $self->maybe_regex($regex); + die "expecting regex, found '$regex'\n" + unless $usable_regex; + $self->ok($thing =~ m/$usable_regex/, $name); + } - # Don't bother with an ending if this is a forked copy. Only the parent - # should do the ending. - if( $self->{Original_Pid} != $$ ) { - return; - } +=back - # Ran tests but never declared a plan or hit done_testing - if( !$self->{Have_Plan} and $self->{Curr_Test} ) { - $self->is_passing(0); - $self->diag("Tests were run but no plan was declared and done_testing() was not seen."); - - if($real_exit_code) { - $self->diag(<<"FAIL"); -Looks like your test exited with $real_exit_code just after $self->{Curr_Test}. -FAIL - $self->is_passing(0); - _my_exit($real_exit_code) && return; - } +=head1 PACKAGE VARIABLES - # But if the tests ran, handle exit code. - my $test_results = $self->{Test_Results}; - if(@$test_results) { - my $num_failed = grep !$_->{'ok'}, @{$test_results}[ 0 .. $self->{Curr_Test} - 1 ]; - if ($num_failed > 0) { +B<NOTE>: These are tied to the package, not the instance. Basically that means +touching these can affect more things than you expect. Using these can lead to +unexpected interactions at a distance. - my $exit_code = $num_failed <= 254 ? $num_failed : 254; - _my_exit($exit_code) && return; - } - } - _my_exit(254) && return; - } +=over 4 - # Exit if plan() was never called. This is so "require Test::Simple" - # doesn't puke. - if( !$self->{Have_Plan} ) { - return; - } +=item C<$Level> - # Don't do an ending if we bailed out. - if( $self->{Bailed_Out} ) { - $self->is_passing(0); - return; - } - # Figure out if we passed or failed and print helpful messages. - my $test_results = $self->{Test_Results}; - if(@$test_results) { - # The plan? We have no plan. - if( $self->{No_Plan} ) { - $self->_output_plan($self->{Curr_Test}) unless $self->no_header; - $self->{Expected_Tests} = $self->{Curr_Test}; - } +Originally this was the only way to tell Test::Builder where in the stack +errors should be reported. Now the preferred method of finding where errors +should be reported is using the L<Test::Builder::Trace> and +L<Test::Builder::Provider> modules. - # Auto-extended arrays and elements which aren't explicitly - # filled in with a shared reference will puke under 5.8.0 - # ithreads. So we have to fill them in by hand. :( - my $empty_result = &share( {} ); - for my $idx ( 0 .. $self->{Expected_Tests} - 1 ) { - $test_results->[$idx] = $empty_result - unless defined $test_results->[$idx]; - } +C<$Level> should be considered deprecated when possible, that said it will not +be removed any time soon. There is too much legacy code that depends on +C<$Level>. There are also a couple situations in which C<$Level> is necessary: - my $num_failed = grep !$_->{'ok'}, @{$test_results}[ 0 .. $self->{Curr_Test} - 1 ]; +=over 4 - my $num_extra = $self->{Curr_Test} - $self->{Expected_Tests}; +=item Backwards compatibility - if( $num_extra != 0 ) { - my $s = $self->{Expected_Tests} == 1 ? '' : 's'; - $self->diag(<<"FAIL"); -Looks like you planned $self->{Expected_Tests} test$s but ran $self->{Curr_Test}. -FAIL - $self->is_passing(0); - } +If code simply cannot depend on a recent version of Test::Builder, then $Level +must be used as there is no alternative. See L<Test::Builder::Compat> for tools +to help make test tools that work in old and new versions. - if($num_failed) { - my $num_tests = $self->{Curr_Test}; - my $s = $num_failed == 1 ? '' : 's'; +=item Stack Management - my $qualifier = $num_extra == 0 ? '' : ' run'; +Using L<Test::Builder::Provider> is not practical for situations like in +L<Test::Exception> where one needs to munge the call stack to hide frames. - $self->diag(<<"FAIL"); -Looks like you failed $num_failed test$s of $num_tests$qualifier. -FAIL - $self->is_passing(0); - } +=back - if($real_exit_code) { - $self->diag(<<"FAIL"); -Looks like your test exited with $real_exit_code just after $self->{Curr_Test}. -FAIL - $self->is_passing(0); - _my_exit($real_exit_code) && return; - } +=item C<$BLevel> - my $exit_code; - if($num_failed) { - $exit_code = $num_failed <= 254 ? $num_failed : 254; - } - elsif( $num_extra != 0 ) { - $exit_code = 255; - } - else { - $exit_code = 0; - } +Used internally by the L<Test::Builder::Trace>, do not modify or rely on this +in your own code. Documented for completeness. - _my_exit($exit_code) && return; - } - elsif( $self->{Skip_All} ) { - _my_exit(0) && return; - } - elsif($real_exit_code) { - $self->diag(<<"FAIL"); -Looks like your test exited with $real_exit_code before it could output anything. -FAIL - $self->is_passing(0); - _my_exit($real_exit_code) && return; - } - else { - $self->diag("No tests run!\n"); - $self->is_passing(0); - _my_exit(255) && return; - } +=item C<$Test> - $self->is_passing(0); - $self->_whoa( 1, "We fell off the end of _ending()" ); -} +The singleton returned by C<new()>, which is deprecated in favor of +C<create()>. -END { - $Test->_ending if defined $Test; -} +=back =head1 EXIT CODES @@ -2602,11 +2341,13 @@ So the exit codes are... If you fail more than 254 tests, it will be reported as 254. +B<Note:> The magic that accomplishes this has been moved to +L<Test::Builder::ExitMagic> + =head1 THREADS In perl 5.8.1 and later, Test::Builder is thread-safe. The test -number is shared amongst all threads. This means if one thread sets -the test number using C<current_test()> they will all be effected. +number is shared amongst all threads. While versions earlier than 5.8.1 had threads they contain too many bugs to support. @@ -2616,7 +2357,11 @@ Test::Builder. =head1 MEMORY -An informative hash, accessible via C<<details()>>, is stored for each +B<Note:> This only applies if you turn lresults on. + + $Test->stream->no_lresults; + +An informative hash, accessible via C<details()>, is stored for each test you perform. So memory usage will scale linearly with each test run. Although this is not a problem for most test suites, it can become an issue if you do large (hundred thousands to million) @@ -2624,24 +2369,22 @@ combinatorics tests in the same run. In such cases, you are advised to either split the test file into smaller ones, or use a reverse approach, doing "normal" (code) compares and -triggering fail() should anything go unexpected. - -Future versions of Test::Builder will have a way to turn history off. - +triggering C<fail()> should anything go unexpected. =head1 EXAMPLES -CPAN can provide the best examples. Test::Simple, Test::More, -Test::Exception and Test::Differences all use Test::Builder. +CPAN can provide the best examples. L<Test::Simple>, L<Test::More>, +L<Test::Exception> and L<Test::Differences> all use Test::Builder. =head1 SEE ALSO -Test::Simple, Test::More, Test::Harness +L<Test::Simple>, L<Test::More>, L<Test::Harness>, L<Fennec> =head1 AUTHORS Original code by chromatic, maintained by Michael G Schwern -E<lt>schwern@pobox.comE<gt> +E<lt>schwern@pobox.comE<gt> until 2014. Currently maintained by Chad Granum +E<lt>exodist7@gmail.comE<gt>. =head1 MAINTAINERS @@ -2653,15 +2396,12 @@ E<lt>schwern@pobox.comE<gt> =head1 COPYRIGHT -Copyright 2002-2008 by chromatic E<lt>chromatic@wgz.orgE<gt> and - Michael G Schwern E<lt>schwern@pobox.comE<gt>. +Copyright 2002-2014 by chromatic E<lt>chromatic@wgz.orgE<gt> and + Michael G Schwern E<lt>schwern@pobox.comE<gt> and + Chad Granum E<lt>exodist7@gmail.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> -=cut - -1; - |