Test-Exception-0.32000755001750001750 012137063411 14506 5ustar00adrianhadrianh000000000000Test-Exception-0.32/Changes000555001750001750 2002412137063411 16157 0ustar00adrianhadrianh000000000000Revision history for Perl extension Test::Exception: 0.32 [2013-04-28] Or the "prepping for upcoming Test::Simple 0.99" release - Fixed tests that broke due to Test::More diagnostic changes 0.31 [2010-10-10] Or the "Yay - an actual release!" release - Same as 0.30_2 0.30_2 [2010-10-06] Or the "oh what a to do" release - Added a bunch of folk to the acknowledgements - Added some clarifying documentation to respond to RT#59293 - Marked a test that was failing under T::B 2.0 until we figure out whether it should pass or not. See http://is.gd/fNOFb 0.30_1 [2010-10-04] Or the "Peter Rabbitson did all the work" release - Added dates to changes file, as far as we can from backpan et al - Fix for DB::args bug (thanks Peter Rabbitson) - Fix for bizarre-copy bug (thanks Peter Rabbitson) 0.29 [2010-01-11] - Same as 0.28_01 - Many thanks to Ricardo Signes for doing all the work getting this release out 0.28_01 - Patch to fix code with Sub::Uplevel again. Many thanks to David Golden 0.27 [2008-02-16] - Patch to fix my broken code with the now working Sub::Uplevel. Many thanks to David Golden 0.26 [2007-12-10] - Added some more exposition on the usage of dies_ok() and lives_ok() for those who found them confusing. Also reordered presentation of docs so more specific throws_ok() comes first. - Some misc. documentation tweaks. - Added some tests for RT#24678, but not actually fixed them yet (thanks to Joshua ben Jore & David Golden). They skip for now. - Tests should now pass on Strawberry/Vanilla Perl (thanks Nadim Khemir & Chris Dolan) - Added comment in docs about T::E not catching exit() in eval() blocks (thanks Peter Scott) - Updated Test::* & Sub::Uplevel version dependencies to something modern 0.25 [2007-02-15] - Updated Test::Simple dependency to make sure it is in sync with the latest T::B::T (thanks David Cantrell) 0.24 [2006-10-07] - Fixed a bunch of spelling mistakes in the POD - Added an (optional) spelling test in t/developer 0.23 [2006-10-03] - Added a bunch of missed acknowledgements - Made the fact that $@ is preserved by T::E subroutines explicit in the synopsis 0.22 - or the "about bloody time" release [2006-09-01] - We now test that the import works (it does :-) - Now works with exception classes that override isa - Added link to AnnoCPAN - Applied patch from Ben Prew to turn the misused TODO tests into proper Test::Builder::Tester tests - thanks Ben - Now cannot pass undef as the exception to throws_ok - The optional test description for lives_and is now optional :) - Can now have empty test description for throws_ok - Requires Sub::Uplevel 0.13 - squashing several bugs (thanks to David Golden for fixing Sub::Uplevel, and for reporting the issue - along with Cees Hek & Steve Purkis) - Uses Test::Pod::Coverage rather than home grown script - Added (optional) Perl::Critic tests - Updated Test::Builder::Tester dependency to 1.04 - Tidied up tests, code and POD a little - All developer tests live in t/developer and do not run by default - Added example of only using Test::Exception if it's installed (thanks to Rob Muhlestein for suggesting this) - Test coverage now at 100% (statement, branch, condition, subroutine & POD) according to Devel::Cover 0.58 0.21 [2005-06-04] - Most of build_requires should have been in requires, which was causing CPANPLUS to choke on installs. Fixed (thanks Jos I. Boumans) - Test names now called test descriptions to fit in with latest TAP style - Added link to tada list to TO DO section of documentation - Added COMMUNITY section to POD - Added description of how to use Test::Exception in a sub-passing non prototype style (after feedback from Jim Keenan & Perrin) 0.20 [2004-08-27] - fixed bug in lives_and where $Test::Builder::Level was set to high if test in block lived 0.19 [2004-08-15] - Added support for Module::Build 0.18 [2004-08-11] - Cosmetic POD tweaks - Added Test::Warn and Test::NoWarnings to SEE ALSO (thanks to Andy Lester for pointing out the lack) 0.17 [2004-01-18] - Tests now pass with Test::Simple 0.48 0.16 [] - pod.t now uses Test::Pod - cleaned up code a little - Fixed year in copyright in POD - Added import() after suggestion from Peter Scott - tidied tests a bit 0.15 [2003-01-28] - Removed live() and added lives_and() after an excellent suggestion from Aristotle - Default name for throws_ok now has better output when passed exceptions that overload "". - Refectored t/Exception.t a bit - Now handles bad exception classes that overload "" without overloading eq (thanks to Mark Fowler for bug report & patch). - extended _exception_as_string to cover undef and normal exit - made format of exception display in throws_ok constant with other functions. - extended _exception_as_string to add appropriate prefix 0.14 - Added live() - Added default test name for throws_ok if no supplied 0.13 [2003-01-06] - fixed MANIFEST and added MANIFEST.SKIP - better output for lives_ok and throws_ok if exception classes overload "" - bug where it would fail if Test::Builder::ok ever threw exceptions internally fixed. 0.12 [2002-08-26] - patched return.t so that it skips if we don't have a Test::Harness that can handle TODO tests (thanks to for pointing this out). - tweaked POD and README - Fixed prototypes 0.11 [2002-06-29] - corrected README file - refactored code a little - minor tweaks to POD - Added test to Exception.t that demonstrated bug in throws_ok (you couldn't regex an empty string - i.e. normal exit). - Fixed bug. 0.10 [2002-06-02] - Stopped over-exuberant pod.t and documented.t checking that other peoples modules were documented and had legal POD! - Couple of minor tweaks to the docs. - Added caller.t and patch to Exception.pm from Michael G Schwern to stop dies_ok, lives_ok and throws_ok interfering with caller(). Much better than the regex hack added in 0.08 --- which has now been removed. 0.09 [2002-06-01] - Fixed poor English in throws_ok docs. 0.08 [2002-05-31] - Added reference to Test::Inline to docs - Test::More now in PREREQ_PM - Culled some code that could never be called - Added t/pod.t and t/documented.t - Now bails if cannot load module in tests - Fixed typo of Text::Differences in docs - Added stacktrace.t to demontrate error reported by Janek Schleicher where a stacktrace in the exception can cause throws_ok to always succeed. - Stopped stacktrace.t failing. 0.07 [2002-04-12] - may_be_regex -> maybe_regex in Test::Builder 0.06 - couple of minor tweaks to the docs 0.05 - now uses may_be_regex public method from Test::Builder - should work & test under 5.005, don't have a perl to hand to double check so feedback welcome 0.04 - Can now pass regex-like strings as well as regexes. Thanks to Mark Fowler for the suggestion and Michael G Schwern for adding code to Test::Builder. 0.03 [2002-04-09] - dies_ok, lives_ok & throws_ok now all return the result of the underlying ok - $@ is now guaranteed to be preserved (and is documented as such). Thanks to Michael G Schwern for suggesting this. - Tests run tainted, strict & with warnings (just to be on the safe side :-) 0.02 [2002-04-09] - Documented properly 0.01 [2002-03-20] - original version; created by h2xs 1.21 with options -AX -n Test::Exception Test-Exception-0.32/META.json000444001750001750 212412137063411 16263 0ustar00adrianhadrianh000000000000{ "abstract" : "Test exception based code", "author" : [ "Adrian Howard " ], "dynamic_config" : 1, "generated_by" : "Module::Build version 0.38, CPAN::Meta::Converter version 2.112621", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Test-Exception", "prereqs" : { "configure" : { "requires" : { "Module::Build" : "0.38" } }, "runtime" : { "requires" : { "Sub::Uplevel" : "0.18", "Test::Builder" : "0.7", "Test::Builder::Tester" : "1.07", "Test::Harness" : "2.03", "Test::More" : "0.7", "Test::Simple" : "0.7" } } }, "provides" : { "Test::Exception" : { "file" : "lib/Test/Exception.pm", "version" : "0.32" } }, "release_status" : "stable", "resources" : { "license" : [ "http://dev.perl.org/licenses/" ] }, "version" : "0.32" } Test-Exception-0.32/README000444001750001750 2572212137063411 15553 0ustar00adrianhadrianh000000000000NAME Test::Exception - Test exception based code SYNOPSIS use Test::More tests => 5; use Test::Exception; # or if you don't need Test::More use Test::Exception tests => 5; # then... # Check that the stringified exception matches given regex throws_ok { $foo->method } qr/division by zero/, 'zero caught okay'; # Check an exception of the given class (or subclass) is thrown throws_ok { $foo->method } 'Error::Simple', 'simple error thrown'; # all Test::Exceptions subroutines are guaranteed to preserve the state # of $@ so you can do things like this after throws_ok and dies_ok like $@, 'what the stringified exception should look like'; # Check that something died - we do not care why dies_ok { $foo->method } 'expecting to die'; # Check that something did not die lives_ok { $foo->method } 'expecting to live'; # Check that a test runs without an exception lives_and { is $foo->method, 42 } 'method is 42'; # or if you don't like prototyped functions throws_ok( sub { $foo->method }, qr/division by zero/, 'zero caught okay' ); throws_ok( sub { $foo->method }, 'Error::Simple', 'simple error thrown' ); dies_ok( sub { $foo->method }, 'expecting to die' ); lives_ok( sub { $foo->method }, 'expecting to live' ); lives_and( sub { is $foo->method, 42 }, 'method is 42' ); DESCRIPTION This module provides a few convenience methods for testing exception based code. It is built with Test::Builder and plays happily with Test::More and friends. If you are not already familiar with Test::More now would be the time to go take a look. You can specify the test plan when you `use Test::Exception' in the same way as `use Test::More'. See Test::More for details. NOTE: Test::Exception only checks for exceptions. It will ignore other methods of stopping program execution - including exit(). If you have an exit() in evalled code Test::Exception will not catch this with any of its testing functions. throws_ok Tests to see that a specific exception is thrown. throws_ok() has two forms: throws_ok BLOCK REGEX, TEST_DESCRIPTION throws_ok BLOCK CLASS, TEST_DESCRIPTION In the first form the test passes if the stringified exception matches the give regular expression. For example: throws_ok { read_file( 'unreadable' ) } qr/No file/, 'no file'; If your perl does not support `qr//' you can also pass a regex-like string, for example: throws_ok { read_file( 'unreadable' ) } '/No file/', 'no file'; The second form of throws_ok() test passes if the exception is of the same class as the one supplied, or a subclass of that class. For example: throws_ok { $foo->bar } "Error::Simple", 'simple error'; Will only pass if the `bar' method throws an Error::Simple exception, or a subclass of an Error::Simple exception. You can get the same effect by passing an instance of the exception you want to look for. The following is equivalent to the previous example: my $SIMPLE = Error::Simple->new; throws_ok { $foo->bar } $SIMPLE, 'simple error'; Should a throws_ok() test fail it produces appropriate diagnostic messages. For example: not ok 3 - simple error # Failed test (test.t at line 48) # expecting: Error::Simple exception # found: normal exit Like all other Test::Exception functions you can avoid prototypes by passing a subroutine explicitly: throws_ok( sub {$foo->bar}, "Error::Simple", 'simple error' ); A true value is returned if the test succeeds, false otherwise. On exit $@ is guaranteed to be the cause of death (if any). A description of the exception being checked is used if no optional test description is passed. NOTE: Rememeber when you `die $string_without_a_trailing_newline' perl will automatically add the current script line number, input line number and a newline. This will form part of the string that throws_ok regular expressions match against. dies_ok Checks that a piece of code dies, rather than returning normally. For example: sub div { my ( $a, $b ) = @_; return $a / $b; }; dies_ok { div( 1, 0 ) } 'divide by zero detected'; # or if you don't like prototypes dies_ok( sub { div( 1, 0 ) }, 'divide by zero detected' ); A true value is returned if the test succeeds, false otherwise. On exit $@ is guaranteed to be the cause of death (if any). Remember: This test will pass if the code dies for any reason. If you care about the reason it might be more sensible to write a more specific test using throws_ok(). The test description is optional, but recommended. lives_ok Checks that a piece of code doesn't die. This allows your test script to continue, rather than aborting if you get an unexpected exception. For example: sub read_file { my $file = shift; local $/; open my $fh, '<', $file or die "open failed ($!)\n"; $file = ; return $file; }; my $file; lives_ok { $file = read_file('test.txt') } 'file read'; # or if you don't like prototypes lives_ok( sub { $file = read_file('test.txt') }, 'file read' ); Should a lives_ok() test fail it produces appropriate diagnostic messages. For example: not ok 1 - file read # Failed test (test.t at line 15) # died: open failed (No such file or directory) A true value is returned if the test succeeds, false otherwise. On exit $@ is guaranteed to be the cause of death (if any). The test description is optional, but recommended. lives_and Run a test that may throw an exception. For example, instead of doing: my $file; lives_ok { $file = read_file('answer.txt') } 'read_file worked'; is $file, "42", 'answer was 42'; You can use lives_and() like this: lives_and { is read_file('answer.txt'), "42" } 'answer is 42'; # or if you don't like prototypes lives_and(sub {is read_file('answer.txt'), "42"}, 'answer is 42'); Which is the same as doing is read_file('answer.txt'), "42\n", 'answer is 42'; unless `read_file('answer.txt')' dies, in which case you get the same kind of error as lives_ok() not ok 1 - answer is 42 # Failed test (test.t at line 15) # died: open failed (No such file or directory) A true value is returned if the test succeeds, false otherwise. On exit $@ is guaranteed to be the cause of death (if any). The test description is optional, but recommended. SKIPPING TEST::EXCEPTION TESTS Sometimes we want to use Test::Exception tests in a test suite, but don't want to force the user to have Test::Exception installed. One way to do this is to skip the tests if Test::Exception is absent. You can do this with code something like this: use strict; use warnings; use Test::More; BEGIN { eval "use Test::Exception"; plan skip_all => "Test::Exception needed" if $@; } plan tests => 2; # ... tests that need Test::Exception ... Note that we load Test::Exception in a `BEGIN' block ensuring that the subroutine prototypes are in place before the rest of the test script is compiled. BUGS There are some edge cases in Perl's exception handling where Test::Exception will miss exceptions thrown in DESTROY blocks. See the RT bug http://rt.cpan.org/Ticket/Display.html?id=24678 for details, along with the t/edge-cases.t in the distribution test suite. These will be addressed in a future Test::Exception release. If you find any more bugs please let me know by e-mail, or report the problem with http://rt.cpan.org/. COMMUNITY perl-qa If you are interested in testing using Perl I recommend you visit http://qa.perl.org/ and join the excellent perl-qa mailing list. See http://lists.perl.org/showlist.cgi?name=perl-qa for details on how to subscribe. perlmonks You can find users of Test::Exception, including the module author, on http://www.perlmonks.org/. Feel free to ask questions on Test::Exception there. CPAN::Forum The CPAN Forum is a web forum for discussing Perl's CPAN modules. The Test::Exception forum can be found at http://www.cpanforum.com/dist/Test-Exception. AnnoCPAN AnnoCPAN is a web site that allows community annotations of Perl module documentation. The Test::Exception annotations can be found at http://annocpan.org/~ADIE/Test-Exception/. TO DO If you think this module should do something that it doesn't (or does something that it shouldn't) please let me know. You can see my current to do list at http://adrianh.tadalist.com/lists/public/15421, with an RSS feed of changes at http://adrianh.tadalist.com/lists/feed_public/15421. ACKNOWLEDGMENTS Thanks to chromatic and Michael G Schwern for the excellent Test::Builder, without which this module wouldn't be possible. Thanks to Adam Kennedy, Andy Lester, Aristotle Pagaltzis, Ben Prew, Cees Hek, Chris Dolan, chromatic, Curt Sampson, David Cantrell, David Golden, David Tulloh, David Wheeler, J. K. O'Brien, Janek Schleicher, Jim Keenan, Jos I. Boumans, Joshua ben Jore, Jost Krieger, Mark Fowler, Michael G Schwern, Nadim Khemir, Paul McCann, Perrin Harkins, Peter Rabbitson, Peter Scott, Ricardo Signes, Rob Muhlestein, Scott R. Godin, Steve Purkis, Steve, Tim Bunce, and various anonymous folk for comments, suggestions, bug reports and patches. AUTHOR Adrian Howard If you can spare the time, please drop me a line if you find this module useful. SEE ALSO http://del.icio.us/tag/Test::Exception Delicious links on Test::Exception. Test::Warn & Test::NoWarnings Modules to help test warnings. Test::Builder Support module for building test libraries. Test::Simple & Test::More Basic utilities for writing tests. http://qa.perl.org/test-modules.html Overview of some of the many testing modules available on CPAN. http://del.icio.us/tag/perl+testing Delicious links on perl testing. LICENCE Copyright 2002-2007 Adrian Howard, All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Test-Exception-0.32/Build.PL000444001750001750 103112137063411 16132 0ustar00adrianhadrianh000000000000use Module::Build; my $build = Module::Build->new( module_name => 'Test::Exception', license => 'perl', requires => { # 'perl' => '5.6.1', 'Test::Simple' => '0.7', 'Test::Builder' => '0.7', 'Test::Builder::Tester' => '1.07', 'Test::More' => '0.7', 'Test::Harness' => '2.03', 'Sub::Uplevel' => '0.18', }, create_makefile_pl => 'traditional', create_readme => 1, ); $build->create_build_script; Test-Exception-0.32/MANIFEST000444001750001750 46712137063411 15763 0ustar00adrianhadrianh000000000000Build.PL Changes lib/Test/Exception.pm MANIFEST This list of files README t/caller.t t/edge-cases.t t/Exception.t t/import.t t/isa.t t/lives_and.t t/preserve.t t/return.t t/rt.t t/stacktrace.t t/throws_ok.t xt/documented.t xt/perlcritic.t xt/perlcriticrc xt/pod.t xt/spelling.t Makefile.PL META.yml META.json Test-Exception-0.32/META.yml000444001750001750 123412137063411 16114 0ustar00adrianhadrianh000000000000--- abstract: 'Test exception based code' author: - 'Adrian Howard ' build_requires: {} configure_requires: Module::Build: 0.38 dynamic_config: 1 generated_by: 'Module::Build version 0.38, CPAN::Meta::Converter version 2.112621' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Test-Exception provides: Test::Exception: file: lib/Test/Exception.pm version: 0.32 requires: Sub::Uplevel: 0.18 Test::Builder: 0.7 Test::Builder::Tester: 1.07 Test::Harness: 2.03 Test::More: 0.7 Test::Simple: 0.7 resources: license: http://dev.perl.org/licenses/ version: 0.32 Test-Exception-0.32/Makefile.PL000444001750001750 110312137063411 16610 0ustar00adrianhadrianh000000000000# Note: this file was auto-generated by Module::Build::Compat version 0.3800 use ExtUtils::MakeMaker; WriteMakefile ( 'NAME' => 'Test::Exception', 'VERSION_FROM' => 'lib/Test/Exception.pm', 'PREREQ_PM' => { 'Sub::Uplevel' => '0.18', 'Test::Builder' => '0.7', 'Test::Builder::Tester' => '1.07', 'Test::Harness' => '2.03', 'Test::More' => '0.7', 'Test::Simple' => '0.7' }, 'INSTALLDIRS' => 'site', 'EXE_FILES' => [], 'PL_FILES' => {} ) ; Test-Exception-0.32/xt000755001750001750 012137063411 15141 5ustar00adrianhadrianh000000000000Test-Exception-0.32/xt/perlcriticrc000444001750001750 5512137063411 17646 0ustar00adrianhadrianh000000000000[-Subroutines::ProhibitSubroutinePrototypes] Test-Exception-0.32/xt/spelling.t000444001750001750 112212137063411 17274 0ustar00adrianhadrianh000000000000#!/usr/bin/perl use strict; use warnings; use Test::More; my $ispell_path = eval q{ use Test::Spelling; use File::Which; which('ispell') || die 'no ispell' }; plan skip_all => 'Optional Test::Spelling, File::Which and ispell program required to spellcheck POD' if $@; set_spell_cmd("$ispell_path -l"); add_stopwords( ); all_pod_files_spelling_ok(); __DATA__ AnnoCPAN CPAN perlmonks RSS Boumans Cees Godin Harkins Hek Purkis Schleicher Muhlestein Perrin Prew Krieger LICENCE McCann Jos Jost qa Adrian Cantrell Janek Jore ben Khemir Nadim Pagaltzis Dolan RT Ricardo Signes Test-Exception-0.32/xt/documented.t000555001750001750 32112137063411 17571 0ustar00adrianhadrianh000000000000#! /usr/bin/perl -Tw use strict; use warnings; use Test::More; eval "use Test::Pod::Coverage 1.00"; plan skip_all => "Test::Pod::Coverage 1.00 required for testing POD coverage" if $@; all_pod_coverage_ok();Test-Exception-0.32/xt/pod.t000555001750001750 26212137063411 16230 0ustar00adrianhadrianh000000000000#! /usr/bin/perl -Tw use strict; use warnings; use Test::More; eval "use Test::Pod 1.00"; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; all_pod_files_ok(); Test-Exception-0.32/xt/perlcritic.t000444001750001750 32712137063411 17605 0ustar00adrianhadrianh000000000000#! /usr/bin/perl -Tw use strict; use warnings; use Test::More; eval "use Test::Perl::Critic (-profile => 'xt/perlcriticrc')"; plan skip_all => "Test::Perl::Critic required for criticism" if $@; all_critic_ok(); Test-Exception-0.32/lib000755001750001750 012137063411 15254 5ustar00adrianhadrianh000000000000Test-Exception-0.32/lib/Test000755001750001750 012137063411 16173 5ustar00adrianhadrianh000000000000Test-Exception-0.32/lib/Test/Exception.pm000444001750001750 3530612137063411 20653 0ustar00adrianhadrianh000000000000use strict; use warnings; package Test::Exception; use Test::Builder; use Sub::Uplevel qw( uplevel ); use base qw( Exporter ); our $VERSION = '0.32'; our @EXPORT = qw(dies_ok lives_ok throws_ok lives_and); my $Tester = Test::Builder->new; sub import { my $self = shift; if ( @_ ) { my $package = caller; $Tester->exported_to( $package ); $Tester->plan( @_ ); }; $self->export_to_level( 1, $self, $_ ) foreach @EXPORT; } =head1 NAME Test::Exception - Test exception based code =head1 SYNOPSIS use Test::More tests => 5; use Test::Exception; # or if you don't need Test::More use Test::Exception tests => 5; # then... # Check that the stringified exception matches given regex throws_ok { $foo->method } qr/division by zero/, 'zero caught okay'; # Check an exception of the given class (or subclass) is thrown throws_ok { $foo->method } 'Error::Simple', 'simple error thrown'; # all Test::Exceptions subroutines are guaranteed to preserve the state # of $@ so you can do things like this after throws_ok and dies_ok like $@, 'what the stringified exception should look like'; # Check that something died - we do not care why dies_ok { $foo->method } 'expecting to die'; # Check that something did not die lives_ok { $foo->method } 'expecting to live'; # Check that a test runs without an exception lives_and { is $foo->method, 42 } 'method is 42'; # or if you don't like prototyped functions throws_ok( sub { $foo->method }, qr/division by zero/, 'zero caught okay' ); throws_ok( sub { $foo->method }, 'Error::Simple', 'simple error thrown' ); dies_ok( sub { $foo->method }, 'expecting to die' ); lives_ok( sub { $foo->method }, 'expecting to live' ); lives_and( sub { is $foo->method, 42 }, 'method is 42' ); =head1 DESCRIPTION This module provides a few convenience methods for testing exception based code. It is built with L and plays happily with L and friends. If you are not already familiar with L now would be the time to go take a look. You can specify the test plan when you C in the same way as C. See L for details. NOTE: Test::Exception only checks for exceptions. It will ignore other methods of stopping program execution - including exit(). If you have an exit() in evalled code Test::Exception will not catch this with any of its testing functions. =cut sub _quiet_caller (;$) { ## no critic Prototypes my $height = $_[0]; $height++; if ( CORE::caller() eq 'DB' ) { # passthrough the @DB::args trick package DB; if( wantarray ) { if ( !@_ ) { return (CORE::caller($height))[0..2]; } else { # If we got here, we are within a Test::Exception test, and # something is producing a stacktrace. In case this is a full # trace (i.e. confess() ), we have to make sure that the sub # args are not visible. If we do not do this, and the test in # question is throws_ok() with a regex, it will end up matching # against itself in the args to throws_ok(). # # While it is possible (and maybe wise), to test if we are # indeed running under throws_ok (by crawling the stack right # up from here), the old behavior of Test::Exception was to # simply obliterate @DB::args altogether in _quiet_caller, so # we are just preserving the behavior to avoid surprises # my @frame_info = CORE::caller($height); @DB::args = (); return @frame_info; } } # fallback if nothing above returns return CORE::caller($height); } else { if( wantarray and !@_ ) { return (CORE::caller($height))[0..2]; } else { return CORE::caller($height); } } } sub _try_as_caller { my $coderef = shift; # local works here because Sub::Uplevel has already overridden caller local *CORE::GLOBAL::caller; { no warnings 'redefine'; *CORE::GLOBAL::caller = \&_quiet_caller; } eval { uplevel 3, $coderef }; return $@; }; sub _is_exception { my $exception = shift; return ref $exception || $exception ne ''; }; sub _exception_as_string { my ( $prefix, $exception ) = @_; return "$prefix normal exit" unless _is_exception( $exception ); my $class = ref $exception; $exception = "$class ($exception)" if $class && "$exception" !~ m/^\Q$class/; chomp $exception; return "$prefix $exception"; }; =over 4 =item B Tests to see that a specific exception is thrown. throws_ok() has two forms: throws_ok BLOCK REGEX, TEST_DESCRIPTION throws_ok BLOCK CLASS, TEST_DESCRIPTION In the first form the test passes if the stringified exception matches the give regular expression. For example: throws_ok { read_file( 'unreadable' ) } qr/No file/, 'no file'; If your perl does not support C you can also pass a regex-like string, for example: throws_ok { read_file( 'unreadable' ) } '/No file/', 'no file'; The second form of throws_ok() test passes if the exception is of the same class as the one supplied, or a subclass of that class. For example: throws_ok { $foo->bar } "Error::Simple", 'simple error'; Will only pass if the C method throws an Error::Simple exception, or a subclass of an Error::Simple exception. You can get the same effect by passing an instance of the exception you want to look for. The following is equivalent to the previous example: my $SIMPLE = Error::Simple->new; throws_ok { $foo->bar } $SIMPLE, 'simple error'; Should a throws_ok() test fail it produces appropriate diagnostic messages. For example: not ok 3 - simple error # Failed test (test.t at line 48) # expecting: Error::Simple exception # found: normal exit Like all other Test::Exception functions you can avoid prototypes by passing a subroutine explicitly: throws_ok( sub {$foo->bar}, "Error::Simple", 'simple error' ); A true value is returned if the test succeeds, false otherwise. On exit $@ is guaranteed to be the cause of death (if any). A description of the exception being checked is used if no optional test description is passed. NOTE: Rememeber when you C perl will automatically add the current script line number, input line number and a newline. This will form part of the string that throws_ok regular expressions match against. =cut sub throws_ok (&$;$) { my ( $coderef, $expecting, $description ) = @_; unless (defined $expecting) { require Carp; Carp::croak( "throws_ok: must pass exception class/object or regex" ); } $description = _exception_as_string( "threw", $expecting ) unless defined $description; my $exception = _try_as_caller( $coderef ); my $regex = $Tester->maybe_regex( $expecting ); my $ok = $regex ? ( $exception =~ m/$regex/ ) : eval { $exception->isa( ref $expecting ? ref $expecting : $expecting ) }; $Tester->ok( $ok, $description ); unless ( $ok ) { $Tester->diag( _exception_as_string( "expecting:", $expecting ) ); $Tester->diag( _exception_as_string( "found:", $exception ) ); }; $@ = $exception; return $ok; }; =item B Checks that a piece of code dies, rather than returning normally. For example: sub div { my ( $a, $b ) = @_; return $a / $b; }; dies_ok { div( 1, 0 ) } 'divide by zero detected'; # or if you don't like prototypes dies_ok( sub { div( 1, 0 ) }, 'divide by zero detected' ); A true value is returned if the test succeeds, false otherwise. On exit $@ is guaranteed to be the cause of death (if any). Remember: This test will pass if the code dies for any reason. If you care about the reason it might be more sensible to write a more specific test using throws_ok(). The test description is optional, but recommended. =cut sub dies_ok (&;$) { my ( $coderef, $description ) = @_; my $exception = _try_as_caller( $coderef ); my $ok = $Tester->ok( _is_exception($exception), $description ); $@ = $exception; return $ok; } =item B Checks that a piece of code doesn't die. This allows your test script to continue, rather than aborting if you get an unexpected exception. For example: sub read_file { my $file = shift; local $/; open my $fh, '<', $file or die "open failed ($!)\n"; $file = ; return $file; }; my $file; lives_ok { $file = read_file('test.txt') } 'file read'; # or if you don't like prototypes lives_ok( sub { $file = read_file('test.txt') }, 'file read' ); Should a lives_ok() test fail it produces appropriate diagnostic messages. For example: not ok 1 - file read # Failed test (test.t at line 15) # died: open failed (No such file or directory) A true value is returned if the test succeeds, false otherwise. On exit $@ is guaranteed to be the cause of death (if any). The test description is optional, but recommended. =cut sub lives_ok (&;$) { my ( $coderef, $description ) = @_; my $exception = _try_as_caller( $coderef ); my $ok = $Tester->ok( ! _is_exception( $exception ), $description ); $Tester->diag( _exception_as_string( "died:", $exception ) ) unless $ok; $@ = $exception; return $ok; } =item B Run a test that may throw an exception. For example, instead of doing: my $file; lives_ok { $file = read_file('answer.txt') } 'read_file worked'; is $file, "42", 'answer was 42'; You can use lives_and() like this: lives_and { is read_file('answer.txt'), "42" } 'answer is 42'; # or if you don't like prototypes lives_and(sub {is read_file('answer.txt'), "42"}, 'answer is 42'); Which is the same as doing is read_file('answer.txt'), "42\n", 'answer is 42'; unless C dies, in which case you get the same kind of error as lives_ok() not ok 1 - answer is 42 # Failed test (test.t at line 15) # died: open failed (No such file or directory) A true value is returned if the test succeeds, false otherwise. On exit $@ is guaranteed to be the cause of death (if any). The test description is optional, but recommended. =cut sub lives_and (&;$) { my ( $test, $description ) = @_; { local $Test::Builder::Level = $Test::Builder::Level + 1; my $ok = \&Test::Builder::ok; no warnings; local *Test::Builder::ok = sub { $_[2] = $description unless defined $_[2]; $ok->(@_); }; use warnings; eval { $test->() } and return 1; }; my $exception = $@; if ( _is_exception( $exception ) ) { $Tester->ok( 0, $description ); $Tester->diag( _exception_as_string( "died:", $exception ) ); }; $@ = $exception; return; } =back =head1 SKIPPING TEST::EXCEPTION TESTS Sometimes we want to use Test::Exception tests in a test suite, but don't want to force the user to have Test::Exception installed. One way to do this is to skip the tests if Test::Exception is absent. You can do this with code something like this: use strict; use warnings; use Test::More; BEGIN { eval "use Test::Exception"; plan skip_all => "Test::Exception needed" if $@; } plan tests => 2; # ... tests that need Test::Exception ... Note that we load Test::Exception in a C block ensuring that the subroutine prototypes are in place before the rest of the test script is compiled. =head1 BUGS There are some edge cases in Perl's exception handling where Test::Exception will miss exceptions thrown in DESTROY blocks. See the RT bug L for details, along with the t/edge-cases.t in the distribution test suite. These will be addressed in a future Test::Exception release. If you find any more bugs please let me know by e-mail, or report the problem with L. =head1 COMMUNITY =over 4 =item perl-qa If you are interested in testing using Perl I recommend you visit L and join the excellent perl-qa mailing list. See L for details on how to subscribe. =item perlmonks You can find users of Test::Exception, including the module author, on L. Feel free to ask questions on Test::Exception there. =item CPAN::Forum The CPAN Forum is a web forum for discussing Perl's CPAN modules. The Test::Exception forum can be found at L. =item AnnoCPAN AnnoCPAN is a web site that allows community annotations of Perl module documentation. The Test::Exception annotations can be found at L. =back =head1 TO DO If you think this module should do something that it doesn't (or does something that it shouldn't) please let me know. You can see my current to do list at L, with an RSS feed of changes at L. =head1 ACKNOWLEDGMENTS Thanks to chromatic and Michael G Schwern for the excellent Test::Builder, without which this module wouldn't be possible. Thanks to Adam Kennedy, Andy Lester, Aristotle Pagaltzis, Ben Prew, Cees Hek, Chris Dolan, chromatic, Curt Sampson, David Cantrell, David Golden, David Tulloh, David Wheeler, J. K. O'Brien, Janek Schleicher, Jim Keenan, Jos I. Boumans, Joshua ben Jore, Jost Krieger, Mark Fowler, Michael G Schwern, Nadim Khemir, Paul McCann, Perrin Harkins, Peter Rabbitson, Peter Scott, Ricardo Signes, Rob Muhlestein, Scott R. Godin, Steve Purkis, Steve, Tim Bunce, and various anonymous folk for comments, suggestions, bug reports and patches. =head1 AUTHOR Adrian Howard If you can spare the time, please drop me a line if you find this module useful. =head1 SEE ALSO =over 4 =item L Delicious links on Test::Exception. =item L & L Modules to help test warnings. =item L Support module for building test libraries. =item L & L Basic utilities for writing tests. =item L Overview of some of the many testing modules available on CPAN. =item L Delicious links on perl testing. =back =head1 LICENCE Copyright 2002-2007 Adrian Howard, All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Test-Exception-0.32/t000755001750001750 012137063411 14751 5ustar00adrianhadrianh000000000000Test-Exception-0.32/t/caller.t000444001750001750 127612137063411 16543 0ustar00adrianhadrianh000000000000#!/usr/bin/perl -Tw # Make sure caller() is undisturbed. use strict; use warnings; use Test::Exception; use Test::More tests => 3; eval { die caller() . "\n" }; is( $@, "main\n" ); throws_ok { die caller() . "\n" } qr/^main$/; # Make sure our override of caller() does not mess up @DB::args and thus Carp # The test is rather strange, but there is no clearer way to trigger this # error. For details see: # http://rt.perl.org/rt3/Public/Bug/Display.html?id=52610#txn-713770 require Carp; my $croaker = sub { Carp::croak ('No bizarre errors') }; for my $x (1..1) { eval { $croaker->($x) }; } throws_ok ( sub { $croaker->() }, qr/No bizarre errors/, "Croak works properly (final)", ); Test-Exception-0.32/t/rt.t000444001750001750 107012137063411 15716 0ustar00adrianhadrianh000000000000#! /usr/bin/perl use strict; use warnings; use Test::More 'no_plan'; use Test::Exception; { package Foo; use Carp qw( confess ); sub an_abstract_method { shift->subclass_responsibility; } sub subclass_responsibility { my $class = shift; my $method = (caller(1))[3]; $method =~ s/.*:://; confess( "abstract method '$method' not implemented for $class" ); } } throws_ok { Foo->an_abstract_method } qr/abstract method 'an_abstract_method'/, 'RT 11846: throws_ok breaks tests that depend on caller stack: working'; Test-Exception-0.32/t/isa.t000444001750001750 63112137063411 16027 0ustar00adrianhadrianh000000000000#! /usr/bin/perl -Tw use strict; use warnings; use Test::More tests => 1; use Test::Exception; { package MockFooException; sub new { bless {}, shift }; sub isa { my ( $self, $class ) = @_; return 1 if $class eq 'Foo'; return $self->SUPER::isa( $class ); } } throws_ok { die MockFooException->new } 'Foo', 'Understand exception classes that override isa';Test-Exception-0.32/t/lives_and.t000444001750001750 142612137063411 17242 0ustar00adrianhadrianh000000000000#! /usr/bin/perl -Tw use strict; use warnings; use Test::Builder::Tester tests => 3; use Test::More; BEGIN { use_ok( 'Test::Exception' ) }; sub works {return shift}; sub dies { die 'oops' }; my $filename = sub { return (caller)[1] }->(); lives_and {is works(42), 42} 'lives_and, no_exception & success'; test_out('not ok 1 - lives_and, no_exception & failure'); test_fail(+3); test_err("# got: '42'"); test_err("# expected: '24'"); lives_and {is works(42), 24} 'lives_and, no_exception & failure'; test_out('not ok 2 - lives_and, exception'); test_fail(+2); test_err("# died: oops at $filename line 11."); lives_and {is dies(42), 42} 'lives_and, exception'; test_out('ok 3 - the test passed' ); lives_and { ok(1, 'the test passed') }; test_test('lives_and works'); Test-Exception-0.32/t/import.t000444001750001750 27512137063411 16571 0ustar00adrianhadrianh000000000000#! /usr/bin/perl -Tw use strict; use warnings; use Test::More; BEGIN { use_ok( 'Test::Exception', tests => 2 ) }; is( Test::Builder->new->expected_tests, 2, 'Test::Exception set plan' );Test-Exception-0.32/t/preserve.t000555001750001750 75012137063411 17113 0ustar00adrianhadrianh000000000000#! /usr/bin/perl -Tw use strict; use warnings; use Test::More tests => 5; BEGIN { use_ok( 'Test::Exception' ) }; sub div { my ($a, $b) = @_; return( $a / $b ); }; dies_ok { div(1, 0) } 'exception thrown okay in dies_ok'; like( $@, '/^Illegal division by zero/', 'exception preserved after dies_ok' ); throws_ok { div(1, 0) } '/^Illegal division by zero/', 'exception thrown okay in throws_ok'; like( $@, '/^Illegal division by zero/', 'exception preserved after thrown_ok' ); Test-Exception-0.32/t/edge-cases.t000444001750001750 413012137063411 17271 0ustar00adrianhadrianh000000000000#! /usr/bin/perl use strict; use warnings; use Test::More skip_all => 'stuff relating to RT#24678 that I have not fixed yet'; use Test::Exception tests => 12; sub A1::DESTROY {eval{}} dies_ok { my $x = bless [], 'A1'; die } q[Unlocalized $@ for eval{} during DESTROY]; sub A2::DESTROY {die 43 } throws_ok { my $x = bless [], 'A2'; die 42} qr/42.+43/s, q[Died with the primary and secondar errors]; sub A2a::DESTROY { die 42 } throws_ok { my $obj = bless [], 'A2a'; die 43 } qr/43/, q[Of multiple failures, the "primary" one is returned]; { sub A3::DESTROY {die} dies_ok { my $x = bless [], 'A3'; 1 } q[Death during destruction for success is noticed]; } sub A4::DESTROY {delete$SIG{__DIE__};eval{}} dies_ok { my $x = bless [], 'A4'; die } q[Unlocalized $@ for eval{} during DESTROY]; sub A5::DESTROY {delete$SIG{__DIE__};die 43 } throws_ok { my $x = bless [], 'A5'; die 42} qr/42.+43/s, q[Died with the primary and secondar errors]; TODO: { our $TODO = q[No clue how to solve this one.]; sub A6::DESTROY {delete$SIG{__DIE__};die} dies_ok { my $x = bless [], 'A6'; 1 } q[Death during destruction for success is noticed]; } dies_ok { die bless [], 0 } q[Died with a "false" exception class]; dies_ok { die bless [], "\0" } q[Died with a "false" exception class]; package A7; use overload bool => sub { 0 }, '0+' => sub { 0 }, '""' => sub { '' }, fallback => 1; package main; dies_ok { die bless [], 'A7' } q[False overloaded exceptions are noticed]; $main::{'0::'} = $main::{'A7::'}; dies_ok { die bless [], 0 } q[Died a false death]; package A8; use overload bool => sub {eval{};0}, '0+' => sub{eval{};0}, '""' => sub { eval{}; '' }, fallback => 1; package main; dies_ok { die bless [], 'A8' } q[Evanescent exceptions are noticed]; __END__ dies_ok{ my $foo = Foo->new; die "Fatal Error" }; lives_ok{ my $foo = Foo->new; die "Fatal Error" }; not ok 1 # Code died, but appeared to live because $@ was reset # unexpectedly by a DESTROY method called during cleanup not ok 2 # Code died, but appeared to live because $@ was reset # unexpectedly by a DESTROY method called during cleanup Test-Exception-0.32/t/Exception.t000555001750001750 1067612137063411 17266 0ustar00adrianhadrianh000000000000#! /usr/bin/perl -Tw use strict; use warnings; use Test::Builder::Tester tests => 20; use Test::More; BEGIN { use_ok( 'Test::Exception' ) }; { package Local::Error::Simple; my %Exception_singleton; sub instance { my $class = shift; return $Exception_singleton{$class} ||= bless {}, $class; }; sub throw { my $class = shift; die $class->instance; }; package Local::Error::Test; use base qw(Local::Error::Simple); package Local::Error::Overload; use base qw(Local::Error::Simple); use overload q{""} => sub { "overloaded" }, fallback => 1; package Local::Error::NoFallback; use base qw(Local::Error::Simple); use overload q{""} => sub { "no fallback" }; }; my %Exception = map {m/([^:]+)$/; lc $1 => $_->instance} qw( Local::Error::Simple Local::Error::Test Local::Error::Overload Local::Error::NoFallback ); sub error { my $type = shift; die $Exception{$type} if exists $Exception{$type}; warn "exiting: unrecognised error type $type\n"; exit(1); }; sub no_exception { "this subroutine does not die" }; sub normal_die { die "a normal die\n" }; test_out("ok 1"); dies_ok { normal_die() }; test_test("dies_ok: die"); test_out("not ok 1 - lived. oops"); test_fail(+1); dies_ok { no_exception() } "lived. oops"; test_test("dies_ok: normal exit detected"); test_out("ok 1 - lived"); lives_ok { no_exception() } "lived"; test_test("lives_ok: normal exit"); test_out("not ok 1"); test_fail(+2); test_diag("died: a normal die"); lives_ok { normal_die() }; test_test("lives_ok: die detected"); test_out("not ok 1"); test_fail(+2); test_diag("died: Local::Error::Overload (overloaded)"); lives_ok { Local::Error::Overload->throw }; test_test("lives_ok: die detected"); test_out("ok 1 - expecting normal die"); throws_ok { normal_die() } '/normal/', 'expecting normal die'; test_test("throws_ok: regex match"); test_out("not ok 1 - should die"); test_fail(+3); test_diag("expecting: /abnormal/"); test_diag("found: a normal die"); throws_ok { normal_die() } '/abnormal/', 'should die'; test_test("throws_ok: regex bad match detected"); test_out("ok 1 - threw Local::Error::Simple"); throws_ok { Local::Error::Simple->throw } "Local::Error::Simple"; test_test("throws_ok: identical exception class"); test_out("not ok 1 - threw Local::Error::Simple"); test_fail(+3); test_diag("expecting: Local::Error::Simple"); test_diag("found: normal exit"); throws_ok { no_exception() } "Local::Error::Simple"; test_test("throws_ok: exception on normal exit"); test_out("ok 1 - threw Local::Error::Simple"); throws_ok { Local::Error::Test->throw } "Local::Error::Simple"; test_test("throws_ok: exception sub-class"); test_out("not ok 1 - threw Local::Error::Test"); test_fail(+3); test_diag("expecting: Local::Error::Test"); test_diag("found: " . Local::Error::Simple->instance); throws_ok { error("simple") } "Local::Error::Test"; test_test("throws_ok: bad sub-class match detected"); test_out("not ok 1 - threw Local::Error::Test"); test_fail(+3); test_diag("expecting: Local::Error::Test"); test_diag("found: Local::Error::Overload (overloaded)"); throws_ok { error("overload") } "Local::Error::Test"; test_test("throws_ok: throws_ok found overloaded"); test_out("not ok 1 - threw Local::Error::Overload (overloaded)"); test_fail(+3); test_diag("expecting: Local::Error::Overload (overloaded)"); test_diag("found: $Exception{test}"); throws_ok { error("test") } $Exception{overload}; test_test("throws_ok: throws_ok found overloaded"); my $e = Local::Error::Test->instance("hello"); test_out("ok 1 - threw $e"); throws_ok { error("test") } $e; test_test("throws_ok: class from object match"); test_out("ok 1 - normal exit"); throws_ok { no_exception() } qr/^$/, "normal exit"; test_test("throws_ok: normal exit matched"); test_out("ok 1"); dies_ok { error("nofallback") }; test_test("dies_ok: overload without fallback"); test_out("not ok 1"); test_fail(+2); test_diag("died: Local::Error::NoFallback (no fallback)"); lives_ok { error("nofallback") }; test_test("lives_ok: overload without fallback"); test_out("not ok 1 - threw Local::Error::Test"); test_fail(+3); test_diag("expecting: Local::Error::Test"); test_diag("found: Local::Error::NoFallback (no fallback)"); throws_ok { error("nofallback") } "Local::Error::Test"; test_test("throws_ok: throws_ok overload without fallback"); test_out("ok 1 - "); throws_ok { normal_die() } '/normal/', ''; { local $TODO = "See http://github.com/schwern/test-more/issues/issue/84"; test_test("throws_ok: can pass empty test description"); } Test-Exception-0.32/t/return.t000555001750001750 266712137063411 16630 0ustar00adrianhadrianh000000000000#! /usr/bin/perl -Tw use strict; use warnings; use Test::Builder; use Test::Harness; use Test::Builder::Tester tests => 13; use Test::More; BEGIN { use_ok( 'Test::Exception' ) }; sub div { my ($a, $b) = @_; return( $a / $b ); }; my $filename = sub { return (caller)[1] }->(); { my $ok = dies_ok { div(1, 0) } 'dies_ok passed on die'; ok($ok, 'dies_ok returned true when block dies'); } { test_out('not ok 1 - dies_ok failed'); test_fail( +1 ); my $ok = dies_ok { div(1, 1) } 'dies_ok failed'; test_test('dies_ok fails when code does not die'); ok(!$ok, 'dies_ok returned false on failure'); } { my $ok = throws_ok { div(1, 0) } '/./', 'throws_ok succeeded'; ok($ok, 'throws_ok returned true on success'); } { test_out('not ok 1 - throws_ok failed'); test_fail(+3); test_err('# expecting: /./'); test_err('# found: normal exit'); my $ok = throws_ok { div(1, 1) } '/./', 'throws_ok failed'; test_test('throws_ok fails when appropriate'); ok(!$ok, 'throws_ok returned false on failure'); } { my $ok = lives_ok { div(1, 1) } 'lives_ok succeeded'; ok($ok, 'lives_ok returned true on success'); } { test_out('not ok 1 - lives_ok failed'); test_fail(+2); test_err("# died: Illegal division by zero at $filename line 14."); my $ok = lives_ok { div(1, 0) } 'lives_ok failed'; test_test("dies_ok fails"); ok(!$ok, 'lives_ok returned false on failure'); } Test-Exception-0.32/t/stacktrace.t000444001750001750 200012137063411 17407 0ustar00adrianhadrianh000000000000#! /usr/bin/perl -Tw use strict; use warnings; use Sub::Uplevel; use Carp; use Test::Builder::Tester tests => 3; use Test::More; BEGIN { use_ok( 'Test::Exception' ) }; # This test in essence makes sure that no false # positives are encountered due to @DB::args being part # of the stacktrace # The test seems rather complex due to the fact that # we make a really tricky stacktrace test_false_positive($_) for ('/fribble/', qr/fribble/); sub throw { confess ('something unexpected') } sub try { throw->(@_) } sub test_false_positive { my $test_against_desc = my $test_against = shift; if (my $ref = ref ($test_against) ) { $test_against_desc = "$ref ($test_against_desc)" if $test_against_desc !~ /^\Q$ref\E/; } test_out("not ok 1 - threw $test_against_desc"); test_fail(+1); throws_ok { try ('fribble') } $test_against; my $exception = $@; test_diag("expecting: $test_against_desc"); test_diag(split /\n/, "found: $exception"); test_test("$test_against_desc in stacktrace ignored"); } Test-Exception-0.32/t/throws_ok.t000444001750001750 31512137063411 17271 0ustar00adrianhadrianh000000000000#! /usr/bin/perl -Tw use strict; use warnings; use Test::More tests => 2; BEGIN { use_ok( 'Test::Exception' ) }; eval { throws_ok {} undef }; like( $@, '/^throws_ok/', 'cannot pass undef to throws_ok' );