9 Test::Leaner - A slimmer Test::More for when you favor performance over completeness.
17 our $VERSION = '0.01';
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) 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> and L</cmp_ok> are all guaranteed to return the truth value of the test.
48 L</like> and L</unlike> don't special case regular expressions that are passed as C<'/.../'> strings.
49 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>).
53 L</cmp_ok> throws an exception if the given operator isn't a valid Perl binary operator (except C<'='> and variants).
54 It also tests in scalar context, so C<'..'> will be treated as the flip-flop operator and not the range operator.
58 L</is_deeply> doesn't guard for memory cycles.
59 If the two first arguments present parallel memory cycles, the test may result in an infinite loop.
63 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.
67 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.
71 L<Test::Leaner> depends on L<Scalar::Util>, while L<Test::More> does not.
81 if ($] >= 5.008 and $INC{'threads.pm'}) {
82 my $use_ithreads = do {
85 $Config::Config{useithreads};
88 require threads::shared;
89 *THREADSAFE = sub () { 1 };
92 unless (defined &Test::Leaner::THREADSAFE) {
93 *THREADSAFE = sub () { 0 }
97 my ($TAP_STREAM, $DIAG_STREAM);
99 my ($plan, $test, $failed, $no_diag, $done_testing);
121 =head2 C<PERL_TEST_LEANER_USES_TEST_MORE>
123 If this environment variable is set, L<Test::Leaner> will replace its functions by those from L<Test::More>.
124 Moreover, the symbols that are imported 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).
125 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.
127 This may be useful if your L<Test::Leaner>-based test script fails and you want extra diagnostics.
131 sub _handle_import_args {
139 if ($item eq 'import') {
140 push @imports, @{ $_[$i+1] };
142 } elsif ($item eq 'no_diag') {
143 lock $plan if THREADSAFE;
149 splice @_, $i, $splice;
158 if ($ENV{PERL_TEST_LEANER_USES_TEST_MORE}) {
161 my $leaner_stash = \%Test::Leaner::;
162 my $more_stash = \%Test::More::;
167 my $replacement = exists $more_stash->{$_} ? *{$more_stash->{$_}}{CODE}
169 if (defined $replacement) {
170 $valid_imports{$_} = 1;
173 @_ = ("$_ is not implemented in this version of Test::More");
177 no warnings 'redefine';
178 $leaner_stash->{$_} = $replacement;
183 my @imports = &_handle_import_args;
184 @imports = @EXPORT unless @imports;
185 my @test_more_imports;
187 if ($valid_imports{$_}) {
188 push @test_more_imports, $_;
192 *{$pkg."::$_"} = $leaner_stash->{$_};
195 my $test_more_import = 'Test::More'->can('import');
199 import => \@test_more_imports,
202 lock $plan if THREADSAFE;
203 push @_, 'no_diag' if $no_diag;
205 goto $test_more_import;
208 no warnings 'redefine';
214 sub NO_PLAN () { -1 }
215 sub SKIP_ALL () { -2 }
219 threads::shared::share($_) for $plan, $test, $failed, $no_diag, $done_testing;
222 lock $plan if THREADSAFE;
230 my $level = 1 + ($Test::Builder::Level || 0);
233 @caller = caller $level--;
234 } while (!@caller and $level >= 0);
235 my ($file, $line) = @caller[1, 2];
236 warn @_, " at $file line $line.\n";
240 my $level = 1 + ($Test::Builder::Level || 0);
243 @caller = caller $level--;
244 } while (!@caller and $level >= 0);
245 my ($file, $line) = @caller[1, 2];
246 die @_, " at $file line $line.\n";
249 sub _sanitize_comment {
252 $_[0] =~ s/\n/\n# /g;
257 The following functions from L<Test::More> are implemented and exported by default.
259 =head2 C<< plan [ tests => $count | 'no_plan' | skip_all => $reason ] >>
261 See L<Test::More/plan>.
266 my ($key, $value) = @_;
270 lock $plan if THREADSAFE;
272 croak("You tried to plan twice") if defined $plan;
276 if ($key eq 'no_plan') {
277 croak("no_plan takes no arguments") if $value;
279 } elsif ($key eq 'tests') {
280 croak("Got an undefined number of tests") unless defined $value;
281 croak("You said to run 0 tests") unless $value;
282 croak("Number of tests must be a positive integer. You gave it '$value'")
283 unless $value =~ /^\+?[0-9]+$/;
285 $plan_str = "1..$value";
286 } elsif ($key eq 'skip_all') {
288 $plan_str = '1..0 # SKIP';
289 if (defined $value) {
290 _sanitize_comment($value);
291 $plan_str .= " $value" if length $value;
294 my @args = grep defined, $key, $value;
295 croak("plan() doesn't understand @args");
298 if (defined $plan_str) {
300 print $TAP_STREAM "$plan_str\n";
303 exit 0 if $plan == SKIP_ALL;
311 my @imports = &_handle_import_args;
314 local $Test::Builder::Level = ($Test::Builder::Level || 0) + 1;
318 @_ = ($class, @imports);
319 goto &Exporter::import;
322 =head2 C<< skip $reason => $count >>
324 See L<Test::More/skip>.
329 my ($reason, $count) = @_;
331 lock $plan if THREADSAFE;
333 if (not defined $count) {
334 carp("skip() needs to know \$how_many tests are in the block")
335 unless defined $plan and $plan == NO_PLAN;
337 } elsif ($count =~ /[^0-9]/) {
338 carp('skip() was passed a non-numeric number of tests. Did you get the arguments backwards?');
345 my $skip_str = "ok $test # skip";
346 if (defined $reason) {
347 _sanitize_comment($reason);
348 $skip_str .= " $reason" if length $reason;
352 print $TAP_STREAM "$skip_str\n";
355 no warnings 'exiting';
359 =head2 C<done_testing [ $count ]>
361 See L<Test::More/done_testing>.
368 lock $plan if THREADSAFE;
370 $count = $test unless defined $count;
371 croak("Number of tests must be a positive integer. You gave it '$count'")
372 unless $count =~ /^\+?[0-9]+$/;
374 if (not defined $plan or $plan == NO_PLAN) {
375 $plan = $count; # $plan can't be NO_PLAN anymore
378 print $TAP_STREAM "1..$plan\n";
381 @_ = ('done_testing() was already called');
383 } elsif ($plan != $count) {
384 @_ = ("planned to run $plan tests but done_testing() expects $count");
392 =head2 C<ok $ok [, $desc ]>
394 See L<Test::More/ok>.
399 my ($ok, $desc) = @_;
401 lock $plan if THREADSAFE;
405 my $test_str = "ok $test";
407 $test_str = "not $test_str";
411 _sanitize_comment($desc);
412 $test_str .= " - $desc" if length $desc;
416 print $TAP_STREAM "$test_str\n";
421 =head2 C<pass [ $desc ]>
423 See L<Test::More/pass>.
432 =head2 C<fail [ $desc ]>
434 See L<Test::More/fail>.
443 =head2 C<is $got, $expected [, $desc ]>
445 See L<Test::More/is>.
450 my ($got, $expected, $desc) = @_;
451 no warnings 'uninitialized';
453 (not(defined $got xor defined $expected) and $got eq $expected),
459 =head2 C<isnt $got, $expected [, $desc ]>
461 See L<Test::More/isnt>.
466 my ($got, $expected, $desc) = @_;
467 no warnings 'uninitialized';
469 ((defined $got xor defined $expected) or $got ne $expected),
481 ('//' => 'dor') x ($] >= 5.010),
506 ('~~' => 'smartmatch') x ($] >= 5.010),
518 '...' => 'altflipflop',
525 sub _create_binop_handler {
527 my $name = $binops{$op};
528 croak("Operator $op not supported") unless defined $name;
532 sub is_$name (\$\$;\$) {
533 my (\$got, \$expected, \$desc) = \@_;
534 \@_ = (scalar(\$got $op \$expected), \$desc);
540 $binop_handlers{$op} = do {
542 \&{__PACKAGE__."::is_$name"};
546 =head2 C<like $got, $regexp_expected [, $desc ]>
548 See L<Test::More/like>.
550 =head2 C<unlike $got, $regexp_expected, [, $desc ]>
552 See L<Test::More/unlike>.
558 *like = _create_binop_handler('=~');
559 *unlike = _create_binop_handler('!~');
562 =head2 C<cmp_ok $got, $op, $expected [, $desc ]>
564 See L<Test::More/cmp_ok>.
569 my ($got, $op, $expected, $desc) = @_;
570 my $handler = $binop_handlers{$op};
572 local $Test::More::Level = ($Test::More::Level || 0) + 1;
573 $handler = _create_binop_handler($op);
575 @_ = ($got, $expected, $desc);
579 =head2 C<is_deeply $got, $expected [, $desc ]>
581 See L<Test::More/is_deeply>.
585 sub _deep_ref_check {
586 my ($x, $y, $ry) = @_;
588 no warnings qw<numeric uninitialized>;
590 if ($ry eq 'ARRAY') {
591 return 0 unless $#$x == $#$y;
598 # Inline the beginning of _deep_check
599 return 0 if defined $ex xor defined $ey;
601 next if not(ref $ex xor ref $ey) and $ex eq $ey;
603 $ry = Scalar::Util::reftype($ey);
604 return 0 if Scalar::Util::reftype($ex) ne $ry;
606 return 0 unless $ry and _deep_ref_check($ex, $ey, $ry);
610 } elsif ($ry eq 'HASH') {
611 return 0 unless keys(%$x) == keys(%$y);
615 return 0 unless exists $x->{$_};
619 # Inline the beginning of _deep_check
620 return 0 if defined $ex xor defined $ey;
622 next if not(ref $ex xor ref $ey) and $ex eq $ey;
624 $ry = Scalar::Util::reftype($ey);
625 return 0 if Scalar::Util::reftype($ex) ne $ry;
627 return 0 unless $ry and _deep_ref_check($ex, $ey, $ry);
631 } elsif ($ry eq 'SCALAR' or $ry eq 'REF') {
632 return _deep_check($$x, $$y);
641 no warnings qw<numeric uninitialized>;
643 return 0 if defined $x xor defined $y;
645 # Try object identity/eq overloading first. It also covers the case where
646 # $x and $y are both undefined.
647 # If either $x or $y is overloaded but none has eq overloading, the test will
648 # break at that point.
649 return 1 if not(ref $x xor ref $y) and $x eq $y;
651 # Test::More::is_deeply happily breaks encapsulation if the objects aren't
653 my $ry = Scalar::Util::reftype($y);
654 return 0 if Scalar::Util::reftype($x) ne $ry;
656 # Shortcut if $x and $y are both not references and failed the previous
660 # We know that $x and $y are both references of type $ry, without overloading.
661 _deep_ref_check($x, $y, $ry);
677 lock $plan if THREADSAFE;
680 my $msg = join '', map { defined($_) ? $_ : 'undef' } @_;
681 _sanitize_comment($msg);
682 return unless length $msg;
685 print $fh "# $msg\n";
692 See L<Test::More/diag>.
697 unshift @_, $DIAG_STREAM;
703 See L<Test::More/note>.
708 unshift @_, $TAP_STREAM;
712 =head2 C<BAIL_OUT [ $desc ]>
714 See L<Test::More/BAIL_OUT>.
721 lock $plan if THREADSAFE;
723 my $bail_out_str = 'Bail out!';
725 _sanitize_comment($desc);
726 $bail_out_str .= " $desc" if length $desc; # Two spaces
730 print $TAP_STREAM "$bail_out_str\n";
737 lock $plan if THREADSAFE;
741 $? = $failed <= 254 ? $failed : 254;
742 } elsif ($plan >= 0) {
743 $? = $test == $plan ? 0 : 255;
745 if ($plan == NO_PLAN) {
747 print $TAP_STREAM "1..$test\n";
755 L<Test::Leaner> also provides some functions of its own, which are never exported.
757 =head2 C<tap_stream [ $fh ]>
759 Read/write accessor for the filehandle to which the tests are outputted.
760 On write, it also turns autoflush on onto C<$fh>.
762 Note that it can only be used as a write accessor before you start any thread, as L<threads::shared> cannot reliably share filehandles.
764 Defaults to C<STDOUT>.
768 sub tap_stream (;*) {
772 my $fh = select $TAP_STREAM;
782 =head2 C<diag_stream [ $fh ]>
784 Read/write accessor for the filehandle to which the diagnostics are printed.
785 On write, it also turns autoflush on onto C<$fh>.
787 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.
789 Defaults to C<STDERR>.
793 sub diag_stream (;*) {
795 $DIAG_STREAM = $_[0];
797 my $fh = select $DIAG_STREAM;
809 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>.
810 In that case, it also needs a working L<threads::shared>.
816 L<Exporter>, L<Scalar::Util>, L<Test::More>.
820 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
822 You can contact me by mail or on C<irc.perl.org> (vincent).
826 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>.
827 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
831 You can find documentation for this module with the perldoc command.
835 =head1 COPYRIGHT & LICENSE
837 Copyright 2010 Vincent Pit, all rights reserved.
839 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
843 1; # End of Test::Leaner