summaryrefslogtreecommitdiff
path: root/cpan/Test-Simple/lib/Test/Builder.pm
diff options
context:
space:
mode:
authorChad Granum <chad.granum@dreamhost.com>2014-08-15 08:40:10 -0700
committerJames E Keenan <jkeenan@cpan.org>2014-08-16 23:19:29 +0200
commit6bdb88770f849c47b5c09e733ac460ce3e9dbc97 (patch)
tree3eda7f11aea1019f7a802c1caecfb81ab26e7761 /cpan/Test-Simple/lib/Test/Builder.pm
parent7d16fb5f4895e672484c0b7490722d46df82b099 (diff)
downloadperl-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.pm3172
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;
-