]> git.vpit.fr Git - perl/modules/indirect.git/blob - t/lib/Test/Leaner.pm
04984d7574066ef1f7b7c93d08a5092d9153232c
[perl/modules/indirect.git] / t / lib / Test / Leaner.pm
1 package Test::Leaner;
2
3 use 5.006;
4 use strict;
5 use warnings;
6
7 =head1 NAME
8
9 Test::Leaner - A slimmer Test::More for when you favor performance over completeness.
10
11 =head1 VERSION
12
13 Version 0.05
14
15 =cut
16
17 our $VERSION = '0.05';
18
19 =head1 SYNOPSIS
20
21     use Test::Leaner tests => 10_000;
22     for (1 .. 10_000) {
23      ...
24      is $one, 1, "checking situation $_";
25     }
26
27
28 =head1 DESCRIPTION
29
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>.
31
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 :
34
35 =over 4
36
37 =item *
38
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.
41
42 =item *
43
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.
45
46 =item *
47
48 C<isn't> (the sub C<t> in package C<isn>) is not aliased to L</isnt>.
49
50 =item *
51
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>).
54
55 =item *
56
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.
59
60 =item *
61
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.
64
65 =item *
66
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>.
69
70 =item *
71
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.
73
74 =back
75
76 =cut
77
78 use Exporter ();
79
80 my $main_process;
81
82 BEGIN {
83  $main_process = $$;
84
85  if ("$]" >= 5.008 and $INC{'threads.pm'}) {
86   my $use_ithreads = do {
87    require Config;
88    no warnings 'once';
89    $Config::Config{useithreads};
90   };
91   if ($use_ithreads) {
92    require threads::shared;
93    *THREADSAFE = sub () { 1 };
94   }
95  }
96  unless (defined &Test::Leaner::THREADSAFE) {
97   *THREADSAFE = sub () { 0 }
98  }
99 }
100
101 my ($TAP_STREAM, $DIAG_STREAM);
102
103 my ($plan, $test, $failed, $no_diag, $done_testing);
104
105 our @EXPORT = qw<
106  plan
107  skip
108  done_testing
109  pass
110  fail
111  ok
112  is
113  isnt
114  like
115  unlike
116  cmp_ok
117  is_deeply
118  diag
119  note
120  BAIL_OUT
121 >;
122
123 =head1 ENVIRONMENT
124
125 =head2 C<PERL_TEST_LEANER_USES_TEST_MORE>
126
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.
130
131 This may be useful if your L<Test::Leaner>-based test script fails and you want extra diagnostics.
132
133 =cut
134
135 sub _handle_import_args {
136  my @imports;
137
138  my $i = 0;
139  while ($i <= $#_) {
140   my $item = $_[$i];
141   my $splice;
142   if (defined $item) {
143    if ($item eq 'import') {
144     push @imports, @{ $_[$i+1] };
145     $splice  = 2;
146    } elsif ($item eq 'no_diag') {
147     lock $plan if THREADSAFE;
148     $no_diag = 1;
149     $splice  = 1;
150    }
151   }
152   if ($splice) {
153    splice @_, $i, $splice;
154   } else {
155    ++$i;
156   }
157  }
158
159  return @imports;
160 }
161
162 if ($ENV{PERL_TEST_LEANER_USES_TEST_MORE}) {
163  require Test::More;
164
165  my $leaner_stash = \%Test::Leaner::;
166  my $more_stash   = \%Test::More::;
167
168  my %stubbed;
169
170  for (@EXPORT) {
171   my $replacement = exists $more_stash->{$_} ? *{$more_stash->{$_}}{CODE}
172                                              : undef;
173   unless (defined $replacement) {
174    $stubbed{$_}++;
175    $replacement = sub {
176     @_ = ("$_ is not implemented in this version of Test::More");
177     goto &croak;
178    };
179   }
180   no warnings 'redefine';
181   $leaner_stash->{$_} = $replacement;
182  }
183
184  my $import = sub {
185   my $class = shift;
186
187   my @imports = &_handle_import_args;
188   if (@imports == grep /^!/, @imports) {
189    # All imports are negated, or @imports is empty
190    my %negated;
191    /^!(.*)/ and ++$negated{$1} for @imports;
192    push @imports, grep !$negated{$_}, @EXPORT;
193   }
194
195   my @test_more_imports;
196   for (@imports) {
197    if ($stubbed{$_}) {
198     my $pkg = caller;
199     no strict 'refs';
200     *{$pkg."::$_"} = $leaner_stash->{$_};
201    } elsif (/^!/ or !exists $more_stash->{$_} or exists $leaner_stash->{$_}) {
202     push @test_more_imports, $_;
203    } else {
204     # Croak for symbols in Test::More but not in Test::Leaner
205     Exporter::import($class, $_);
206    }
207   }
208
209   my $test_more_import = 'Test::More'->can('import');
210   return unless $test_more_import;
211
212   @_ = (
213    'Test::More',
214    @_,
215    import => \@test_more_imports,
216   );
217   {
218    lock $plan if THREADSAFE;
219    push @_, 'no_diag' if $no_diag;
220   }
221
222   goto $test_more_import;
223  };
224
225  no warnings 'redefine';
226  *import = $import;
227
228  return 1;
229 }
230
231 sub NO_PLAN  () { -1 }
232 sub SKIP_ALL () { -2 }
233
234 BEGIN {
235  if (THREADSAFE) {
236   threads::shared::share($_) for $plan, $test, $failed, $no_diag, $done_testing;
237  }
238
239  lock $plan if THREADSAFE;
240
241  $plan   = undef;
242  $test   = 0;
243  $failed = 0;
244 }
245
246 sub carp {
247  my $level = 1 + ($Test::Builder::Level || 0);
248  my @caller;
249  do {
250   @caller = caller $level--;
251  } while (!@caller and $level >= 0);
252  my ($file, $line) = @caller[1, 2];
253  warn @_, " at $file line $line.\n";
254 }
255
256 sub croak {
257  my $level = 1 + ($Test::Builder::Level || 0);
258  my @caller;
259  do {
260   @caller = caller $level--;
261  } while (!@caller and $level >= 0);
262  my ($file, $line) = @caller[1, 2];
263  die @_, " at $file line $line.\n";
264 }
265
266 sub _sanitize_comment {
267  $_[0] =~ s/\n+\z//;
268  $_[0] =~ s/#/\\#/g;
269  $_[0] =~ s/\n/\n# /g;
270 }
271
272 =head1 FUNCTIONS
273
274 The following functions from L<Test::More> are implemented and exported by default.
275
276 =head2 C<plan>
277
278     plan tests => $count;
279     plan 'no_plan';
280     plan skip_all => $reason;
281
282 See L<Test::More/plan>.
283
284 =cut
285
286 sub plan {
287  my ($key, $value) = @_;
288
289  return unless $key;
290
291  lock $plan if THREADSAFE;
292
293  croak("You tried to plan twice") if defined $plan;
294
295  my $plan_str;
296
297  if ($key eq 'no_plan') {
298   croak("no_plan takes no arguments") if $value;
299   $plan       = NO_PLAN;
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]+$/;
305   $plan       = $value;
306   $plan_str   = "1..$value";
307  } elsif ($key eq 'skip_all') {
308   $plan       = SKIP_ALL;
309   $plan_str   = '1..0 # SKIP';
310   if (defined $value) {
311    _sanitize_comment($value);
312    $plan_str .= " $value" if length $value;
313   }
314  } else {
315   my @args = grep defined, $key, $value;
316   croak("plan() doesn't understand @args");
317  }
318
319  if (defined $plan_str) {
320   local $\;
321   print $TAP_STREAM "$plan_str\n";
322  }
323
324  exit 0 if $plan == SKIP_ALL;
325
326  return 1;
327 }
328
329 sub import {
330  my $class = shift;
331
332  my @imports = &_handle_import_args;
333
334  if (@_) {
335   local $Test::Builder::Level = ($Test::Builder::Level || 0) + 1;
336   &plan;
337  }
338
339  @_ = ($class, @imports);
340  goto &Exporter::import;
341 }
342
343 =head2 C<skip>
344
345     skip $reason => $count;
346
347 See L<Test::More/skip>.
348
349 =cut
350
351 sub skip {
352  my ($reason, $count) = @_;
353
354  lock $plan if THREADSAFE;
355
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;
359   $count = 1;
360  } elsif ($count =~ /[^0-9]/) {
361   carp('skip() was passed a non-numeric number of tests.  Did you get the arguments backwards?');
362   $count = 1;
363  }
364
365  for (1 .. $count) {
366   ++$test;
367
368   my $skip_str = "ok $test # skip";
369   if (defined $reason) {
370    _sanitize_comment($reason);
371    $skip_str  .= " $reason" if length $reason;
372   }
373
374   local $\;
375   print $TAP_STREAM "$skip_str\n";
376  }
377
378  no warnings 'exiting';
379  last SKIP;
380 }
381
382 =head2 C<done_testing>
383
384     done_testing;
385     done_testing $count;
386
387 See L<Test::More/done_testing>.
388
389 =cut
390
391 sub done_testing {
392  my ($count) = @_;
393
394  lock $plan if THREADSAFE;
395
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]+$/;
399
400  if (not defined $plan or $plan == NO_PLAN) {
401   $plan         = $count; # $plan can't be NO_PLAN anymore
402   $done_testing = 1;
403   local $\;
404   print $TAP_STREAM "1..$plan\n";
405  } else {
406   if ($done_testing) {
407    @_ = ('done_testing() was already called');
408    goto &fail;
409   } elsif ($plan != $count) {
410    @_ = ("planned to run $plan tests but done_testing() expects $count");
411    goto &fail;
412   }
413  }
414
415  return 1;
416 }
417
418 =head2 C<ok>
419
420     ok $ok;
421     ok $ok, $desc;
422
423 See L<Test::More/ok>.
424
425 =cut
426
427 sub ok ($;$) {
428  my ($ok, $desc) = @_;
429
430  lock $plan if THREADSAFE;
431
432  ++$test;
433
434  my $test_str = "ok $test";
435  $ok or do {
436   $test_str   = "not $test_str";
437   ++$failed;
438  };
439  if (defined $desc) {
440   _sanitize_comment($desc);
441   $test_str .= " - $desc" if length $desc;
442  }
443
444  local $\;
445  print $TAP_STREAM "$test_str\n";
446
447  return $ok;
448 }
449
450 =head2 C<pass>
451
452     pass;
453     pass $desc;
454
455 See L<Test::More/pass>.
456
457 =cut
458
459 sub pass (;$) {
460  unshift @_, 1;
461  goto &ok;
462 }
463
464 =head2 C<fail>
465
466     fail;
467     fail $desc;
468
469 See L<Test::More/fail>.
470
471 =cut
472
473 sub fail (;$) {
474  unshift @_, 0;
475  goto &ok;
476 }
477
478 =head2 C<is>
479
480     is $got, $expected;
481     is $got, $expected, $desc;
482
483 See L<Test::More/is>.
484
485 =cut
486
487 sub is ($$;$) {
488  my ($got, $expected, $desc) = @_;
489  no warnings 'uninitialized';
490  @_ = (
491   (not(defined $got xor defined $expected) and $got eq $expected),
492   $desc,
493  );
494  goto &ok;
495 }
496
497 =head2 C<isnt>
498
499     isnt $got, $expected;
500     isnt $got, $expected, $desc;
501
502 See L<Test::More/isnt>.
503
504 =cut
505
506 sub isnt ($$;$) {
507  my ($got, $expected, $desc) = @_;
508  no warnings 'uninitialized';
509  @_ = (
510   ((defined $got xor defined $expected) or $got ne $expected),
511   $desc,
512  );
513  goto &ok;
514 }
515
516 my %binops = (
517  'or'  => 'or',
518  'xor' => 'xor',
519  'and' => 'and',
520
521  '||'  => 'hor',
522  ('//' => 'dor') x ("$]" >= 5.010),
523  '&&'  => 'hand',
524
525  '|'   => 'bor',
526  '^'   => 'bxor',
527  '&'   => 'band',
528
529  'lt'  => 'lt',
530  'le'  => 'le',
531  'gt'  => 'gt',
532  'ge'  => 'ge',
533  'eq'  => 'eq',
534  'ne'  => 'ne',
535  'cmp' => 'cmp',
536
537  '<'   => 'nlt',
538  '<='  => 'nle',
539  '>'   => 'ngt',
540  '>='  => 'nge',
541  '=='  => 'neq',
542  '!='  => 'nne',
543  '<=>' => 'ncmp',
544
545  '=~'  => 'like',
546  '!~'  => 'unlike',
547  ('~~' => 'smartmatch') x ("$]" >= 5.010),
548
549  '+'   => 'add',
550  '-'   => 'substract',
551  '*'   => 'multiply',
552  '/'   => 'divide',
553  '%'   => 'modulo',
554  '<<'  => 'lshift',
555  '>>'  => 'rshift',
556
557  '.'   => 'concat',
558  '..'  => 'flipflop',
559  '...' => 'altflipflop',
560  ','   => 'comma',
561  '=>'  => 'fatcomma',
562 );
563
564 my %binop_handlers;
565
566 sub _create_binop_handler {
567  my ($op) = @_;
568  my $name = $binops{$op};
569  croak("Operator $op not supported") unless defined $name;
570  {
571   local $@;
572   eval <<"IS_BINOP";
573 sub is_$name (\$\$;\$) {
574  my (\$got, \$expected, \$desc) = \@_;
575  \@_ = (scalar(\$got $op \$expected), \$desc);
576  goto &ok;
577 }
578 IS_BINOP
579   die $@ if $@;
580  }
581  $binop_handlers{$op} = do {
582   no strict 'refs';
583   \&{__PACKAGE__."::is_$name"};
584  }
585 }
586
587 =head2 C<like>
588
589     like $got, $regexp_expected;
590     like $got, $regexp_expected, $desc;
591
592 See L<Test::More/like>.
593
594 =head2 C<unlike>
595
596     unlike $got, $regexp_expected;
597     unlike $got, $regexp_expected, $desc;
598
599 See L<Test::More/unlike>.
600
601 =cut
602
603 {
604  no warnings 'once';
605  *like   = _create_binop_handler('=~');
606  *unlike = _create_binop_handler('!~');
607 }
608
609 =head2 C<cmp_ok>
610
611     cmp_ok $got, $op, $expected;
612     cmp_ok $got, $op, $expected, $desc;
613
614 See L<Test::More/cmp_ok>.
615
616 =cut
617
618 sub cmp_ok ($$$;$) {
619  my ($got, $op, $expected, $desc) = @_;
620  my $handler = $binop_handlers{$op};
621  unless ($handler) {
622   local $Test::More::Level = ($Test::More::Level || 0) + 1;
623   $handler = _create_binop_handler($op);
624  }
625  @_ = ($got, $expected, $desc);
626  goto $handler;
627 }
628
629 =head2 C<is_deeply>
630
631     is_deeply $got, $expected;
632     is_deeply $got, $expected, $desc;
633
634 See L<Test::More/is_deeply>.
635
636 =cut
637
638 BEGIN {
639  local $@;
640  if (eval { require Scalar::Util; 1 }) {
641   *_reftype = \&Scalar::Util::reftype;
642  } else {
643   # Stolen from Scalar::Util::PP
644   require B;
645   my %tmap = qw<
646    B::NULL   SCALAR
647
648    B::HV     HASH
649    B::AV     ARRAY
650    B::CV     CODE
651    B::IO     IO
652    B::GV     GLOB
653    B::REGEXP REGEXP
654   >;
655   *_reftype = sub ($) {
656    my $r = shift;
657
658    return undef unless length ref $r;
659
660    my $t = ref B::svref_2object($r);
661
662    return exists $tmap{$t} ? $tmap{$t}
663                            : length ref $$r ? 'REF'
664                                             : 'SCALAR'
665   }
666  }
667 }
668
669 sub _deep_ref_check {
670  my ($x, $y, $ry) = @_;
671
672  no warnings qw<numeric uninitialized>;
673
674  if ($ry eq 'ARRAY') {
675   return 0 unless $#$x == $#$y;
676
677   my ($ex, $ey);
678   for (0 .. $#$y) {
679    $ex = $x->[$_];
680    $ey = $y->[$_];
681
682    # Inline the beginning of _deep_check
683    return 0 if defined $ex xor defined $ey;
684
685    next if not(ref $ex xor ref $ey) and $ex eq $ey;
686
687    $ry = _reftype($ey);
688    return 0 if _reftype($ex) ne $ry;
689
690    return 0 unless $ry and _deep_ref_check($ex, $ey, $ry);
691   }
692
693   return 1;
694  } elsif ($ry eq 'HASH') {
695   return 0 unless keys(%$x) == keys(%$y);
696
697   my ($ex, $ey);
698   for (keys %$y) {
699    return 0 unless exists $x->{$_};
700    $ex = $x->{$_};
701    $ey = $y->{$_};
702
703    # Inline the beginning of _deep_check
704    return 0 if defined $ex xor defined $ey;
705
706    next if not(ref $ex xor ref $ey) and $ex eq $ey;
707
708    $ry = _reftype($ey);
709    return 0 if _reftype($ex) ne $ry;
710
711    return 0 unless $ry and _deep_ref_check($ex, $ey, $ry);
712   }
713
714   return 1;
715  } elsif ($ry eq 'SCALAR' or $ry eq 'REF') {
716   return _deep_check($$x, $$y);
717  }
718
719  return 0;
720 }
721
722 sub _deep_check {
723  my ($x, $y) = @_;
724
725  no warnings qw<numeric uninitialized>;
726
727  return 0 if defined $x xor defined $y;
728
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;
734
735  # Test::More::is_deeply happily breaks encapsulation if the objects aren't
736  # overloaded.
737  my $ry = _reftype($y);
738  return 0 if _reftype($x) ne $ry;
739
740  # Shortcut if $x and $y are both not references and failed the previous
741  # $x eq $y test.
742  return 0 unless $ry;
743
744  # We know that $x and $y are both references of type $ry, without overloading.
745  _deep_ref_check($x, $y, $ry);
746 }
747
748 sub is_deeply {
749  @_ = (
750   &_deep_check,
751   $_[2],
752  );
753  goto &ok;
754 }
755
756 sub _diag_fh {
757  my $fh = shift;
758
759  return unless @_;
760
761  lock $plan if THREADSAFE;
762  return if $no_diag;
763
764  my $msg = join '', map { defined($_) ? $_ : 'undef' } @_;
765  _sanitize_comment($msg);
766  return unless length $msg;
767
768  local $\;
769  print $fh "# $msg\n";
770
771  return 0;
772 };
773
774 =head2 C<diag>
775
776     diag @lines;
777
778 See L<Test::More/diag>.
779
780 =cut
781
782 sub diag {
783  unshift @_, $DIAG_STREAM;
784  goto &_diag_fh;
785 }
786
787 =head2 C<note>
788
789     note @lines;
790
791 See L<Test::More/note>.
792
793 =cut
794
795 sub note {
796  unshift @_, $TAP_STREAM;
797  goto &_diag_fh;
798 }
799
800 =head2 C<BAIL_OUT>
801
802     BAIL_OUT;
803     BAIL_OUT $desc;
804
805 See L<Test::More/BAIL_OUT>.
806
807 =cut
808
809 sub BAIL_OUT {
810  my ($desc) = @_;
811
812  lock $plan if THREADSAFE;
813
814  my $bail_out_str = 'Bail out!';
815  if (defined $desc) {
816   _sanitize_comment($desc);
817   $bail_out_str  .= "  $desc" if length $desc; # Two spaces
818  }
819
820  local $\;
821  print $TAP_STREAM "$bail_out_str\n";
822
823  exit 255;
824 }
825
826 END {
827  if ($main_process == $$ and not $?) {
828   lock $plan if THREADSAFE;
829
830   if (defined $plan) {
831    if ($failed) {
832     $? = $failed <= 254 ? $failed : 254;
833    } elsif ($plan >= 0) {
834     $? = $test == $plan ? 0 : 255;
835    }
836    if ($plan == NO_PLAN) {
837     local $\;
838     print $TAP_STREAM "1..$test\n";
839    }
840   }
841  }
842 }
843
844 =pod
845
846 L<Test::Leaner> also provides some functions of its own, which are never exported.
847
848 =head2 C<tap_stream>
849
850     my $tap_fh = tap_stream;
851     tap_stream $fh;
852
853 Read/write accessor for the filehandle to which the tests are outputted.
854 On write, it also turns autoflush on onto C<$fh>.
855
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.
857
858 Defaults to C<STDOUT>.
859
860 =cut
861
862 sub tap_stream (;*) {
863  if (@_) {
864   $TAP_STREAM = $_[0];
865
866   my $fh = select $TAP_STREAM;
867   $|++;
868   select $fh;
869  }
870
871  return $TAP_STREAM;
872 }
873
874 tap_stream *STDOUT;
875
876 =head2 C<diag_stream>
877
878     my $diag_fh = diag_stream;
879     diag_stream $fh;
880
881 Read/write accessor for the filehandle to which the diagnostics are printed.
882 On write, it also turns autoflush on onto C<$fh>.
883
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.
885
886 Defaults to C<STDERR>.
887
888 =cut
889
890 sub diag_stream (;*) {
891  if (@_) {
892   $DIAG_STREAM = $_[0];
893
894   my $fh = select $DIAG_STREAM;
895   $|++;
896   select $fh;
897  }
898
899  return $DIAG_STREAM;
900 }
901
902 diag_stream *STDERR;
903
904 =head2 C<THREADSAFE>
905
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>.
908
909 =head1 DEPENDENCIES
910
911 L<perl> 5.6.
912
913 L<Exporter>, L<Test::More>.
914
915 =head1 AUTHOR
916
917 Vincent Pit C<< <vpit at cpan.org> >>.
918
919 You can contact me by mail or on C<irc.perl.org> (vincent).
920
921 =head1 BUGS
922
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.
925
926 =head1 SUPPORT
927
928 You can find documentation for this module with the perldoc command.
929
930     perldoc Test::Leaner
931
932 =head1 COPYRIGHT & LICENSE
933
934 Copyright 2010,2011,2013,2019 Vincent Pit, all rights reserved.
935
936 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
937
938 Except for the fallback implementation of the internal C<_reftype> function, which has been taken from L<Scalar::Util> and is
939
940 Copyright 1997-2007 Graham Barr, all rights reserved.
941
942 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
943
944 =cut
945
946 1; # End of Test::Leaner