9 Test::Leaner - A slimmer Test::More for when you favor performance over completeness.
17 our $VERSION = '0.05';
21 use Test::Leaner tests => 10_000;
24 is $one, 1, "checking situation $_";
30 When profiling some L<Test::More>-based test script that contained about 10 000 unit tests, I realized that 60% of the time was spent in L<Test::Builder> itself, even though every single test actually involved a costly C<eval STRING>.
32 This module aims to be a partial replacement to L<Test::More> in those situations where you want to run a large number of simple tests.
33 Its functions behave the same as their L<Test::More> counterparts, except for the following differences :
39 Stringification isn't forced on the test operands.
40 However, L</ok> honors C<'bool'> overloading, L</is> and L</is_deeply> honor C<'eq'> overloading (and just that one), L</isnt> honors C<'ne'> overloading, and L</cmp_ok> honors whichever overloading category corresponds to the specified operator.
44 L</pass>, L</fail>, L</ok>, L</is>, L</isnt>, L</like>, L</unlike>, L</cmp_ok> and L</is_deeply> are all guaranteed to return the truth value of the test.
48 C<isn't> (the sub C<t> in package C<isn>) is not aliased to L</isnt>.
52 L</like> and L</unlike> don't special case regular expressions that are passed as C<'/.../'> strings.
53 A string regexp argument is always treated as 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>).
57 L</cmp_ok> throws an exception if the given operator isn't a valid Perl binary operator (except C<'='> and variants).
58 It also tests in scalar context, so C<'..'> will be treated as the flip-flop operator and not the range operator.
62 L</is_deeply> doesn't guard for memory cycles.
63 If the two first arguments present parallel memory cycles, the test may result in an infinite loop.
67 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.
68 Moreover, this allows a much faster variant of L</is_deeply>.
72 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.
85 if ("$]" >= 5.008 and $INC{'threads.pm'}) {
86 my $use_ithreads = do {
89 $Config::Config{useithreads};
92 require threads::shared;
93 *THREADSAFE = sub () { 1 };
96 unless (defined &Test::Leaner::THREADSAFE) {
97 *THREADSAFE = sub () { 0 }
101 my ($TAP_STREAM, $DIAG_STREAM);
103 my ($plan, $test, $failed, $no_diag, $done_testing);
125 =head2 C<PERL_TEST_LEANER_USES_TEST_MORE>
127 If this environment variable is set, L<Test::Leaner> will replace its functions by those from L<Test::More>.
128 Moreover, the symbols that are imported when you C<use Test::Leaner> will be those from L<Test::More>, but you can still only import the symbols originally defined in L<Test::Leaner> (hence the functions from L<Test::More> that are not implemented in L<Test::Leaner> will not be imported).
129 If your version of L<Test::More> is too old and doesn't have some symbols (like L</note> or L</done_testing>), they will be replaced in L<Test::Leaner> by croaking stubs.
131 This may be useful if your L<Test::Leaner>-based test script fails and you want extra diagnostics.
135 sub _handle_import_args {
143 if ($item eq 'import') {
144 push @imports, @{ $_[$i+1] };
146 } elsif ($item eq 'no_diag') {
147 lock $plan if THREADSAFE;
153 splice @_, $i, $splice;
162 if ($ENV{PERL_TEST_LEANER_USES_TEST_MORE}) {
165 my $leaner_stash = \%Test::Leaner::;
166 my $more_stash = \%Test::More::;
171 my $replacement = exists $more_stash->{$_} ? *{$more_stash->{$_}}{CODE}
173 unless (defined $replacement) {
176 @_ = ("$_ is not implemented in this version of Test::More");
180 no warnings 'redefine';
181 $leaner_stash->{$_} = $replacement;
187 my @imports = &_handle_import_args;
188 if (@imports == grep /^!/, @imports) {
189 # All imports are negated, or @imports is empty
191 /^!(.*)/ and ++$negated{$1} for @imports;
192 push @imports, grep !$negated{$_}, @EXPORT;
195 my @test_more_imports;
200 *{$pkg."::$_"} = $leaner_stash->{$_};
201 } elsif (/^!/ or !exists $more_stash->{$_} or exists $leaner_stash->{$_}) {
202 push @test_more_imports, $_;
204 # Croak for symbols in Test::More but not in Test::Leaner
205 Exporter::import($class, $_);
209 my $test_more_import = 'Test::More'->can('import');
210 return unless $test_more_import;
215 import => \@test_more_imports,
218 lock $plan if THREADSAFE;
219 push @_, 'no_diag' if $no_diag;
222 goto $test_more_import;
225 no warnings 'redefine';
231 sub NO_PLAN () { -1 }
232 sub SKIP_ALL () { -2 }
236 threads::shared::share($_) for $plan, $test, $failed, $no_diag, $done_testing;
239 lock $plan if THREADSAFE;
247 my $level = 1 + ($Test::Builder::Level || 0);
250 @caller = caller $level--;
251 } while (!@caller and $level >= 0);
252 my ($file, $line) = @caller[1, 2];
253 warn @_, " at $file line $line.\n";
257 my $level = 1 + ($Test::Builder::Level || 0);
260 @caller = caller $level--;
261 } while (!@caller and $level >= 0);
262 my ($file, $line) = @caller[1, 2];
263 die @_, " at $file line $line.\n";
266 sub _sanitize_comment {
269 $_[0] =~ s/\n/\n# /g;
274 The following functions from L<Test::More> are implemented and exported by default.
278 plan tests => $count;
280 plan skip_all => $reason;
282 See L<Test::More/plan>.
287 my ($key, $value) = @_;
291 lock $plan if THREADSAFE;
293 croak("You tried to plan twice") if defined $plan;
297 if ($key eq 'no_plan') {
298 croak("no_plan takes no arguments") if $value;
300 } elsif ($key eq 'tests') {
301 croak("Got an undefined number of tests") unless defined $value;
302 croak("You said to run 0 tests") unless $value;
303 croak("Number of tests must be a positive integer. You gave it '$value'")
304 unless $value =~ /^\+?[0-9]+$/;
306 $plan_str = "1..$value";
307 } elsif ($key eq 'skip_all') {
309 $plan_str = '1..0 # SKIP';
310 if (defined $value) {
311 _sanitize_comment($value);
312 $plan_str .= " $value" if length $value;
315 my @args = grep defined, $key, $value;
316 croak("plan() doesn't understand @args");
319 if (defined $plan_str) {
321 print $TAP_STREAM "$plan_str\n";
324 exit 0 if $plan == SKIP_ALL;
332 my @imports = &_handle_import_args;
335 local $Test::Builder::Level = ($Test::Builder::Level || 0) + 1;
339 @_ = ($class, @imports);
340 goto &Exporter::import;
345 skip $reason => $count;
347 See L<Test::More/skip>.
352 my ($reason, $count) = @_;
354 lock $plan if THREADSAFE;
356 if (not defined $count) {
357 carp("skip() needs to know \$how_many tests are in the block")
358 unless defined $plan and $plan == NO_PLAN;
360 } elsif ($count =~ /[^0-9]/) {
361 carp('skip() was passed a non-numeric number of tests. Did you get the arguments backwards?');
368 my $skip_str = "ok $test # skip";
369 if (defined $reason) {
370 _sanitize_comment($reason);
371 $skip_str .= " $reason" if length $reason;
375 print $TAP_STREAM "$skip_str\n";
378 no warnings 'exiting';
382 =head2 C<done_testing>
387 See L<Test::More/done_testing>.
394 lock $plan if THREADSAFE;
396 $count = $test unless defined $count;
397 croak("Number of tests must be a positive integer. You gave it '$count'")
398 unless $count =~ /^\+?[0-9]+$/;
400 if (not defined $plan or $plan == NO_PLAN) {
401 $plan = $count; # $plan can't be NO_PLAN anymore
404 print $TAP_STREAM "1..$plan\n";
407 @_ = ('done_testing() was already called');
409 } elsif ($plan != $count) {
410 @_ = ("planned to run $plan tests but done_testing() expects $count");
423 See L<Test::More/ok>.
428 my ($ok, $desc) = @_;
430 lock $plan if THREADSAFE;
434 my $test_str = "ok $test";
436 $test_str = "not $test_str";
440 _sanitize_comment($desc);
441 $test_str .= " - $desc" if length $desc;
445 print $TAP_STREAM "$test_str\n";
455 See L<Test::More/pass>.
469 See L<Test::More/fail>.
481 is $got, $expected, $desc;
483 See L<Test::More/is>.
488 my ($got, $expected, $desc) = @_;
489 no warnings 'uninitialized';
491 (not(defined $got xor defined $expected) and $got eq $expected),
499 isnt $got, $expected;
500 isnt $got, $expected, $desc;
502 See L<Test::More/isnt>.
507 my ($got, $expected, $desc) = @_;
508 no warnings 'uninitialized';
510 ((defined $got xor defined $expected) or $got ne $expected),
522 ('//' => 'dor') x ("$]" >= 5.010),
547 ('~~' => 'smartmatch') x ("$]" >= 5.010),
559 '...' => 'altflipflop',
566 sub _create_binop_handler {
568 my $name = $binops{$op};
569 croak("Operator $op not supported") unless defined $name;
573 sub is_$name (\$\$;\$) {
574 my (\$got, \$expected, \$desc) = \@_;
575 \@_ = (scalar(\$got $op \$expected), \$desc);
581 $binop_handlers{$op} = do {
583 \&{__PACKAGE__."::is_$name"};
589 like $got, $regexp_expected;
590 like $got, $regexp_expected, $desc;
592 See L<Test::More/like>.
596 unlike $got, $regexp_expected;
597 unlike $got, $regexp_expected, $desc;
599 See L<Test::More/unlike>.
605 *like = _create_binop_handler('=~');
606 *unlike = _create_binop_handler('!~');
611 cmp_ok $got, $op, $expected;
612 cmp_ok $got, $op, $expected, $desc;
614 See L<Test::More/cmp_ok>.
619 my ($got, $op, $expected, $desc) = @_;
620 my $handler = $binop_handlers{$op};
622 local $Test::More::Level = ($Test::More::Level || 0) + 1;
623 $handler = _create_binop_handler($op);
625 @_ = ($got, $expected, $desc);
631 is_deeply $got, $expected;
632 is_deeply $got, $expected, $desc;
634 See L<Test::More/is_deeply>.
640 if (eval { require Scalar::Util; 1 }) {
641 *_reftype = \&Scalar::Util::reftype;
643 # Stolen from Scalar::Util::PP
655 *_reftype = sub ($) {
658 return undef unless length ref $r;
660 my $t = ref B::svref_2object($r);
662 return exists $tmap{$t} ? $tmap{$t}
663 : length ref $$r ? 'REF'
669 sub _deep_ref_check {
670 my ($x, $y, $ry) = @_;
672 no warnings qw<numeric uninitialized>;
674 if ($ry eq 'ARRAY') {
675 return 0 unless $#$x == $#$y;
682 # Inline the beginning of _deep_check
683 return 0 if defined $ex xor defined $ey;
685 next if not(ref $ex xor ref $ey) and $ex eq $ey;
688 return 0 if _reftype($ex) ne $ry;
690 return 0 unless $ry and _deep_ref_check($ex, $ey, $ry);
694 } elsif ($ry eq 'HASH') {
695 return 0 unless keys(%$x) == keys(%$y);
699 return 0 unless exists $x->{$_};
703 # Inline the beginning of _deep_check
704 return 0 if defined $ex xor defined $ey;
706 next if not(ref $ex xor ref $ey) and $ex eq $ey;
709 return 0 if _reftype($ex) ne $ry;
711 return 0 unless $ry and _deep_ref_check($ex, $ey, $ry);
715 } elsif ($ry eq 'SCALAR' or $ry eq 'REF') {
716 return _deep_check($$x, $$y);
725 no warnings qw<numeric uninitialized>;
727 return 0 if defined $x xor defined $y;
729 # Try object identity/eq overloading first. It also covers the case where
730 # $x and $y are both undefined.
731 # If either $x or $y is overloaded but none has eq overloading, the test will
732 # break at that point.
733 return 1 if not(ref $x xor ref $y) and $x eq $y;
735 # Test::More::is_deeply happily breaks encapsulation if the objects aren't
737 my $ry = _reftype($y);
738 return 0 if _reftype($x) ne $ry;
740 # Shortcut if $x and $y are both not references and failed the previous
744 # We know that $x and $y are both references of type $ry, without overloading.
745 _deep_ref_check($x, $y, $ry);
761 lock $plan if THREADSAFE;
764 my $msg = join '', map { defined($_) ? $_ : 'undef' } @_;
765 _sanitize_comment($msg);
766 return unless length $msg;
769 print $fh "# $msg\n";
778 See L<Test::More/diag>.
783 unshift @_, $DIAG_STREAM;
791 See L<Test::More/note>.
796 unshift @_, $TAP_STREAM;
805 See L<Test::More/BAIL_OUT>.
812 lock $plan if THREADSAFE;
814 my $bail_out_str = 'Bail out!';
816 _sanitize_comment($desc);
817 $bail_out_str .= " $desc" if length $desc; # Two spaces
821 print $TAP_STREAM "$bail_out_str\n";
827 if ($main_process == $$ and not $?) {
828 lock $plan if THREADSAFE;
832 $? = $failed <= 254 ? $failed : 254;
833 } elsif ($plan >= 0) {
834 $? = $test == $plan ? 0 : 255;
836 if ($plan == NO_PLAN) {
838 print $TAP_STREAM "1..$test\n";
846 L<Test::Leaner> also provides some functions of its own, which are never exported.
850 my $tap_fh = tap_stream;
853 Read/write accessor for the filehandle to which the tests are outputted.
854 On write, it also turns autoflush on onto C<$fh>.
856 Note that it can only be used as a write accessor before you start any thread, as L<threads::shared> cannot reliably share filehandles.
858 Defaults to C<STDOUT>.
862 sub tap_stream (;*) {
866 my $fh = select $TAP_STREAM;
876 =head2 C<diag_stream>
878 my $diag_fh = diag_stream;
881 Read/write accessor for the filehandle to which the diagnostics are printed.
882 On write, it also turns autoflush on onto C<$fh>.
884 Just like L</tap_stream>, it can only be used as a write accessor before you start any thread, as L<threads::shared> cannot reliably share filehandles.
886 Defaults to C<STDERR>.
890 sub diag_stream (;*) {
892 $DIAG_STREAM = $_[0];
894 my $fh = select $DIAG_STREAM;
906 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>.
907 In that case, it also needs a working L<threads::shared>.
913 L<Exporter>, L<Test::More>.
917 Vincent Pit C<< <vpit at cpan.org> >>.
919 You can contact me by mail or on C<irc.perl.org> (vincent).
923 Please report any bugs or feature requests to C<bug-test-leaner at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-Leaner>.
924 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
928 You can find documentation for this module with the perldoc command.
932 =head1 COPYRIGHT & LICENSE
934 Copyright 2010,2011,2013,2019 Vincent Pit, all rights reserved.
936 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
938 Except for the fallback implementation of the internal C<_reftype> function, which has been taken from L<Scalar::Util> and is
940 Copyright 1997-2007 Graham Barr, all rights reserved.
942 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
946 1; # End of Test::Leaner