Permalink
Browse files

The real Version 0.50

  • Loading branch information...
1 parent 9ec3efa commit 5d279804775b6d60a61c9ca9dc56d2c5c722c387 @schwern schwern committed Nov 20, 2004
Showing with 7,302 additions and 0 deletions.
  1. +258 −0 trunk/Changes
  2. +69 −0 trunk/MANIFEST
  3. +27 −0 trunk/MANIFEST.SKIP
  4. +107 −0 trunk/Makefile.PL
  5. +24 −0 trunk/README
  6. +37 −0 trunk/TODO
  7. +1,499 −0 trunk/lib/Test/Builder.pm
  8. +253 −0 trunk/lib/Test/FAQ.pod
  9. +1,330 −0 trunk/lib/Test/More.pm
  10. +235 −0 trunk/lib/Test/Simple.pm
  11. +603 −0 trunk/lib/Test/Tutorial.pod
  12. +24 −0 trunk/t/00test_harness_check.t
  13. +30 −0 trunk/t/Builder.t
  14. +153 −0 trunk/t/More.t
  15. +38 −0 trunk/t/bad_plan.t
  16. +22 −0 trunk/t/buffer.t
  17. +11 −0 trunk/t/curr_test.t
  18. +93 −0 trunk/t/details.t
  19. +73 −0 trunk/t/diag.t
  20. +21 −0 trunk/t/eq_set.t
  21. +103 −0 trunk/t/exit.t
  22. +65 −0 trunk/t/extra.t
  23. +59 −0 trunk/t/extra_one.t
  24. +74 −0 trunk/t/fail-like.t
  25. +270 −0 trunk/t/fail-more.t
  26. +70 −0 trunk/t/fail.t
  27. +62 −0 trunk/t/fail_one.t
  28. +21 −0 trunk/t/filehandles.t
  29. +25 −0 trunk/t/fork.t
  30. +99 −0 trunk/t/harness_active.t
  31. +23 −0 trunk/t/has_plan.t
  32. +34 −0 trunk/t/has_plan2.t
  33. +12 −0 trunk/t/import.t
  34. +236 −0 trunk/t/is_deeply.t
  35. +10 −0 trunk/t/lib/NoExporter.pm
  36. +18 −0 trunk/t/lib/Test/Simple/Catch.pm
  37. +13 −0 trunk/t/lib/Test/Simple/sample_tests/death.plx
  38. +22 −0 trunk/t/lib/Test/Simple/sample_tests/death_in_eval.plx
  39. +16 −0 trunk/t/lib/Test/Simple/sample_tests/extras.plx
  40. +13 −0 trunk/t/lib/Test/Simple/sample_tests/five_fail.plx
  41. +16 −0 trunk/t/lib/Test/Simple/sample_tests/last_minute_death.plx
  42. +14 −0 trunk/t/lib/Test/Simple/sample_tests/one_fail.plx
  43. +17 −0 trunk/t/lib/Test/Simple/sample_tests/pre_plan_death.plx
  44. +1 −0 trunk/t/lib/Test/Simple/sample_tests/require.plx
  45. +13 −0 trunk/t/lib/Test/Simple/sample_tests/success.plx
  46. +11 −0 trunk/t/lib/Test/Simple/sample_tests/too_few.plx
  47. +14 −0 trunk/t/lib/Test/Simple/sample_tests/two_fail.plx
  48. +26 −0 trunk/t/lib/TieOut.pm
  49. +50 −0 trunk/t/maybe_regex.t
  50. +57 −0 trunk/t/missing.t
  51. +6 −0 trunk/t/no_diag.t
  52. +21 −0 trunk/t/no_ending.t
  53. +21 −0 trunk/t/no_header.t
  54. +73 −0 trunk/t/no_plan.t
  55. +29 −0 trunk/t/ok_obj.t
  56. +95 −0 trunk/t/output.t
  57. +53 −0 trunk/t/overload.t
  58. +19 −0 trunk/t/plan.t
  59. +54 −0 trunk/t/plan_is_noplan.t
  60. +31 −0 trunk/t/plan_no_plan.t
  61. +12 −0 trunk/t/plan_skip_all.t
  62. +84 −0 trunk/t/reset.t
  63. +17 −0 trunk/t/simple.t
  64. +86 −0 trunk/t/skip.t
  65. +44 −0 trunk/t/skipall.t
  66. +41 −0 trunk/t/strays.t
  67. +5 −0 trunk/t/thread_taint.t
  68. +33 −0 trunk/t/threads.t
  69. +68 −0 trunk/t/todo.t
  70. +60 −0 trunk/t/undef.t
  71. +60 −0 trunk/t/use_ok.t
  72. +19 −0 trunk/t/useing.t
View
258 trunk/Changes
@@ -0,0 +1,258 @@
+0.50 Sat Nov 20 00:28:44 EST 2004
+ * Fixed bug in fail-more test on Windows (not a real bug).
+ [rt.cpan.org 8022]
+ - Change from CVS to SVK. Hopefully this is the last version control
+ system change.
+ - Again removing File::Spec dependency (came back in 0.48_02)
+ - Change from Aegis back to CVS
+
+0.49 Thu Oct 14 21:58:50 EDT 2004
+ - t/harness_active.t would fail for frivolous reasons with older
+ MakeMakers (test bug) [thanks Bill Moseley for noticing]
+
+0.48_02 Mon Jul 19 02:07:23 EDT 2004
+ * Overloaded objects as names now won't blow up under threads
+ [rt.cpan.org 4218 and 4232]
+ * Overloaded objects which stringify to undef used as test names
+ now won't cause internal uninit warnings. [rt.cpan.org 4232]
+ * Failure diagnostics now come out on their own line when run in
+ Test::Harness.
+ - eq_set() sometimes wasn't giving the right results if nested refs
+ were involved [rt.cpan.org 3747]
+ - isnt() giving wrong diagnostics and warning if given any undefs.
+ * Give unlike() the right prototype [rt.cpan.org 4944]
+ - Change from CVS to Aegis
+ - is_deeply() will now do some basic argument checks to guard against
+ accidentally passing in a whole array instead of its reference.
+ - Mentioning Test::Differences, Test::Deep and Bundle::Test.
+ - Removed dependency on File::Spec.
+ - Fixing the grammar of diagnostic outputs when only a single test
+ is run or failed (ie. "Looks like you failed 1 tests").
+ [Darren Chamberlain]
+
+0.48_01 Mon Nov 11 02:36:43 EST 2002
+ - Mention Test::Class in Test::More's SEE ALSO
+ * use_ok() now DWIM for version checks
+ - More problems with ithreads fixed.
+ * Test::Harness upgrade no longer optional. It was causing too
+ many problems when the T::H upgrade didn't work.
+ * Drew Taylor added a 'no_diag' option to Test::More to switch
+ off all diag() statements.
+ * Test::Builder/More no longer automatically loads threads.pm
+ when threads are enabled. The user must now do this manually.
+ * Alex Francis added reset() reset the state of Test::Builder in
+ persistent environments.
+ - David Hand noted that Test::Builder/More exit code behavior was
+ not documented. Only Test::Simple.
+
+0.47 Mon Aug 26 03:54:22 PDT 2002
+ * Tatsuhiko Miyagawa noticed Test::Builder was accidentally storing
+ objects passed into test functions causing problems with tests
+ relying on object destruction.
+ - Added example of calculating the number of tests to Test::Tutorial
+ - Peter Scott made the ending logic not fire on child processes when
+ forking.
+ * Test::Builder is once again ithread safe.
+
+0.46 Sat Jul 20 19:57:40 EDT 2002
+ - Noted eq_set() isn't really a set comparision.
+ - Test fix, exit codes are broken on MacPerl (bleadperl@16868)
+ - Make Test::Simple install itself into the core for >= 5.8
+ - Small fixes to Test::Tutorial and skip examples
+ * Added TB->has_plan() from Adrian Howard
+ - Clarified the meaning of 'actual_ok' from TB->details
+ * Added TB->details() from chromatic
+ - Neil Watkiss fixed a pre-5.8 test glitch with threads.t
+ * If the test died before a plan, it would exit with 0 [ID 20020716.013]
+
+0.45 Wed Jun 19 18:41:12 EDT 2002
+ - Andy Lester made the SKIP & TODO docs a bit clearer.
+ - Explicitly disallowing double plans. (RT #553)
+ - Kicking up the minimum version of Test::Harness to one that's
+ fairly bug free.
+ - Made clear a common problem with use_ok and BEGIN blocks.
+ - Arthur Bergman made Test::Builder thread-safe.
+
+0.44 Thu Apr 25 00:27:27 EDT 2002
+ - names containing newlines no longer produce confusing output
+ (from chromatic)
+ - chromatic provided a fix so can_ok() honors can() overrides.
+ - Nick Ing-Simmons suggested todo_skip() be a bit clearer about
+ the skipping part.
+ - Making plan() vomit if it gets something it doesn't understand.
+ - Tatsuhiko Miyagawa fixed use_ok() with pragmata on older perls.
+ - quieting diag(undef)
+
+0.43 Thu Apr 11 22:55:23 EDT 2002
+ - Adrian Howard added TB->maybe_regex()
+ - Adding Mark Fowler's suggestion to make diag() return
+ false.
+ - TB->current_test() still not working when no tests were run via
+ TB itself. Fixed by Dave Rolsky.
+
+0.42 Wed Mar 6 15:00:24 EST 2002
+ - Setting Test::Builder->current_test() now works (see what happens
+ when you forget to test things?)
+ - The change in is()'s undef/'' handling in 0.34 was an API change,
+ but I forgot to declare it as such.
+ - The apostrophilic jihad attacks! Philip Newtons patch for
+ grammar mistakes in the doc's.
+
+0.41 Mon Dec 17 22:45:20 EST 2001
+ * chromatic added diag()
+ - Internal eval()'s sometimes interfering with $@ and $!. Fixed.
+
+0.40 Fri Dec 14 15:41:39 EST 2001
+ * isa_ok() now accepts unblessed references gracefully
+ - Nick Clark found a bug with like() and a regex with % in it.
+ - exit.t was hanging on 5.005_03 VMS perl. Test now skipped.
+ - can_ok() would pass if no methods were given. Now fails.
+ - isnt() diagnostic output format changed
+ * Added some docs about embedding and extending Test::More
+ * Added Test::More->builder
+ * Added cmp_ok()
+ * Added todo_skip()
+ * Added unlike()
+ - Piers pointed out that sometimes people override isa().
+ isa_ok() now accounts for that.
+
+0.36 Thu Nov 29 14:07:39 EST 2001
+ - Matthias Urlichs found that intermixed prints to STDOUT and test
+ output came out in the wrong order when piped.
+
+0.35 Tue Nov 27 19:57:03 EST 2001
+ - Little glitch in the test suite. No actual bug.
+
+0.34 Tue Nov 27 15:43:56 EST 2001
+ * **API CHANGE** Empty string no longer matches undef in is()
+ and isnt().
+ * Added isnt_eq and isnt_num to Test::Builder.
+
+0.33 Mon Oct 22 21:05:47 EDT 2001
+ * It's now officially safe to redirect STDOUT and STDERR without
+ affecting test output.
+ - License and POD cleanup by Autrijus Tang
+ - Synched up Test::Tutorial with the wiki version
+ - Minor VMS test nit.
+
+0.32 Tue Oct 16 16:52:02 EDT 2001
+ * Finally added a seperate plan() function
+ * Adding a name field to isa_ok()
+ (Requested by Dave Rolsky)
+ - Test::More was using Carp.pm, causing the occasional false positive.
+ (Reported by Tatsuhiko Miyagawa)
+
+0.31 Mon Oct 8 19:24:53 EDT 2001
+ * Added an import option to Test::More
+ * Added no_ending and no_header options to Test::Builder
+ (Thanks to Dave Rolsky for giving this a swift kick in the ass)
+ * Added is_deeply(). Display of scalar refs not quite 100%
+ (Thanks to Stas Bekman for Apache::TestUtil idea thievery)
+ - Fixed a minor warning with skip()
+ (Thanks to Wolfgang Weisselberg for finding this one)
+
+0.30 Thu Sep 27 22:10:04 EDT 2001
+ * Added Test::Builder
+ (Thanks muchly to chromatic for getting this off the ground!)
+ * Diagnostics are back to using STDERR *unless* it's from a todo
+ test. Those go to STDOUT.
+ - Fixed it so nothing is printed if a test is run with a -c flag.
+ Handy when a test is being deparsed with B::Deparse.
+
+0.20 *UNRELEASED*
+
+0.19 Tue Sep 18 17:48:32 EDT 2001
+ * Test::Simple and Test::More no longer print their diagnostics
+ to STDERR. It instead goes to STDOUT.
+ * TODO tests which fail now print full failure diagnostics.
+ - Minor bug in ok()'s test name diagnostics made it think a blank
+ name was a number.
+ - ok() less draconian about test names
+ - Added temporary special case for Parrot::Test
+ - Now requiring File::Spec for our tests.
+
+0.18 Wed Sep 5 20:35:24 EDT 2001
+ * ***API CHANGE*** can_ok() only counts as one test
+ - can_ok() has better diagnostics
+ - Minor POD fixes from mjd
+ - adjusting the internal layout to make it easier to put it into
+ the core
+
+0.17 Wed Aug 29 20:16:28 EDT 2001
+ * Added can_ok() and isa_ok() to Test::More
+
+0.16 Tue Aug 28 19:52:11 EDT 2001
+ * vmsperl foiled my sensisble exit codes. Reverting to a much more
+ coarse scheme.
+
+0.15 Tue Aug 28 06:18:35 EDT 2001 *UNRELEASED*
+ * Now using sensible exit codes on VMS.
+
+0.14 Wed Aug 22 17:26:28 EDT 2001
+ * Added a first cut at Test::Tutorial
+
+0.13 Tue Aug 14 15:30:10 EDT 2001
+ * Added a reason to the skip_all interface
+ - Fixed a bug to allow 'use Test::More;' to work.
+ (Thanks to Tatsuhiko Miyagawa again)
+ - Now always testing backwards compatibility.
+
+0.12 Tue Aug 14 11:02:39 EDT 2001
+ * Fixed some compatibility bugs with older Perls
+ (Thanks to Tatsuhiko Miyagawa)
+
+0.11 Sat Aug 11 23:05:19 EDT 2001
+ * Will no longer warn about testing undef values
+ - Escaping # in test names
+ - Ensuring that ok() returns true or false and not undef
+ - Minor doc typo in the example
+
+0.10 Tue Jul 31 15:01:11 EDT 2001
+ * Test::More is now distributed in this tarball.
+ * skip and todo tests work!
+ * Extended use_ok() so it can import
+ - A little internal rejiggering
+ - Added a TODO file
+
+0.09 Wed Jun 27 02:55:54 EDT 2001
+ - VMS fixes
+
+0.08 Fri Jun 15 14:39:50 EDT 2001
+ - Guarding against $/ and -l
+ - Reformatted the way failed tests are reported to make them stand out
+ a bit better.
+
+0.07 Tue Jun 12 15:55:54 BST 2001
+ - 'use Test::Simple' by itself no longer causes death
+ - Yet more fixes for death in eval
+ - Limiting max failures reported via exit code to 254.
+
+0.06 Wed May 9 23:38:17 BST 2001
+ - Whoops, left a private method in the public docs.
+
+0.05 Wed May 9 20:40:35 BST 2001
+ - Forgot to include the exit tests.
+ - Trouble with exiting properly under 5.005_03 and 5.6.1 fixed
+ - Turned off buffering
+ * 5.004 new minimum version
+ - Now explicitly tested with 5.6.1, 5.6.0, 5.005_03 and 5.004
+
+0.04 Mon Apr 2 11:05:01 BST 2001
+ - Fixed "require Test::Simple" so it doesn't bitch and exit 255
+ - Now installable with the CPAN shell.
+
+0.03 Fri Mar 30 08:08:33 BST 2001
+ - ok() now prints on what line and file it failed.
+ - eval 'die' was considered abnormal. Fixed.
+
+0.02 Fri Mar 30 05:12:14 BST 2001 *UNRELEASED*
+ - exit codes tested
+ * exit code on abnormal exit changed to 255 (thanks to Tim Bunce for
+ pointing out that Unix can't do negative exit codes)
+ - abnormal exits now better caught.
+ - No longer using Test.pm to test this, but still minimum of 5.005
+ due to needing $^S.
+
+0.01 Wed Mar 28 06:44:44 BST 2001
+ - First working version released to CPAN
+
View
69 trunk/MANIFEST
@@ -0,0 +1,69 @@
+Changes
+lib/Test/Builder.pm
+lib/Test/More.pm
+lib/Test/Simple.pm
+lib/Test/Tutorial.pod
+Makefile.PL
+MANIFEST
+README
+t/00test_harness_check.t
+t/bad_plan.t
+t/buffer.t
+t/Builder.t
+t/curr_test.t
+t/details.t
+t/diag.t
+t/eq_set.t
+t/exit.t
+t/extra.t
+t/extra_one.t
+t/fail-like.t
+t/fail-more.t
+t/fail.t
+t/fail_one.t
+t/filehandles.t
+t/fork.t
+t/harness_active.t
+t/has_plan.t
+t/has_plan2.t
+t/import.t
+t/is_deeply.t
+t/lib/NoExporter.pm
+t/lib/Test/Simple/Catch.pm
+t/lib/Test/Simple/sample_tests/death.plx
+t/lib/Test/Simple/sample_tests/death_in_eval.plx
+t/lib/Test/Simple/sample_tests/extras.plx
+t/lib/Test/Simple/sample_tests/five_fail.plx
+t/lib/Test/Simple/sample_tests/last_minute_death.plx
+t/lib/Test/Simple/sample_tests/one_fail.plx
+t/lib/Test/Simple/sample_tests/pre_plan_death.plx
+t/lib/Test/Simple/sample_tests/require.plx
+t/lib/Test/Simple/sample_tests/success.plx
+t/lib/Test/Simple/sample_tests/too_few.plx
+t/lib/Test/Simple/sample_tests/two_fail.plx
+t/lib/TieOut.pm
+t/maybe_regex.t
+t/missing.t
+t/More.t
+t/no_diag.t
+t/no_ending.t
+t/no_header.t
+t/no_plan.t
+t/ok_obj.t
+t/output.t
+t/overload.t
+t/plan.t
+t/plan_is_noplan.t
+t/plan_no_plan.t
+t/plan_skip_all.t
+t/reset.t
+t/simple.t
+t/skip.t
+t/skipall.t
+t/thread_taint.t
+t/threads.t
+t/todo.t
+t/undef.t
+t/use_ok.t
+t/useing.t
+TODO
View
27 trunk/MANIFEST.SKIP
@@ -0,0 +1,27 @@
+# Avoid version control files.
+\bRCS\b
+\bCVS\b
+,\w$
+
+# Avoid Makemaker generated and utility files.
+^MANIFEST\.
+^Makefile$
+^blib/
+^MakeMaker-\d
+^pm_to_blib$
+\.ts$
+
+# Avoid temp and backup files.
+~$
+\.old$
+\#$
+^\.#
+
+# Avoid this one test that doesn't work yet
+^t/strays.t
+
+# Don't distribute Test::Harness
+^t/lib/Test/Harness
+
+# Test::FAQ is not complete.
+^lib/Test/FAQ
View
107 trunk/Makefile.PL
@@ -0,0 +1,107 @@
+# A template for Makefile.PL used by Arena Networks.
+# - Set the $PACKAGE variable to the name of your module.
+# - Set $LAST_API_CHANGE to reflect the last version you changed the API
+# of your module.
+# - Fill in your dependencies in PREREQ_PM
+# Alternatively, you can say the hell with this and use h2xs.
+
+use 5.004;
+
+use Config;
+use ExtUtils::MakeMaker;
+
+$PACKAGE = 'Test::Simple';
+($PACKAGE_FILE = $PACKAGE) =~ s|::|/|g;
+$LAST_API_CHANGE = 0.48;
+$LAST_THREAD_CHANGE = 0.48;
+
+eval "require $PACKAGE";
+
+unless ($@) { # Make sure we did find the module.
+ if( ${$PACKAGE.'::VERSION'} < $LAST_API_CHANGE ) {
+ printf <<"CHANGE_WARN", $LAST_API_CHANGE;
+
+NOTE: There have been API changes between this version and any older
+than version %s! Please see the Changes file for details.
+
+CHANGE_WARN
+
+ sleep 5;
+ }
+ if( $] >= 5.008 && $Config{useithreads} &&
+ ${$PACKAGE.'::VERSION'} < $LAST_THREAD_CHANGE
+ )
+ {
+ printf <<"THREAD_WARN", $LAST_THREAD_CHANGE;
+
+NOTE: The behavior of Test::More and threads has changed between this
+version and any older than version %s! Please see the Changes file
+for details.
+
+THREAD_WARN
+
+ sleep 5;
+ }
+
+}
+
+WriteMakefile(
+ NAME => $PACKAGE,
+ VERSION_FROM => "lib/$PACKAGE_FILE.pm", # finds $VERSION
+ PREREQ_PM => {
+ Test::Harness => 2.03,
+ },
+ # Added to the core somewhere around 5.7.2.
+ INSTALLDIRS => $] >= 5.00702 ? 'perl' : 'site'
+);
+
+
+{
+ package MY;
+
+ use File::Basename;
+ sub test_via_harness {
+ my($self, $orig_perl, $tests) = @_;
+
+ my @perls = ();
+ if( $ENV{PERL_TEST_ALL} ) {
+ require File::Spec;
+ my $tlib = File::Spec->rel2abs('t/lib/');
+ push @perls,
+ map "PERL5LIB=$tlib $_",
+ qw(
+ perl5.4.0
+ perl5.4.5
+ perl5.5.3
+ perl5.6.0
+ perl5.6.1
+ );
+
+ push @perls,
+ qw(
+ perl
+ perl5.8.0
+ perl5.8.0-ithreads
+ bleadperl
+ );
+ }
+ else {
+ push @perls, $orig_perl;
+ }
+
+ my $out;
+ foreach my $perl (@perls) {
+ $out .= $self->SUPER::test_via_harness($perl, $tests) . "\n";
+ }
+ $out =~ s{-I\$\(PERL_\w*LIB\)}{}g;
+
+ return $out;
+ }
+}
+
+
+# Older versions of Test::Simple were very naughty about being required and
+# exitted with 255. This overrides that behavior so it builds from CPAN.
+END {
+ exit(0);
+}
View
24 trunk/README
@@ -0,0 +1,24 @@
+This is the README file for Test::Simple, basic utilities for
+writing tests, by Michael G Schwern <schwern@pobox.com>.
+
+After installation, please consult the tutorial for how to
+start adding tests to your modules. 'perldoc Test::Tutorial'
+should work on most systems.
+
+* Installation
+
+Test::Simple uses the standard perl module install process:
+
+perl Makefile.PL
+make
+make test
+make install
+
+* Copyright
+
+Copyright 2001 by Michael G Schwern <schwern@pobox.com>.
+
+All rights reserved. You can redistribute and/or modify
+this bundle under the same terms as Perl itself.
+
+See <http://www.perl.com/perl/misc/Artistic.html>.
View
37 trunk/TODO
@@ -0,0 +1,37 @@
+ Test use_ok() with imports better.
+
+ Add BAIL_OUT() (little known Test::Harness feature that basically
+ declares that the universe has turned out all wrong and the test
+ will now stop what it's doing and just go back to bed.)
+
+ Add a way to ask "Are we passing so far?". Probably a
+ Test::Builder method.
+
+ Finish (start?) Test::FAQ
+
+ Expand the Test::Tutorial
+
+ Restructure the Test::More synopsis.
+
+ Decide if the exit code behavior on failure is a useful default
+ case.
+
+ $^C exception control?
+
+ Document that everything goes through Test::Builder->ok()
+
+ Add test name to diagnostic output
+
+ Put a newline before the first diagnostic failure when in Test::Harness
+
+ Trap bare exit() calls.
+
+ Add diag() to details().
+
+ Add is_passing() method to check if we're passing?
+
+ Add at_end() callback?
+
+ Combine all *output methods into outputs().
+
+ Change *output* to return the old FH, not the new one when setting.
View
1,499 trunk/lib/Test/Builder.pm
@@ -0,0 +1,1499 @@
+package Test::Builder;
+
+use 5.004;
+
+# $^C was only introduced in 5.005-ish. We do this to prevent
+# use of uninitialized value warnings in older perls.
+$^C ||= 0;
+
+use strict;
+use vars qw($VERSION);
+$VERSION = '0.19';
+
+my $IsVMS = $^O eq 'VMS';
+
+# Make Test::Builder thread-safe for ithreads.
+BEGIN {
+ use Config;
+ # Load threads::shared when threads are turned on
+ if( $] >= 5.008 && $Config{useithreads} && $INC{'threads.pm'}) {
+ require threads::shared;
+ threads::shared->import;
+ }
+ # 5.8.0's threads::shared is busted when threads are off.
+ # We emulate it here.
+ else {
+ *share = sub { return $_[0] };
+ *lock = sub { 0 };
+ }
+}
+
+
+=head1 NAME
+
+Test::Builder - Backend for building test libraries
+
+=head1 SYNOPSIS
+
+ package My::Test::Module;
+ use Test::Builder;
+ require Exporter;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(ok);
+
+ my $Test = Test::Builder->new;
+ $Test->output('my_logfile');
+
+ sub import {
+ my($self) = shift;
+ my $pack = caller;
+
+ $Test->exported_to($pack);
+ $Test->plan(@_);
+
+ $self->export_to_level(1, $self, 'ok');
+ }
+
+ sub ok {
+ my($test, $name) = @_;
+
+ $Test->ok($test, $name);
+ }
+
+
+=head1 DESCRIPTION
+
+Test::Simple and Test::More have proven to be popular testing modules,
+but they're not always flexible enough. Test::Builder provides the a
+building block upon which to write your own test libraries I<which can
+work together>.
+
+=head2 Construction
+
+=over 4
+
+=item B<new>
+
+ my $Test = Test::Builder->new;
+
+Returns a Test::Builder object representing the current state of the
+test.
+
+Since you only run one test per program, there is B<one and only one>
+Test::Builder object. No matter how many times you call new(), you're
+getting the same object. (This is called a singleton).
+
+=cut
+
+my $Test = Test::Builder->new;
+sub new {
+ my($class) = shift;
+ $Test ||= bless ['Move along, nothing to see here'], $class;
+ return $Test;
+}
+
+=item B<reset>
+
+ $Test->reset;
+
+Reinitializes the Test::Builder singleton to its original state.
+Mostly useful for tests run in persistent environments where the same
+test might be run multiple times in the same process.
+
+=cut
+
+my $Test_Died;
+my $Have_Plan;
+my $No_Plan;
+my $Curr_Test; share($Curr_Test);
+use vars qw($Level);
+my $Original_Pid;
+my @Test_Results; share(@Test_Results);
+my @Test_Details; share(@Test_Details);
+
+my $Exported_To;
+my $Expected_Tests;
+
+my $Skip_All;
+
+my $Use_Nums;
+
+my($No_Header, $No_Ending);
+
+$Test->reset;
+
+sub reset {
+ my ($self) = @_;
+
+ $Test_Died = 0;
+ $Have_Plan = 0;
+ $No_Plan = 0;
+ $Curr_Test = 0;
+ $Level = 1;
+ $Original_Pid = $$;
+ @Test_Results = ();
+ @Test_Details = ();
+
+ $Exported_To = undef;
+ $Expected_Tests = 0;
+
+ $Skip_All = 0;
+
+ $Use_Nums = 1;
+
+ ($No_Header, $No_Ending) = (0,0);
+
+ $self->_dup_stdhandles unless $^C;
+
+ return undef;
+}
+
+=back
+
+=head2 Setting up tests
+
+These methods are for setting up tests and declaring how many there
+are. You usually only want to call one of these methods.
+
+=over 4
+
+=item B<exported_to>
+
+ my $pack = $Test->exported_to;
+ $Test->exported_to($pack);
+
+Tells Test::Builder what package you exported your functions to.
+This is important for getting TODO tests right.
+
+=cut
+
+sub exported_to {
+ my($self, $pack) = @_;
+
+ if( defined $pack ) {
+ $Exported_To = $pack;
+ }
+ return $Exported_To;
+}
+
+=item B<plan>
+
+ $Test->plan('no_plan');
+ $Test->plan( skip_all => $reason );
+ $Test->plan( tests => $num_tests );
+
+A convenient way to set up your tests. Call this and Test::Builder
+will print the appropriate headers and take the appropriate actions.
+
+If you call plan(), don't call any of the other methods below.
+
+=cut
+
+sub plan {
+ my($self, $cmd, $arg) = @_;
+
+ return unless $cmd;
+
+ if( $Have_Plan ) {
+ die sprintf "You tried to plan twice! Second plan at %s line %d\n",
+ ($self->caller)[1,2];
+ }
+
+ if( $cmd eq 'no_plan' ) {
+ $self->no_plan;
+ }
+ elsif( $cmd eq 'skip_all' ) {
+ return $self->skip_all($arg);
+ }
+ elsif( $cmd eq 'tests' ) {
+ if( $arg ) {
+ return $self->expected_tests($arg);
+ }
+ elsif( !defined $arg ) {
+ die "Got an undefined number of tests. Looks like you tried to ".
+ "say how many tests you plan to run but made a mistake.\n";
+ }
+ elsif( !$arg ) {
+ die "You said to run 0 tests! You've got to run something.\n";
+ }
+ }
+ else {
+ require Carp;
+ my @args = grep { defined } ($cmd, $arg);
+ Carp::croak("plan() doesn't understand @args");
+ }
+
+ return 1;
+}
+
+=item B<expected_tests>
+
+ my $max = $Test->expected_tests;
+ $Test->expected_tests($max);
+
+Gets/sets the # of tests we expect this test to run and prints out
+the appropriate headers.
+
+=cut
+
+sub expected_tests {
+ my($self, $max) = @_;
+
+ if( defined $max ) {
+ $Expected_Tests = $max;
+ $Have_Plan = 1;
+
+ $self->_print("1..$max\n") unless $self->no_header;
+ }
+ return $Expected_Tests;
+}
+
+
+=item B<no_plan>
+
+ $Test->no_plan;
+
+Declares that this test will run an indeterminate # of tests.
+
+=cut
+
+sub no_plan {
+ $No_Plan = 1;
+ $Have_Plan = 1;
+}
+
+=item B<has_plan>
+
+ $plan = $Test->has_plan
+
+Find out whether a plan has been defined. $plan is either C<undef> (no plan has been set), C<no_plan> (indeterminate # of tests) or an integer (the number of expected tests).
+
+=cut
+
+sub has_plan {
+ return($Expected_Tests) if $Expected_Tests;
+ return('no_plan') if $No_Plan;
+ return(undef);
+};
+
+
+=item B<skip_all>
+
+ $Test->skip_all;
+ $Test->skip_all($reason);
+
+Skips all the tests, using the given $reason. Exits immediately with 0.
+
+=cut
+
+sub skip_all {
+ my($self, $reason) = @_;
+
+ my $out = "1..0";
+ $out .= " # Skip $reason" if $reason;
+ $out .= "\n";
+
+ $Skip_All = 1;
+
+ $self->_print($out) unless $self->no_header;
+ exit(0);
+}
+
+=back
+
+=head2 Running tests
+
+These actually run the tests, analogous to the functions in
+Test::More.
+
+$name is always optional.
+
+=over 4
+
+=item B<ok>
+
+ $Test->ok($test, $name);
+
+Your basic test. Pass if $test is true, fail if $test is false. Just
+like Test::Simple's ok().
+
+=cut
+
+sub ok {
+ my($self, $test, $name) = @_;
+
+ # $test might contain an object which we don't want to accidentally
+ # store, so we turn it into a boolean.
+ $test = $test ? 1 : 0;
+
+ unless( $Have_Plan ) {
+ require Carp;
+ Carp::croak("You tried to run a test without a plan! Gotta have a plan.");
+ }
+
+ lock $Curr_Test;
+ $Curr_Test++;
+
+ # In case $name is a string overloaded object, force it to stringify.
+ local($@,$!);
+ eval {
+ if( defined $name ) {
+ require overload;
+ if( my $string_meth = overload::Method($name, '""') ) {
+ $name = $name->$string_meth();
+ }
+ }
+ };
+
+ $self->diag(<<ERR) if defined $name and $name =~ /^[\d\s]+$/;
+ You named your test '$name'. You shouldn't use numbers for your test names.
+ Very confusing.
+ERR
+
+ my($pack, $file, $line) = $self->caller;
+
+ my $todo = $self->todo($pack);
+
+ my $out;
+ my $result = &share({});
+
+ unless( $test ) {
+ $out .= "not ";
+ @$result{ 'ok', 'actual_ok' } = ( ( $todo ? 1 : 0 ), 0 );
+ }
+ else {
+ @$result{ 'ok', 'actual_ok' } = ( 1, $test );
+ }
+
+ $out .= "ok";
+ $out .= " $Curr_Test" if $self->use_numbers;
+
+ if( defined $name ) {
+ $name =~ s|#|\\#|g; # # in a name can confuse Test::Harness.
+ $out .= " - $name";
+ $result->{name} = $name;
+ }
+ else {
+ $result->{name} = '';
+ }
+
+ if( $todo ) {
+ my $what_todo = $todo;
+ $out .= " # TODO $what_todo";
+ $result->{reason} = $what_todo;
+ $result->{type} = 'todo';
+ }
+ else {
+ $result->{reason} = '';
+ $result->{type} = '';
+ }
+
+ $Test_Results[$Curr_Test-1] = $result;
+ $out .= "\n";
+
+ $self->_print($out);
+
+ unless( $test ) {
+ my $msg = $todo ? "Failed (TODO)" : "Failed";
+ $self->_print_diag("\n") if $ENV{HARNESS_ACTIVE};
+ $self->diag(" $msg test ($file at line $line)\n");
+ }
+
+ return $test ? 1 : 0;
+}
+
+=item B<is_eq>
+
+ $Test->is_eq($got, $expected, $name);
+
+Like Test::More's is(). Checks if $got eq $expected. This is the
+string version.
+
+=item B<is_num>
+
+ $Test->is_num($got, $expected, $name);
+
+Like Test::More's is(). Checks if $got == $expected. This is the
+numeric version.
+
+=cut
+
+sub is_eq {
+ my($self, $got, $expect, $name) = @_;
+ local $Level = $Level + 1;
+
+ if( !defined $got || !defined $expect ) {
+ # undef only matches undef and nothing else
+ my $test = !defined $got && !defined $expect;
+
+ $self->ok($test, $name);
+ $self->_is_diag($got, 'eq', $expect) unless $test;
+ return $test;
+ }
+
+ return $self->cmp_ok($got, 'eq', $expect, $name);
+}
+
+sub is_num {
+ my($self, $got, $expect, $name) = @_;
+ local $Level = $Level + 1;
+
+ if( !defined $got || !defined $expect ) {
+ # undef only matches undef and nothing else
+ my $test = !defined $got && !defined $expect;
+
+ $self->ok($test, $name);
+ $self->_is_diag($got, '==', $expect) unless $test;
+ return $test;
+ }
+
+ return $self->cmp_ok($got, '==', $expect, $name);
+}
+
+sub _is_diag {
+ my($self, $got, $type, $expect) = @_;
+
+ foreach my $val (\$got, \$expect) {
+ if( defined $$val ) {
+ if( $type eq 'eq' ) {
+ # quote and force string context
+ $$val = "'$$val'"
+ }
+ else {
+ # force numeric context
+ $$val = $$val+0;
+ }
+ }
+ else {
+ $$val = 'undef';
+ }
+ }
+
+ return $self->diag(sprintf <<DIAGNOSTIC, $got, $expect);
+ got: %s
+ expected: %s
+DIAGNOSTIC
+
+}
+
+=item B<isnt_eq>
+
+ $Test->isnt_eq($got, $dont_expect, $name);
+
+Like Test::More's isnt(). Checks if $got ne $dont_expect. This is
+the string version.
+
+=item B<isnt_num>
+
+ $Test->is_num($got, $dont_expect, $name);
+
+Like Test::More's isnt(). Checks if $got ne $dont_expect. This is
+the numeric version.
+
+=cut
+
+sub isnt_eq {
+ my($self, $got, $dont_expect, $name) = @_;
+ local $Level = $Level + 1;
+
+ if( !defined $got || !defined $dont_expect ) {
+ # undef only matches undef and nothing else
+ my $test = defined $got || defined $dont_expect;
+
+ $self->ok($test, $name);
+ $self->_cmp_diag($got, 'ne', $dont_expect) unless $test;
+ return $test;
+ }
+
+ return $self->cmp_ok($got, 'ne', $dont_expect, $name);
+}
+
+sub isnt_num {
+ my($self, $got, $dont_expect, $name) = @_;
+ local $Level = $Level + 1;
+
+ if( !defined $got || !defined $dont_expect ) {
+ # undef only matches undef and nothing else
+ my $test = defined $got || defined $dont_expect;
+
+ $self->ok($test, $name);
+ $self->_cmp_diag($got, '!=', $dont_expect) unless $test;
+ return $test;
+ }
+
+ return $self->cmp_ok($got, '!=', $dont_expect, $name);
+}
+
+
+=item B<like>
+
+ $Test->like($this, qr/$regex/, $name);
+ $Test->like($this, '/$regex/', $name);
+
+Like Test::More's like(). Checks if $this matches the given $regex.
+
+You'll want to avoid qr// if you want your tests to work before 5.005.
+
+=item B<unlike>
+
+ $Test->unlike($this, qr/$regex/, $name);
+ $Test->unlike($this, '/$regex/', $name);
+
+Like Test::More's unlike(). Checks if $this B<does not match> the
+given $regex.
+
+=cut
+
+sub like {
+ my($self, $this, $regex, $name) = @_;
+
+ local $Level = $Level + 1;
+ $self->_regex_ok($this, $regex, '=~', $name);
+}
+
+sub unlike {
+ my($self, $this, $regex, $name) = @_;
+
+ local $Level = $Level + 1;
+ $self->_regex_ok($this, $regex, '!~', $name);
+}
+
+=item B<maybe_regex>
+
+ $Test->maybe_regex(qr/$regex/);
+ $Test->maybe_regex('/$regex/');
+
+Convenience method for building testing functions that take regular
+expressions as arguments, but need to work before perl 5.005.
+
+Takes a quoted regular expression produced by qr//, or a string
+representing a regular expression.
+
+Returns a Perl value which may be used instead of the corresponding
+regular expression, or undef if it's argument is not recognised.
+
+For example, a version of like(), sans the useful diagnostic messages,
+could be written as:
+
+ sub laconic_like {
+ my ($self, $this, $regex, $name) = @_;
+ my $usable_regex = $self->maybe_regex($regex);
+ die "expecting regex, found '$regex'\n"
+ unless $usable_regex;
+ $self->ok($this =~ m/$usable_regex/, $name);
+ }
+
+=cut
+
+
+sub maybe_regex {
+ my ($self, $regex) = @_;
+ my $usable_regex = undef;
+ if( ref $regex eq 'Regexp' ) {
+ $usable_regex = $regex;
+ }
+ # Check if it looks like '/foo/'
+ elsif( my($re, $opts) = $regex =~ m{^ /(.*)/ (\w*) $ }sx ) {
+ $usable_regex = length $opts ? "(?$opts)$re" : $re;
+ };
+ return($usable_regex)
+};
+
+sub _regex_ok {
+ my($self, $this, $regex, $cmp, $name) = @_;
+
+ local $Level = $Level + 1;
+
+ my $ok = 0;
+ my $usable_regex = $self->maybe_regex($regex);
+ unless (defined $usable_regex) {
+ $ok = $self->ok( 0, $name );
+ $self->diag(" '$regex' doesn't look much like a regex to me.");
+ return $ok;
+ }
+
+ {
+ local $^W = 0;
+ my $test = $this =~ /$usable_regex/ ? 1 : 0;
+ $test = !$test if $cmp eq '!~';
+ $ok = $self->ok( $test, $name );
+ }
+
+ unless( $ok ) {
+ $this = defined $this ? "'$this'" : 'undef';
+ my $match = $cmp eq '=~' ? "doesn't match" : "matches";
+ $self->diag(sprintf <<DIAGNOSTIC, $this, $match, $regex);
+ %s
+ %13s '%s'
+DIAGNOSTIC
+
+ }
+
+ return $ok;
+}
+
+=item B<cmp_ok>
+
+ $Test->cmp_ok($this, $type, $that, $name);
+
+Works just like Test::More's cmp_ok().
+
+ $Test->cmp_ok($big_num, '!=', $other_big_num);
+
+=cut
+
+sub cmp_ok {
+ my($self, $got, $type, $expect, $name) = @_;
+
+ my $test;
+ {
+ local $^W = 0;
+ local($@,$!); # don't interfere with $@
+ # eval() sometimes resets $!
+ $test = eval "\$got $type \$expect";
+ }
+ local $Level = $Level + 1;
+ my $ok = $self->ok($test, $name);
+
+ unless( $ok ) {
+ if( $type =~ /^(eq|==)$/ ) {
+ $self->_is_diag($got, $type, $expect);
+ }
+ else {
+ $self->_cmp_diag($got, $type, $expect);
+ }
+ }
+ return $ok;
+}
+
+sub _cmp_diag {
+ my($self, $got, $type, $expect) = @_;
+
+ $got = defined $got ? "'$got'" : 'undef';
+ $expect = defined $expect ? "'$expect'" : 'undef';
+ return $self->diag(sprintf <<DIAGNOSTIC, $got, $type, $expect);
+ %s
+ %s
+ %s
+DIAGNOSTIC
+}
+
+=item B<BAILOUT>
+
+ $Test->BAILOUT($reason);
+
+Indicates to the Test::Harness that things are going so badly all
+testing should terminate. This includes running any additional test
+scripts.
+
+It will exit with 255.
+
+=cut
+
+sub BAILOUT {
+ my($self, $reason) = @_;
+
+ $self->_print("Bail out! $reason");
+ exit 255;
+}
+
+=item B<skip>
+
+ $Test->skip;
+ $Test->skip($why);
+
+Skips the current test, reporting $why.
+
+=cut
+
+sub skip {
+ my($self, $why) = @_;
+ $why ||= '';
+
+ unless( $Have_Plan ) {
+ require Carp;
+ Carp::croak("You tried to run tests without a plan! Gotta have a plan.");
+ }
+
+ lock($Curr_Test);
+ $Curr_Test++;
+
+ $Test_Results[$Curr_Test-1] = &share({
+ 'ok' => 1,
+ actual_ok => 1,
+ name => '',
+ type => 'skip',
+ reason => $why,
+ });
+
+ my $out = "ok";
+ $out .= " $Curr_Test" if $self->use_numbers;
+ $out .= " # skip $why\n";
+
+ $Test->_print($out);
+
+ return 1;
+}
+
+
+=item B<todo_skip>
+
+ $Test->todo_skip;
+ $Test->todo_skip($why);
+
+Like skip(), only it will declare the test as failing and TODO. Similar
+to
+
+ print "not ok $tnum # TODO $why\n";
+
+=cut
+
+sub todo_skip {
+ my($self, $why) = @_;
+ $why ||= '';
+
+ unless( $Have_Plan ) {
+ require Carp;
+ Carp::croak("You tried to run tests without a plan! Gotta have a plan.");
+ }
+
+ lock($Curr_Test);
+ $Curr_Test++;
+
+ $Test_Results[$Curr_Test-1] = &share({
+ 'ok' => 1,
+ actual_ok => 0,
+ name => '',
+ type => 'todo_skip',
+ reason => $why,
+ });
+
+ my $out = "not ok";
+ $out .= " $Curr_Test" if $self->use_numbers;
+ $out .= " # TODO & SKIP $why\n";
+
+ $Test->_print($out);
+
+ return 1;
+}
+
+
+=begin _unimplemented
+
+=item B<skip_rest>
+
+ $Test->skip_rest;
+ $Test->skip_rest($reason);
+
+Like skip(), only it skips all the rest of the tests you plan to run
+and terminates the test.
+
+If you're running under no_plan, it skips once and terminates the
+test.
+
+=end _unimplemented
+
+=back
+
+
+=head2 Test style
+
+=over 4
+
+=item B<level>
+
+ $Test->level($how_high);
+
+How far up the call stack should $Test look when reporting where the
+test failed.
+
+Defaults to 1.
+
+Setting $Test::Builder::Level overrides. This is typically useful
+localized:
+
+ {
+ local $Test::Builder::Level = 2;
+ $Test->ok($test);
+ }
+
+=cut
+
+sub level {
+ my($self, $level) = @_;
+
+ if( defined $level ) {
+ $Level = $level;
+ }
+ return $Level;
+}
+
+
+=item B<use_numbers>
+
+ $Test->use_numbers($on_or_off);
+
+Whether or not the test should output numbers. That is, this if true:
+
+ ok 1
+ ok 2
+ ok 3
+
+or this if false
+
+ ok
+ ok
+ ok
+
+Most useful when you can't depend on the test output order, such as
+when threads or forking is involved.
+
+Test::Harness will accept either, but avoid mixing the two styles.
+
+Defaults to on.
+
+=cut
+
+sub use_numbers {
+ my($self, $use_nums) = @_;
+
+ if( defined $use_nums ) {
+ $Use_Nums = $use_nums;
+ }
+ return $Use_Nums;
+}
+
+=item B<no_header>
+
+ $Test->no_header($no_header);
+
+If set to true, no "1..N" header will be printed.
+
+=item B<no_ending>
+
+ $Test->no_ending($no_ending);
+
+Normally, Test::Builder does some extra diagnostics when the test
+ends. It also changes the exit code as described below.
+
+If this is true, none of that will be done.
+
+=cut
+
+sub no_header {
+ my($self, $no_header) = @_;
+
+ if( defined $no_header ) {
+ $No_Header = $no_header;
+ }
+ return $No_Header;
+}
+
+sub no_ending {
+ my($self, $no_ending) = @_;
+
+ if( defined $no_ending ) {
+ $No_Ending = $no_ending;
+ }
+ return $No_Ending;
+}
+
+
+=back
+
+=head2 Output
+
+Controlling where the test output goes.
+
+It's ok for your test to change where STDOUT and STDERR point to,
+Test::Builder's default output settings will not be affected.
+
+=over 4
+
+=item B<diag>
+
+ $Test->diag(@msgs);
+
+Prints out the given $message. Normally, it uses the failure_output()
+handle, but if this is for a TODO test, the todo_output() handle is
+used.
+
+Output will be indented and marked with a # so as not to interfere
+with test output. A newline will be put on the end if there isn't one
+already.
+
+We encourage using this rather than calling print directly.
+
+Returns false. Why? Because diag() is often used in conjunction with
+a failing test (C<ok() || diag()>) it "passes through" the failure.
+
+ return ok(...) || diag(...);
+
+=for blame transfer
+Mark Fowler <mark@twoshortplanks.com>
+
+=cut
+
+sub diag {
+ my($self, @msgs) = @_;
+ return unless @msgs;
+
+ # Prevent printing headers when compiling (i.e. -c)
+ return if $^C;
+
+ # Escape each line with a #.
+ foreach (@msgs) {
+ $_ = 'undef' unless defined;
+ s/^/# /gms;
+ }
+
+ push @msgs, "\n" unless $msgs[-1] =~ /\n\Z/;
+
+ local $Level = $Level + 1;
+ $self->_print_diag(@msgs);
+
+ return 0;
+}
+
+=begin _private
+
+=item B<_print>
+
+ $Test->_print(@msgs);
+
+Prints to the output() filehandle.
+
+=end _private
+
+=cut
+
+sub _print {
+ my($self, @msgs) = @_;
+
+ # Prevent printing headers when only compiling. Mostly for when
+ # tests are deparsed with B::Deparse
+ return if $^C;
+
+ local($\, $", $,) = (undef, ' ', '');
+ my $fh = $self->output;
+
+ # Escape each line after the first with a # so we don't
+ # confuse Test::Harness.
+ foreach (@msgs) {
+ s/\n(.)/\n# $1/sg;
+ }
+
+ push @msgs, "\n" unless $msgs[-1] =~ /\n\Z/;
+
+ print $fh @msgs;
+}
+
+
+=item B<_print_diag>
+
+ $Test->_print_diag(@msg);
+
+Like _print, but prints to the current diagnostic filehandle.
+
+=cut
+
+sub _print_diag {
+ my $self = shift;
+
+ local($\, $", $,) = (undef, ' ', '');
+ my $fh = $self->todo ? $self->todo_output : $self->failure_output;
+ print $fh @_;
+}
+
+=item B<output>
+
+ $Test->output($fh);
+ $Test->output($file);
+
+Where normal "ok/not ok" test output should go.
+
+Defaults to STDOUT.
+
+=item B<failure_output>
+
+ $Test->failure_output($fh);
+ $Test->failure_output($file);
+
+Where diagnostic output on test failures and diag() should go.
+
+Defaults to STDERR.
+
+=item B<todo_output>
+
+ $Test->todo_output($fh);
+ $Test->todo_output($file);
+
+Where diagnostics about todo test failures and diag() should go.
+
+Defaults to STDOUT.
+
+=cut
+
+my($Out_FH, $Fail_FH, $Todo_FH);
+sub output {
+ my($self, $fh) = @_;
+
+ if( defined $fh ) {
+ $Out_FH = _new_fh($fh);
+ }
+ return $Out_FH;
+}
+
+sub failure_output {
+ my($self, $fh) = @_;
+
+ if( defined $fh ) {
+ $Fail_FH = _new_fh($fh);
+ }
+ return $Fail_FH;
+}
+
+sub todo_output {
+ my($self, $fh) = @_;
+
+ if( defined $fh ) {
+ $Todo_FH = _new_fh($fh);
+ }
+ return $Todo_FH;
+}
+
+sub _new_fh {
+ my($file_or_fh) = shift;
+
+ my $fh;
+ unless( UNIVERSAL::isa($file_or_fh, 'GLOB') ) {
+ $fh = do { local *FH };
+ open $fh, ">$file_or_fh" or
+ die "Can't open test output log $file_or_fh: $!";
+ }
+ else {
+ $fh = $file_or_fh;
+ }
+
+ return $fh;
+}
+
+sub _autoflush {
+ my($fh) = shift;
+ my $old_fh = select $fh;
+ $| = 1;
+ select $old_fh;
+}
+
+
+my $Opened_Testhandles = 0;
+sub _dup_stdhandles {
+ my $self = shift;
+
+ $self->_open_testhandles unless $Opened_Testhandles;
+
+ # Set everything to unbuffered else plain prints to STDOUT will
+ # come out in the wrong order from our own prints.
+ _autoflush(\*TESTOUT);
+ _autoflush(\*STDOUT);
+ _autoflush(\*TESTERR);
+ _autoflush(\*STDERR);
+
+ $Test->output(\*TESTOUT);
+ $Test->failure_output(\*TESTERR);
+ $Test->todo_output(\*TESTOUT);
+}
+
+sub _open_testhandles {
+ # We dup STDOUT and STDERR so people can change them in their
+ # test suites while still getting normal test output.
+ open(TESTOUT, ">&STDOUT") or die "Can't dup STDOUT: $!";
+ open(TESTERR, ">&STDERR") or die "Can't dup STDERR: $!";
+ $Opened_Testhandles = 1;
+}
+
+
+=back
+
+
+=head2 Test Status and Info
+
+=over 4
+
+=item B<current_test>
+
+ my $curr_test = $Test->current_test;
+ $Test->current_test($num);
+
+Gets/sets the current test # we're on.
+
+You usually shouldn't have to set this.
+
+=cut
+
+sub current_test {
+ my($self, $num) = @_;
+
+ lock($Curr_Test);
+ if( defined $num ) {
+ unless( $Have_Plan ) {
+ require Carp;
+ Carp::croak("Can't change the current test number without a plan!");
+ }
+
+ $Curr_Test = $num;
+ if( $num > @Test_Results ) {
+ my $start = @Test_Results ? $#Test_Results + 1 : 0;
+ for ($start..$num-1) {
+ $Test_Results[$_] = &share({
+ 'ok' => 1,
+ actual_ok => undef,
+ reason => 'incrementing test number',
+ type => 'unknown',
+ name => undef
+ });
+ }
+ }
+ }
+ return $Curr_Test;
+}
+
+
+=item B<summary>
+
+ my @tests = $Test->summary;
+
+A simple summary of the tests so far. True for pass, false for fail.
+This is a logical pass/fail, so todos are passes.
+
+Of course, test #1 is $tests[0], etc...
+
+=cut
+
+sub summary {
+ my($self) = shift;
+
+ return map { $_->{'ok'} } @Test_Results;
+}
+
+=item B<details>
+
+ my @tests = $Test->details;
+
+Like summary(), but with a lot more detail.
+
+ $tests[$test_num - 1] =
+ { 'ok' => is the test considered a pass?
+ actual_ok => did it literally say 'ok'?
+ name => name of the test (if any)
+ type => type of test (if any, see below).
+ reason => reason for the above (if any)
+ };
+
+'ok' is true if Test::Harness will consider the test to be a pass.
+
+'actual_ok' is a reflection of whether or not the test literally
+printed 'ok' or 'not ok'. This is for examining the result of 'todo'
+tests.
+
+'name' is the name of the test.
+
+'type' indicates if it was a special test. Normal tests have a type
+of ''. Type can be one of the following:
+
+ skip see skip()
+ todo see todo()
+ todo_skip see todo_skip()
+ unknown see below
+
+Sometimes the Test::Builder test counter is incremented without it
+printing any test output, for example, when current_test() is changed.
+In these cases, Test::Builder doesn't know the result of the test, so
+it's type is 'unkown'. These details for these tests are filled in.
+They are considered ok, but the name and actual_ok is left undef.
+
+For example "not ok 23 - hole count # TODO insufficient donuts" would
+result in this structure:
+
+ $tests[22] = # 23 - 1, since arrays start from 0.
+ { ok => 1, # logically, the test passed since it's todo
+ actual_ok => 0, # in absolute terms, it failed
+ name => 'hole count',
+ type => 'todo',
+ reason => 'insufficient donuts'
+ };
+
+=cut
+
+sub details {
+ return @Test_Results;
+}
+
+=item B<todo>
+
+ my $todo_reason = $Test->todo;
+ my $todo_reason = $Test->todo($pack);
+
+todo() looks for a $TODO variable in your tests. If set, all tests
+will be considered 'todo' (see Test::More and Test::Harness for
+details). Returns the reason (ie. the value of $TODO) if running as
+todo tests, false otherwise.
+
+todo() is pretty part about finding the right package to look for
+$TODO in. It uses the exported_to() package to find it. If that's
+not set, it's pretty good at guessing the right package to look at.
+
+Sometimes there is some confusion about where todo() should be looking
+for the $TODO variable. If you want to be sure, tell it explicitly
+what $pack to use.
+
+=cut
+
+sub todo {
+ my($self, $pack) = @_;
+
+ $pack = $pack || $self->exported_to || $self->caller(1);
+
+ no strict 'refs';
+ return defined ${$pack.'::TODO'} ? ${$pack.'::TODO'}
+ : 0;
+}
+
+=item B<caller>
+
+ my $package = $Test->caller;
+ my($pack, $file, $line) = $Test->caller;
+ my($pack, $file, $line) = $Test->caller($height);
+
+Like the normal caller(), except it reports according to your level().
+
+=cut
+
+sub caller {
+ my($self, $height) = @_;
+ $height ||= 0;
+
+ my @caller = CORE::caller($self->level + $height + 1);
+ return wantarray ? @caller : $caller[0];
+}
+
+=back
+
+=cut
+
+=begin _private
+
+=over 4
+
+=item B<_sanity_check>
+
+ _sanity_check();
+
+Runs a bunch of end of test sanity checks to make sure reality came
+through ok. If anything is wrong it will die with a fairly friendly
+error message.
+
+=cut
+
+#'#
+sub _sanity_check {
+ _whoa($Curr_Test < 0, 'Says here you ran a negative number of tests!');
+ _whoa(!$Have_Plan and $Curr_Test,
+ 'Somehow your tests ran without a plan!');
+ _whoa($Curr_Test != @Test_Results,
+ 'Somehow you got a different number of results than tests ran!');
+}
+
+=item B<_whoa>
+
+ _whoa($check, $description);
+
+A sanity check, similar to assert(). If the $check is true, something
+has gone horribly wrong. It will die with the given $description and
+a note to contact the author.
+
+=cut
+
+sub _whoa {
+ my($check, $desc) = @_;
+ if( $check ) {
+ die <<WHOA;
+WHOA! $desc
+This should never happen! Please contact the author immediately!
+WHOA
+ }
+}
+
+=item B<_my_exit>
+
+ _my_exit($exit_num);
+
+Perl seems to have some trouble with exiting inside an END block. 5.005_03
+and 5.6.1 both seem to do odd things. Instead, this function edits $?
+directly. It should ONLY be called from inside an END block. It
+doesn't actually exit, that's your job.
+
+=cut
+
+sub _my_exit {
+ $? = $_[0];
+
+ return 1;
+}
+
+
+=back
+
+=end _private
+
+=cut
+
+$SIG{__DIE__} = sub {
+ # We don't want to muck with death in an eval, but $^S isn't
+ # totally reliable. 5.005_03 and 5.6.1 both do the wrong thing
+ # with it. Instead, we use caller. This also means it runs under
+ # 5.004!
+ my $in_eval = 0;
+ for( my $stack = 1; my $sub = (CORE::caller($stack))[3]; $stack++ ) {
+ $in_eval = 1 if $sub =~ /^\(eval\)/;
+ }
+ $Test_Died = 1 unless $in_eval;
+};
+
+sub _ending {
+ my $self = shift;
+
+ _sanity_check();
+
+ # Don't bother with an ending if this is a forked copy. Only the parent
+ # should do the ending.
+ do{ _my_exit($?) && return } if $Original_Pid != $$;
+
+ # Bailout if plan() was never called. This is so
+ # "require Test::Simple" doesn't puke.
+ do{ _my_exit(0) && return } if !$Have_Plan && !$Test_Died;
+
+ # Figure out if we passed or failed and print helpful messages.
+ if( @Test_Results ) {
+ # The plan? We have no plan.
+ if( $No_Plan ) {
+ $self->_print("1..$Curr_Test\n") unless $self->no_header;
+ $Expected_Tests = $Curr_Test;
+ }
+
+ # Auto-extended arrays and elements which aren't explicitly
+ # filled in with a shared reference will puke under 5.8.0
+ # ithreads. So we have to fill them in by hand. :(
+ my $empty_result = &share({});
+ for my $idx ( 0..$Expected_Tests-1 ) {
+ $Test_Results[$idx] = $empty_result
+ unless defined $Test_Results[$idx];
+ }
+
+ my $num_failed = grep !$_->{'ok'}, @Test_Results[0..$Expected_Tests-1];
+ $num_failed += abs($Expected_Tests - @Test_Results);
+
+ if( $Curr_Test < $Expected_Tests ) {
+ my $s = $Expected_Tests == 1 ? '' : 's';
+ $self->diag(<<"FAIL");
+Looks like you planned $Expected_Tests test$s but only ran $Curr_Test.
+FAIL
+ }
+ elsif( $Curr_Test > $Expected_Tests ) {
+ my $num_extra = $Curr_Test - $Expected_Tests;
+ my $s = $Expected_Tests == 1 ? '' : 's';
+ $self->diag(<<"FAIL");
+Looks like you planned $Expected_Tests test$s but ran $num_extra extra.
+FAIL
+ }
+ elsif ( $num_failed ) {
+ my $s = $num_failed == 1 ? '' : 's';
+ $self->diag(<<"FAIL");
+Looks like you failed $num_failed test$s of $Expected_Tests.
+FAIL
+ }
+
+ if( $Test_Died ) {
+ $self->diag(<<"FAIL");
+Looks like your test died just after $Curr_Test.
+FAIL
+
+ _my_exit( 255 ) && return;
+ }
+
+ _my_exit( $num_failed <= 254 ? $num_failed : 254 ) && return;
+ }
+ elsif ( $Skip_All ) {
+ _my_exit( 0 ) && return;
+ }
+ elsif ( $Test_Died ) {
+ $self->diag(<<'FAIL');
+Looks like your test died before it could output anything.
+FAIL
+ _my_exit( 255 ) && return;
+ }
+ else {
+ $self->diag("No tests run!\n");
+ _my_exit( 255 ) && return;
+ }
+}
+
+END {
+ $Test->_ending if defined $Test and !$Test->no_ending;
+}
+
+=head1 EXIT CODES
+
+If all your tests passed, Test::Builder will exit with zero (which is
+normal). If anything failed it will exit with how many failed. If
+you run less (or more) tests than you planned, the missing (or extras)
+will be considered failures. If no tests were ever run Test::Builder
+will throw a warning and exit with 255. If the test died, even after
+having successfully completed all its tests, it will still be
+considered a failure and will exit with 255.
+
+So the exit codes are...
+
+ 0 all tests successful
+ 255 test died
+ any other number how many failed (including missing or extras)
+
+If you fail more than 254 tests, it will be reported as 254.
+
+
+=head1 THREADS
+
+In perl 5.8.0 and later, Test::Builder is thread-safe. The test
+number is shared amongst all threads. This means if one thread sets
+the test number using current_test() they will all be effected.
+
+Test::Builder is only thread-aware if threads.pm is loaded I<before>
+Test::Builder.
+
+=head1 EXAMPLES
+
+CPAN can provide the best examples. Test::Simple, Test::More,
+Test::Exception and Test::Differences all use Test::Builder.
+
+=head1 SEE ALSO
+
+Test::Simple, Test::More, Test::Harness
+
+=head1 AUTHORS
+
+Original code by chromatic, maintained by Michael G Schwern
+E<lt>schwern@pobox.comE<gt>
+
+=head1 COPYRIGHT
+
+Copyright 2002 by chromatic E<lt>chromatic@wgz.orgE<gt>,
+ Michael G Schwern E<lt>schwern@pobox.comE<gt>.
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+See F<http://www.perl.com/perl/misc/Artistic.html>
+
+=cut
+
+1;
View
253 trunk/lib/Test/FAQ.pod
@@ -0,0 +1,253 @@
+=head1 NAME
+
+Test::FAQ - Frequently Asked Questions about testing with Perl
+
+
+=head1 DESCRIPTION
+
+Frequently Asked Questions about testing in general and specific
+issues with Perl.
+
+=head2 Is there any tutorial on testing?
+
+Test::Tutorial
+
+=head2 Are there any modules for testing?
+
+A whole bunch. Start with Test::Simple then move onto Test::More.
+
+=head2 Are there any modules for testing web pages/CGI programs?
+
+=head2 Are there any modules for testing external programs?
+
+Test::Cmd?
+
+=head2 Can you do XUnit/JUnit style testing in Perl?
+
+Yep. The Test::Inline (aka Pod::Tests) module gives you the same
+effect, but in a different way.
+
+Test::Unit is a more faithful port of the XUnit style to Perl, but
+isn't quite ready for prime-time.
+
+=head2 How do I test my module is backwards/forwards compatible?
+
+First, install a bunch of perls of commonly used versions. At the
+moment, you could try these
+
+ 5.7.2
+ 5.6.1
+ 5.005_03
+ 5.004_05
+
+if you're feeling brave, you might want to have on hand these
+
+ bleadperl
+ 5.6.0
+ 5.004_04
+ 5.004
+
+going back beyond 5.003 is probably beyond the call of duty.
+
+You can then add something like this to your Makefile.PL. It
+overrides the MakeMaker test_via_harness() method to run the tests
+against several different versions of Perl.
+
+ # If PERL_TEST_ALL is set, run "make test" against
+ # other perls as well as the current perl.
+ {
+ package MY;
+
+ sub test_via_harness {
+ my($self, $orig_perl, $tests) = @_;
+
+ # names of your other perl binaries.
+ my @other_perls = qw(perl5.004_05 perl5.005_03 perl5.7.2);
+
+ my @perls = ($orig_perl);
+ push @perls, @other_perls if $ENV{PERL_TEST_ALL};
+
+ my $out;
+ foreach my $perl (@perls) {
+ $out .= $self->SUPER::test_via_harness($perl, $tests);
+ }
+
+ return $out;
+ }
+ }
+
+and re-run your Makefile.PL with the PERL_TEST_ALL environment
+variable set
+
+ PERL_TEST_ALL=1 perl Makefile.PL
+
+now "make test" will run against each of your other perls.
+
+
+=head2 If I'm testing Foo::Bar, where do I put tests for Foo::Bar::Baz?
+
+=head2 How do I know when my tests are good enough?
+
+A: Use tools for measuring the code coverage of your tests, e.g. how many of
+your source code lines/subs/expressions/paths are executed (aka covered) by
+the test suite. The more, the better, of course, although you may not
+be able achive 100%. If your testsuite covers under 100%, then
+the rest of your code is, basically, untested. Which means it may work in
+surprising ways (e.g. doesn't do things like they are intended or
+documented), have bugs (e.g. return wrong results) or it may not work at
+all.
+
+=head2 How do I measure the coverage of my test suite?
+
+Devel::Cover
+
+=head2 How do I get tests to run in a certain order?
+
+=head2 What should I name my tests?
+
+=head2 How do I deal with tests that sometimes pass and sometimes fail?
+
+=head2 How do I test with a database/network/server that the user may or may not have?
+
+=head2 What's a good way to test lists?
+
+=head2 Is there such a thing as untestable code?
+
+There's always compile/export checks.
+
+Code must be written with testabilty in mind. Seperation of form and
+functionality.
+
+=head2 What do I do when I can't make the code do the same thing twice?
+
+Force it to do the same thing twice.
+
+Even a random number generator can be tested.
+
+=head2 How do I test a GUI?
+
+=head2 How do I test an image generator?
+
+=head2 How do I test that my code handles failures gracefully?
+
+Forcing resource failure.
+
+=head2 How do I check the right warnings are issued?
+
+=head2 How do I test code that prints?
+
+=head2 I want to test that my code dies when I do X
+
+use eval { ... };
+
+=head2 I want to print out more diagnostic info on failure.
+
+ok(...) || print "...";
+
+=head2 How can I simulate failures to make sure that my code does the Right Thing in the face of them?
+
+
+=head2 Why use an ok() function?
+
+On Tue, Aug 28, 2001 at 02:12:46PM +0100, Robin Houston wrote:
+> Michael Schwern wrote:
+> > Ah HA! I've been wondering why nobody ever thinks to write a simple
+> > ok() function for their tests! perlhack has bad testing advice.
+>
+> Could you explain the advantage of having a "simple ok() function"?
+
+Because writing:
+
+ print "not " unless some thing worked;
+ print "ok $test\n"; $test++;
+
+gets rapidly annoying. This is why we made up subroutines in the
+first place. It also looks like hell and obscures the real purpose.
+
+Besides, that will cause problems on VMS.
+
+
+> As somebody who has spent many painful hours debugging test failures,
+> I'm intimately familiar with the _disadvantages_. When you run the
+> test, you know that "test 113 failed". That's all you know, in general.
+
+Second advantage is you can easily upgrade the ok() function to fix
+this, either by slapping this line in:
+
+ printf "# Failed test at line %d\n", (caller)[2];
+
+or simply junking the whole thing and switching to Test::Simple or
+Test::More, which does all sorts of nice diagnostics-on-failure for
+you. It's ok() function is backwards compatible with the above.
+
+There's some issues with using Test::Simple to test really basic Perl
+functionality, you have to choose on a per test basis. Since
+Test::Simple doesn't use pack() it's safe for t/op/pack.t to use
+Test::Simple. I just didn't want to make the perlhack patching
+example too complicated.
+
+
+=head2 Dummy Mode
+
+> One compromise would be to use a test-generating script, which allows
+> the tests to be structured simply and _generates_ the actual test
+> code. One could then grep the generated test script to locate the
+> failing code.
+
+This is a very interesting, and very common, response to the problem.
+I'm going to make some observations about reactions to testing,
+they're not specific to you.
+
+If you've ever read the Bastard Operator From Hell series, you'll
+recall the Dummy Mode.
+
+ The words "power surging" and "drivers" have got her. People hear
+ words like that and go into Dummy Mode and do ANYTHING you say. I
+ could tell her to run naked across campus with a powercord rammed
+ up her backside and she'd probably do it... Hmmm...
+
+There seems to be a Dummy Mode WRT testing. An otherwise competent
+person goes to write a test and they suddenly forget all basic
+programming practice.
+
+
+The reasons for using an ok() function above are the same reasons to
+use functions in general, we should all know them. We'd laugh our
+heads off at code that repeated as much as your average test does.
+These are newbie mistakes.
+
+And the normal 'can do' flair seems to disappear. I know Robin. I
+*know* that in any other situation he would have come up with the
+caller() trick in about 15 seconds flat. Instead weird, elaborate,
+inelegant hacks are thought up to solve the simplest problems.
+
+
+I guess there are certain programming idioms that are foreign enough
+to throw your brain into reverse if you're not ready for them. Like
+trying to think in Lisp, for example. Or being presented with OO for
+the first time. I guess writing test is one of those.
+
+
+=head2 How do I use Test::More without depending on it?
+
+=head2 How do I deal with threads and forking?
+
+=head2 Why do I need more than ok?
+
+=head2 What's wrong with C<print $test ? "ok" : "not ok">?
+
+=head2 How do I check for an infinite loop
+
+On Mon, Mar 18, 2002 at 03:57:55AM -0500, Mark-Jason Dominus wrote:
+>
+> Michael The Schwern <schwern@pobox.com> says:
+> > Use alarm and skip the test if $Config{d_alarm} is false (see
+> > t/op/alarm.t for an example). If you think the infinite loop is due
+> > to a programming glitch, as opposed to a cross-platform issue, this
+> > will be enough.
+>
+> Thanks very much!
+>
+
+=head2 How can I check that flock works?
+
View
1,330 trunk/lib/Test/More.pm
@@ -0,0 +1,1330 @@
+package Test::More;
+
+use 5.004;
+
+use strict;
+use Test::Builder;
+
+
+# Can't use Carp because it might cause use_ok() to accidentally succeed
+# even though the module being used forgot to use Carp. Yes, this
+# actually happened.
+sub _carp {
+ my($file, $line) = (caller(1))[1,2];
+ warn @_, " at $file line $line\n";
+}
+
+
+
+require Exporter;
+use vars qw($VERSION @ISA @EXPORT %EXPORT_TAGS $TODO);
+$VERSION = '0.50';
+@ISA = qw(Exporter);
+@EXPORT = qw(ok use_ok require_ok
+ is isnt like unlike is_deeply
+ cmp_ok
+ skip todo todo_skip
+ pass fail
+ eq_array eq_hash eq_set
+ $TODO
+ plan
+ can_ok isa_ok
+ diag
+ );
+
+my $Test = Test::Builder->new;
+my $Show_Diag = 1;
+
+
+# 5.004's Exporter doesn't have export_to_level.
+sub _export_to_level
+{
+ my $pkg = shift;
+ my $level = shift;
+ (undef) = shift; # redundant arg
+ my $callpkg = caller($level);
+ $pkg->export($callpkg, @_);
+}
+
+
+=head1 NAME
+
+Test::More - yet another framework for writing test scripts
+
+=head1 SYNOPSIS
+
+ use Test::More tests => $Num_Tests;
+ # or
+ use Test::More qw(no_plan);
+ # or
+ use Test::More skip_all => $reason;
+
+ BEGIN { use_ok( 'Some::Module' ); }
+ require_ok( 'Some::Module' );
+
+ # Various ways to say "ok"
+ ok($this eq $that, $test_name);
+
+ is ($this, $that, $test_name);
+ isnt($this, $that, $test_name);
+
+ # Rather than print STDERR "# here's what went wrong\n"
+ diag("here's what went wrong");
+
+ like ($this, qr/that/, $test_name);
+ unlike($this, qr/that/, $test_name);
+
+ cmp_ok($this, '==', $that, $test_name);
+
+ is_deeply($complex_structure1, $complex_structure2, $test_name);
+
+ SKIP: {
+ skip $why, $how_many unless $have_some_feature;
+
+ ok( foo(), $test_name );
+ is( foo(42), 23, $test_name );
+ };
+
+ TODO: {
+ local $TODO = $why;
+
+ ok( foo(), $test_name );
+ is( foo(42), 23, $test_name );
+ };
+
+ can_ok($module, @methods);
+ isa_ok($object, $class);
+
+ pass($test_name);
+ fail($test_name);
+
+ # Utility comparison functions.
+ eq_array(\@this, \@that);
+ eq_hash(\%this, \%that);
+ eq_set(\@this, \@that);
+
+ # UNIMPLEMENTED!!!
+ my @status = Test::More::status;
+
+ # UNIMPLEMENTED!!!
+ BAIL_OUT($why);
+
+
+=head1 DESCRIPTION
+
+B<STOP!> If you're just getting started writing tests, have a look at
+Test::Simple first. This is a drop in replacement for Test::Simple
+which you can switch to once you get the hang of basic testing.
+
+The purpose of this module is to provide a wide range of testing
+utilities. Various ways to say "ok" with better diagnostics,
+facilities to skip tests, test future features and compare complicated
+data structures. While you can do almost anything with a simple
+C<ok()> function, it doesn't provide good diagnostic output.
+
+
+=head2 I love it when a plan comes together
+
+Before anything else, you need a testing plan. This basically declares
+how many tests your script is going to run to protect against premature
+failure.
+
+The preferred way to do this is to declare a plan when you C<use Test::More>.
+
+ use Test::More tests => $Num_Tests;
+
+There are rare cases when you will not know beforehand how many tests
+your script is going to run. In this case, you can declare that you
+have no plan. (Try to avoid using this as it weakens your test.)
+
+ use Test::More qw(no_plan);
+
+B<NOTE>: using no_plan requires a Test::Harness upgrade else it will
+think everything has failed. See L<BUGS and CAVEATS>)
+
+In some cases, you'll want to completely skip an entire testing script.
+
+ use Test::More skip_all => $skip_reason;
+
+Your script will declare a skip with the reason why you skipped and
+exit immediately with a zero (success). See L<Test::Harness> for
+details.
+
+If you want to control what functions Test::More will export, you
+have to use the 'import' option. For example, to import everything
+but 'fail', you'd do:
+
+ use Test::More tests => 23, import => ['!fail'];
+
+Alternatively, you can use the plan() function. Useful for when you
+have to calculate the number of tests.
+
+ use Test::More;
+ plan tests => keys %Stuff * 3;
+