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);
101 sub NO_PLAN () { -1 }
102 sub SKIP_ALL () { -2 }
106 threads::shared::share($_) for $plan, $test, $failed, $no_diag, $done_testing;
109 lock $plan if THREADSAFE;
117 my $level = 1 + ($Test::Builder::Level || 0);
118 my ($file, $line) = (caller $level)[1, 2];
119 warn @_, " at $file line $line.\n";
123 my $level = 1 + ($Test::Builder::Level || 0);
124 my ($file, $line) = (caller $level)[1, 2];
125 die @_, " at $file line $line.\n";
128 sub _sanitize_comment {
131 $_[0] =~ s/\n/\n# /g;
136 The following functions from L<Test::More> are implemented and exported by default.
138 =head2 C<< plan [ tests => $count | 'no_plan' | skip_all => $reason ] >>
140 See L<Test::More/plan>.
145 my ($key, $value) = @_;
149 lock $plan if THREADSAFE;
151 croak("You tried to plan twice") if defined $plan;
155 if ($key eq 'no_plan') {
156 croak("no_plan takes no arguments") if $value;
158 } elsif ($key eq 'tests') {
159 croak("Got an undefined number of tests") unless defined $value;
160 croak("You said to run 0 tests") unless $value;
161 croak("Number of tests must be a positive integer. You gave it '$value'")
162 unless $value =~ /^\+?[0-9]+$/;
164 $plan_str = "1..$value";
165 } elsif ($key eq 'skip_all') {
167 $plan_str = '1..0 # SKIP';
168 if (defined $value) {
169 _sanitize_comment($value);
170 $plan_str .= " $value" if length $value;
173 my @args = grep defined, $key, $value;
174 croak("plan() doesn't understand @args");
177 if (defined $plan_str) {
179 print $TAP_STREAM "$plan_str\n";
182 exit 0 if $plan == SKIP_ALL;
214 if ($item eq 'import') {
215 push @imports, @{ $_[$i+1] };
217 } elsif ($item eq 'no_diag') {
218 lock $plan if THREADSAFE;
224 splice @_, $i, $splice;
231 local $Test::Builder::Level = ($Test::Builder::Level || 0) + 1;
235 @_ = ($class, @imports);
236 goto &Exporter::import;
239 =head2 C<< skip $reason => $count >>
241 See L<Test::More/skip>.
246 my ($reason, $count) = @_;
248 lock $plan if THREADSAFE;
250 if (not defined $count) {
251 carp("skip() needs to know \$how_many tests are in the block")
252 unless defined $plan and $plan == NO_PLAN;
254 } elsif ($count =~ /[^0-9]/) {
255 carp('skip() was passed a non-numeric number of tests. Did you get the arguments backwards?');
262 my $skip_str = "ok $test # skip";
263 if (defined $reason) {
264 _sanitize_comment($reason);
265 $skip_str .= " $reason" if length $reason;
269 print $TAP_STREAM "$skip_str\n";
272 no warnings 'exiting';
276 =head2 C<done_testing [ $count ]>
278 See L<Test::More/done_testing>.
285 lock $plan if THREADSAFE;
287 $count = $test unless defined $count;
288 croak("Number of tests must be a positive integer. You gave it '$count'")
289 unless $count =~ /^\+?[0-9]+$/;
291 if (not defined $plan or $plan == NO_PLAN) {
292 $plan = $count; # $plan can't be NO_PLAN anymore
295 print $TAP_STREAM "1..$plan\n";
298 @_ = ('done_testing() was already called');
300 } elsif ($plan != $count) {
301 @_ = ("planned to run $plan tests but done_testing() expects $count");
309 =head2 C<ok $ok [, $desc ]>
311 See L<Test::More/ok>.
316 my ($ok, $desc) = @_;
318 lock $plan if THREADSAFE;
322 my $test_str = "ok $test";
324 $test_str = "not $test_str";
328 _sanitize_comment($desc);
329 $test_str .= " - $desc" if length $desc;
333 print $TAP_STREAM "$test_str\n";
338 =head2 C<pass [ $desc ]>
340 See L<Test::More/pass>.
349 =head2 C<fail [ $desc ]>
351 See L<Test::More/fail>.
360 =head2 C<is $got, $expected [, $desc ]>
362 See L<Test::More/is>.
367 my ($got, $expected, $desc) = @_;
368 no warnings 'uninitialized';
370 (not(defined $got xor defined $expected) and $got eq $expected),
376 =head2 C<isnt $got, $expected [, $desc ]>
378 See L<Test::More/isnt>.
383 my ($got, $expected, $desc) = @_;
384 no warnings 'uninitialized';
386 ((defined $got xor defined $expected) or $got ne $expected),
398 ('//' => 'dor') x ($] >= 5.010),
423 ('~~' => 'smartmatch') x ($] >= 5.010),
435 '...' => 'altflipflop',
442 sub _create_binop_handler {
444 my $name = $binops{$op};
445 croak("Operator $op not supported") unless defined $name;
449 sub is_$name (\$\$;\$) {
450 my (\$got, \$expected, \$desc) = \@_;
451 \@_ = (scalar(\$got $op \$expected), \$desc);
457 $binop_handlers{$op} = do {
459 \&{__PACKAGE__."::is_$name"};
463 =head2 C<like $got, $regexp_expected [, $desc ]>
465 See L<Test::More/like>.
467 =head2 C<unlike $got, $regexp_expected, [, $desc ]>
469 See L<Test::More/unlike>.
475 *like = _create_binop_handler('=~');
476 *unlike = _create_binop_handler('!~');
479 =head2 C<cmp_ok $got, $op, $expected [, $desc ]>
481 See L<Test::More/cmp_ok>.
486 my ($got, $op, $expected, $desc) = @_;
487 my $handler = $binop_handlers{$op};
489 local $Test::More::Level = ($Test::More::Level || 0) + 1;
490 $handler = _create_binop_handler($op);
492 @_ = ($got, $expected, $desc);
496 =head2 C<is_deeply $got, $expected [, $desc ]>
498 See L<Test::More/is_deeply>.
505 no warnings qw<numeric uninitialized>;
507 return 0 if defined($x) xor defined($y);
509 # Try object identity/eq overloading first. It also covers the case where
510 # $x and $y are both undefined.
511 # If either $x or $y is overloaded but none has eq overloading, the test will
512 # break at that point.
513 return 1 if not(ref($x) xor ref($y)) and $x eq $y;
515 # Test::More::is_deeply happily breaks encapsulation if the objects aren't
517 my $ry = Scalar::Util::reftype($y);
518 return 0 if Scalar::Util::reftype($x) ne $ry;
520 # Shortcut if $x and $y are both not references and failed the previous
524 if ($ry eq 'ARRAY') {
526 # Prevent vivification of deleted elements by fetching the array values.
528 _deep_check($ex = $x->[$_], $ey = $y->[$_]) or return 0 for 0 .. $#$y;
531 } elsif ($ry eq 'HASH') {
532 if (keys(%$x) == keys(%$y)) {
533 (exists $x->{$_} and _deep_check($x->{$_}, $y->{$_}))
534 or return 0 for keys %$y;
537 } elsif ($ry eq 'SCALAR' or $ry eq 'REF') {
538 return _deep_check($$x, $$y);
557 lock $plan if THREADSAFE;
560 my $msg = join '', map { defined($_) ? $_ : 'undef' } @_;
561 _sanitize_comment($msg);
562 return unless length $msg;
565 print $fh "# $msg\n";
572 See L<Test::More/diag>.
577 unshift @_, $DIAG_STREAM;
583 See L<Test::More/note>.
588 unshift @_, $TAP_STREAM;
592 =head2 C<BAIL_OUT [ $desc ]>
594 See L<Test::More/BAIL_OUT>.
601 lock $plan if THREADSAFE;
603 my $bail_out_str = 'Bail out!';
605 _sanitize_comment($desc);
606 $bail_out_str .= " $desc" if length $desc; # Two spaces
610 print $TAP_STREAM "$bail_out_str\n";
617 lock $plan if THREADSAFE;
621 $? = $failed <= 254 ? $failed : 254;
622 } elsif ($plan >= 0) {
623 $? = $test == $plan ? 0 : 255;
624 } elsif ($plan == NO_PLAN) {
626 print $TAP_STREAM "1..$test\n";
634 L<Test::Leaner> also provides some functions of its own, which are never exported.
636 =head2 C<tap_stream [ $fh ]>
638 Read/write accessor for the filehandle to which the tests are outputted.
639 On write, it also turns autoflush on onto C<$fh>.
641 Note that it can only be used as a write accessor before you start any thread, as L<threads::shared> cannot reliably share filehandles.
643 Defaults to C<STDOUT>.
647 sub tap_stream (;*) {
651 my $fh = select $TAP_STREAM;
661 =head2 C<diag_stream [ $fh ]>
663 Read/write accessor for the filehandle to which the diagnostics are printed.
664 On write, it also turns autoflush on onto C<$fh>.
666 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.
668 Defaults to C<STDERR>.
672 sub diag_stream (;*) {
674 $DIAG_STREAM = $_[0];
676 my $fh = select $DIAG_STREAM;
688 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>.
689 In that case, it also needs a working L<threads::shared>.
695 L<Exporter>, L<Scalar::Util>, L<Test::More>.
699 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
701 You can contact me by mail or on C<irc.perl.org> (vincent).
705 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>.
706 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
710 You can find documentation for this module with the perldoc command.
714 =head1 COPYRIGHT & LICENSE
716 Copyright 2010 Vincent Pit, all rights reserved.
718 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
722 1; # End of Test::Leaner