=item *
Stringification isn't forced on the test operands.
-However, L</ok> honors C<'bool'> overloading, L</is> honors C<'eq'> overloading and L</cmp_ok> honors whichever overloading category corresponds to the specified operator.
+However, L</ok> honors C<'bool'> overloading, L</is> and L</is_deeply> honor C<'eq'> overloading (and just that one) and L</cmp_ok> honors whichever overloading category corresponds to the specified operator.
=item *
=item *
+L</like> and L</unlike> don't special case regular expressions that are passed as C<'/.../'> strings.
+A string regexp argument is always treated as a the source of the regexp, making C<like $text, $rx> and C<like $text, qr[$rx]> equivalent to each other and to C<cmp_ok $text, '=~', $rx> (and likewise for C<unlike>).
+
+=item *
+
L</cmp_ok> throws an exception if the given operator isn't a valid Perl binary operator (except C<'='> and variants).
It also tests in scalar context, so C<'..'> will be treated as the flip-flop operator and not the range operator.
=item *
+L</is_deeply> doesn't guard for memory cycles.
+If the two first arguments present parallel memory cycles, the test may result in an infinite loop.
+
+=item *
+
+The tests don't output any kind of default diagnostic in case of failure ; the rationale being that if you have a large number of tests and a lot of them are failing, then you don't want to be flooded by diagnostics.
+
+=item *
+
C<use_ok>, C<require_ok>, C<can_ok>, C<isa_ok>, C<new_ok>, C<subtest>, C<explain>, C<TODO> blocks and C<todo_skip> are not implemented.
+=item *
+
+L<Test::Leaner> depends on L<Scalar::Util>, while L<Test::More> does not.
+
=back
=cut
-use Exporter ();
+use Exporter ();
+use Scalar::Util ();
BEGIN {
if ($] >= 5.008 and $INC{'threads.pm'}) {
die @_, " at $file line $line.\n";
}
-sub sanitize_comment {
+sub _sanitize_comment {
$_[0] =~ s/\n+\z//;
$_[0] =~ s/#/\\#/g;
$_[0] =~ s/\n/\n# /g;
$plan = SKIP_ALL;
$plan_str = '1..0 # SKIP';
if (defined $value) {
- sanitize_comment($value);
+ _sanitize_comment($value);
$plan_str .= " $value" if length $value;
}
} else {
ok
is
isnt
- cmp_ok
like
unlike
+ cmp_ok
+ is_deeply
diag
note
BAIL_OUT
my $skip_str = "ok $test # skip";
if (defined $reason) {
- sanitize_comment($reason);
+ _sanitize_comment($reason);
$skip_str .= " $reason" if length $reason;
}
++$failed;
}
if (defined $desc) {
- sanitize_comment($desc);
+ _sanitize_comment($desc);
$test_str .= " - $desc" if length $desc;
}
=head2 C<like $got, $regexp_expected [, $desc ]>
+=cut
+
=head2 C<unlike $got, $regexp_expected, [, $desc ]>
=cut
goto $handler;
}
+=head2 C<is_deeply $got, $expected [, $desc ]>
+
+=cut
+
+sub _deep_check {
+ my ($x, $y) = @_;
+
+ no warnings qw<numeric uninitialized>;
+
+ return 0 if defined($x) xor defined($y);
+
+ # Try object identity/eq overloading first. It also covers the case where
+ # $x and $y are both undefined.
+ # If either $x or $y is overloaded but none has eq overloading, the test will
+ # break at that point.
+ return 1 if not(ref($x) xor ref($y)) and $x eq $y;
+
+ # Test::More::is_deeply happily breaks encapsulation if the objects aren't
+ # overloaded.
+ my $ry = Scalar::Util::reftype($y);
+ return 0 if Scalar::Util::reftype($x) ne $ry;
+
+ # Shortcut if $x and $y are both not references and failed the previous
+ # $x eq $y test.
+ return 0 unless $ry;
+
+ if ($ry eq 'ARRAY') {
+ if ($#$x == $#$y) {
+ # Prevent vivification of deleted elements by fetching the array values.
+ my ($ex, $ey);
+ _deep_check($ex = $x->[$_], $ey = $y->[$_]) or return 0 for 0 .. $#$y;
+ return 1;
+ }
+ } elsif ($ry eq 'HASH') {
+ if (keys(%$x) == keys(%$y)) {
+ (exists $x->{$_} and _deep_check($x->{$_}, $y->{$_}))
+ or return 0 for keys %$y;
+ return 1;
+ }
+ } elsif ($ry eq 'SCALAR' or $ry eq 'REF') {
+ return _deep_check($$x, $$y);
+ }
+
+ return 0;
+};
+
+sub is_deeply {
+ @_ = (
+ &_deep_check,
+ $_[2],
+ );
+ goto &ok;
+}
+
sub _diag_fh {
my $fh = shift;
return if $no_diag;
my $msg = join '', map { defined($_) ? $_ : 'undef' } @_;
- sanitize_comment($msg);
+ _sanitize_comment($msg);
return unless length $msg;
local $\;
my $bail_out_str = 'Bail out!';
if (defined $desc) {
- sanitize_comment($desc);
+ _sanitize_comment($desc);
$bail_out_str .= " $desc" if length $desc; # Two spaces
}
diag_stream *STDERR;
+=head2 C<THREADSAFE>
+
+This constant evaluates to true if and only if L<Test::Leaner> is thread-safe, i.e. when this version of C<perl> is at least 5.8, has been compiled with C<useithreads> defined, and L<threads> has been loaded B<before> L<Test::Leaner>.
+In that case, it also needs a working L<threads::shared>.
+
=head1 DEPENDENCIES
L<perl> 5.6.
-L<Exporter>, L<Test::More>
+L<Exporter>, L<Scalar::Util>, L<Test::More>.
=head1 AUTHOR