summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlperl/lib/Test/Builder.pm
diff options
context:
space:
mode:
Diffstat (limited to 'Master/tlpkg/tlperl/lib/Test/Builder.pm')
-rw-r--r--Master/tlpkg/tlperl/lib/Test/Builder.pm170
1 files changed, 126 insertions, 44 deletions
diff --git a/Master/tlpkg/tlperl/lib/Test/Builder.pm b/Master/tlpkg/tlperl/lib/Test/Builder.pm
index cb4335f5ceb..061b0fc5a63 100644
--- a/Master/tlpkg/tlperl/lib/Test/Builder.pm
+++ b/Master/tlpkg/tlperl/lib/Test/Builder.pm
@@ -4,7 +4,7 @@ use 5.006;
use strict;
use warnings;
-our $VERSION = '0.98';
+our $VERSION = '1.001002';
$VERSION = eval $VERSION; ## no critic (BuiltinFunctions::ProhibitStringyEval)
BEGIN {
@@ -147,6 +147,20 @@ sub create {
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.
+sub _copy {
+ my($src, $dest) = @_;
+
+ %$dest = %$src;
+ _share_keys($dest);
+
+ return;
+}
+
+
=item B<child>
my $child = $builder->child($name_of_child);
@@ -179,15 +193,20 @@ sub child {
# Clear $TODO for the child.
my $orig_TODO = $self->find_TODO(undef, 1, undef);
- my $child = bless {}, ref $self;
- $child->reset;
+ my $class = ref $self;
+ my $child = $class->create;
# Add to our indentation
$child->_indent( $self->_indent . ' ' );
-
- $child->{$_} = $self->{$_} foreach qw{Out_FH Todo_FH Fail_FH};
- if ($parent_in_todo) {
- $child->{Fail_FH} = $self->{Todo_FH};
+
+ # Make the child use the same outputs as the parent
+ for my $method (qw(output failure_output todo_output)) {
+ $child->$method( $self->$method );
+ }
+
+ # Ensure the child understands if they're inside a TODO
+ if( $parent_in_todo ) {
+ $child->failure_output( $self->todo_output );
}
# This will be reset in finalize. We do this here lest one child failure
@@ -220,17 +239,22 @@ sub subtest {
# Turn the child into the parent so anyone who has stored a copy of
# the Test::Builder singleton will get the child.
- my($error, $child, %parent);
+ my $error;
+ my $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;
+ # Store the guts of $self as $parent and turn $child into $self.
$child = $self->child($name);
- %parent = %$self;
- %$self = %$child;
+ _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;
1;
@@ -242,8 +266,8 @@ sub subtest {
}
# Restore the parent and the copied child.
- %$child = %$self;
- %$self = %parent;
+ _copy($self, $child);
+ _copy($parent, $self);
# Restore the parent's $TODO
$self->find_TODO(undef, 1, $child->{Parent_TODO});
@@ -252,7 +276,11 @@ sub subtest {
die $error if $error and !eval { $error->isa('Test::Builder::Exception') };
local $Test::Builder::Level = $Test::Builder::Level + 1;
- return $child->finalize;
+ my $finalize = $child->finalize;
+
+ $self->BAIL_OUT($child->{Bailed_Out_Reason}) if $child->{Bailed_Out};
+
+ return $finalize;
}
=begin _private
@@ -322,14 +350,16 @@ sub finalize {
local $Test::Builder::Level = $Test::Builder::Level + 1;
my $ok = 1;
$self->parent->{Child_Name} = undef;
- if ( $self->{Skip_All} ) {
- $self->parent->skip($self->{Skip_All});
- }
- elsif ( not @{ $self->{Test_Results} } ) {
- $self->parent->ok( 0, sprintf q[No tests run for subtest "%s"], $self->name );
- }
- else {
- $self->parent->ok( $self->is_passing, $self->name );
+ unless ($self->{Bailed_Out}) {
+ if ( $self->{Skip_All} ) {
+ $self->parent->skip($self->{Skip_All});
+ }
+ elsif ( not @{ $self->{Test_Results} } ) {
+ $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};
@@ -415,7 +445,6 @@ sub reset { ## no critic (Subroutines::ProhibitBuiltinHomonyms)
$self->{Child_Name} = undef;
$self->{Indent} ||= '';
- share( $self->{Curr_Test} );
$self->{Curr_Test} = 0;
$self->{Test_Results} = &share( [] );
@@ -434,11 +463,25 @@ sub reset { ## no critic (Subroutines::ProhibitBuiltinHomonyms)
$self->{Start_Todo} = 0;
$self->{Opened_Testhandles} = 0;
+ $self->_share_keys;
$self->_dup_stdhandles;
return;
}
+
+# 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;
+
+ share( $self->{Curr_Test} );
+
+ return;
+}
+
+
=back
=head2 Setting up tests
@@ -633,7 +676,7 @@ Or to plan a variable number of tests:
for my $test (@tests) {
$Test->ok($test);
}
- $Test->done_testing(@tests);
+ $Test->done_testing(scalar @tests);
=cut
@@ -915,7 +958,7 @@ sub _is_dualvar {
no warnings 'numeric';
my $numval = $val + 0;
- return $numval != 0 and $numval ne $val ? 1 : 0;
+ return ($numval != 0 and $numval ne $val ? 1 : 0);
}
=item B<is_eq>
@@ -1065,38 +1108,38 @@ sub isnt_num {
=item B<like>
- $Test->like($this, qr/$regex/, $name);
- $Test->like($this, '/$regex/', $name);
+ $Test->like($thing, qr/$regex/, $name);
+ $Test->like($thing, '/$regex/', $name);
-Like Test::More's C<like()>. Checks if $this matches the given C<$regex>.
+Like Test::More's C<like()>. Checks if $thing matches the given C<$regex>.
=item B<unlike>
- $Test->unlike($this, qr/$regex/, $name);
- $Test->unlike($this, '/$regex/', $name);
+ $Test->unlike($thing, qr/$regex/, $name);
+ $Test->unlike($thing, '/$regex/', $name);
-Like Test::More's C<unlike()>. Checks if $this B<does not match> the
+Like Test::More's C<unlike()>. Checks if $thing B<does not match> the
given C<$regex>.
=cut
sub like {
- my( $self, $this, $regex, $name ) = @_;
+ my( $self, $thing, $regex, $name ) = @_;
local $Level = $Level + 1;
- return $self->_regex_ok( $this, $regex, '=~', $name );
+ return $self->_regex_ok( $thing, $regex, '=~', $name );
}
sub unlike {
- my( $self, $this, $regex, $name ) = @_;
+ my( $self, $thing, $regex, $name ) = @_;
local $Level = $Level + 1;
- return $self->_regex_ok( $this, $regex, '!~', $name );
+ return $self->_regex_ok( $thing, $regex, '!~', $name );
}
=item B<cmp_ok>
- $Test->cmp_ok($this, $type, $that, $name);
+ $Test->cmp_ok($thing, $type, $that, $name);
Works just like Test::More's C<cmp_ok()>.
@@ -1106,9 +1149,16 @@ Works just like Test::More's C<cmp_ok()>.
my %numeric_cmps = map { ( $_, 1 ) } ( "<", "<=", ">", ">=", "==", "!=", "<=>" );
+# Bad, these are not comparison operators. Should we include more?
+my %cmp_ok_bl = map { ( $_, 1 ) } ( "=", "+=", ".=", "x=", "^=", "|=", "||=", "&&=", "...");
+
sub cmp_ok {
my( $self, $got, $type, $expect, $name ) = @_;
+ if ($cmp_ok_bl{$type}) {
+ $self->croak("$type is not a valid comparison operator in cmp_ok()");
+ }
+
my $test;
my $error;
{
@@ -1208,6 +1258,13 @@ sub BAIL_OUT {
my( $self, $reason ) = @_;
$self->{Bailed_Out} = 1;
+
+ if ($self->parent) {
+ $self->{Bailed_Out_Reason} = $reason;
+ $self->no_ending(1);
+ die bless {} => 'Test::Builder::Exception';
+ }
+
$self->_print("Bail out! $reason");
exit 255;
}
@@ -1343,11 +1400,11 @@ For example, a version of C<like()>, sans the useful diagnostic messages,
could be written as:
sub laconic_like {
- my ($self, $this, $regex, $name) = @_;
+ my ($self, $thing, $regex, $name) = @_;
my $usable_regex = $self->maybe_regex($regex);
die "expecting regex, found '$regex'\n"
unless $usable_regex;
- $self->ok($this =~ m/$usable_regex/, $name);
+ $self->ok($thing =~ m/$usable_regex/, $name);
}
=cut
@@ -1385,7 +1442,7 @@ sub _is_qr {
}
sub _regex_ok {
- my( $self, $this, $regex, $cmp, $name ) = @_;
+ my( $self, $thing, $regex, $cmp, $name ) = @_;
my $ok = 0;
my $usable_regex = $self->maybe_regex($regex);
@@ -1397,14 +1454,19 @@ sub _regex_ok {
}
{
- ## no critic (BuiltinFunctions::ProhibitStringyEval)
-
my $test;
my $context = $self->_caller_context;
- local( $@, $!, $SIG{__DIE__} ); # isolate eval
+ {
+ ## no critic (BuiltinFunctions::ProhibitStringyEval)
+
+ local( $@, $!, $SIG{__DIE__} ); # isolate eval
+
+ # No point in issuing an uninit warning, they'll see it in the diagnostics
+ no warnings 'uninitialized';
- $test = eval $context . q{$test = $this =~ /$usable_regex/ ? 1 : 0};
+ $test = eval $context . q{$test = $thing =~ /$usable_regex/ ? 1 : 0};
+ }
$test = !$test if $cmp eq '!~';
@@ -1413,11 +1475,11 @@ sub _regex_ok {
}
unless($ok) {
- $this = defined $this ? "'$this'" : 'undef';
+ $thing = defined $thing ? "'$thing'" : 'undef';
my $match = $cmp eq '=~' ? "doesn't match" : "matches";
local $Level = $Level + 1;
- $self->diag( sprintf <<'DIAGNOSTIC', $this, $match, $regex );
+ $self->diag( sprintf <<'DIAGNOSTIC', $thing, $match, $regex );
%s
%13s '%s'
DIAGNOSTIC
@@ -2402,6 +2464,26 @@ sub _ending {
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;
+ }
+
+ # 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) {
+
+ my $exit_code = $num_failed <= 254 ? $num_failed : 254;
+ _my_exit($exit_code) && return;
+ }
+ }
+ _my_exit(254) && return;
}
# Exit if plan() was never called. This is so "require Test::Simple"