Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Test::Deep expectations #16

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile.PL
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ my %WriteMakefileArgs = (
test => {
requires => {
'Test::More' => '0.7',
'Test::Deep' => '0',
'overload' => '0',
},
},
Expand Down
51 changes: 43 additions & 8 deletions lib/Test/Exception.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use warnings;
package Test::Exception;
use Test::Builder;
use Sub::Uplevel qw( uplevel );
use Scalar::Util;
use base qw( Exporter );

our $VERSION = '0.43';
Expand Down Expand Up @@ -170,6 +171,7 @@ 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
throws_ok BLOCK TEST_DEEP_EXPECTATION, TEST_DESCRIPTION

In the first form the test passes if the stringified exception matches the give regular expression. For example:

Expand All @@ -190,6 +192,21 @@ You can get the same effect by passing an instance of the exception you want to
my $SIMPLE = Error::Simple->new;
throws_ok { $foo->bar } $SIMPLE, 'simple error';

The third form allows usage of L<Test::Deep> to write more complex tests.
L<Test::Deep> itself is not imported by L<Test::Exception>.

throws_ok
{ code that should throw exception }
all (
obj_isa ('Expected::Exception::Instance'),
methods (
errcode => 400,
errstr => re (qr/foo/),
)
),
'description',
;

Should a throws_ok() test fail it produces appropriate diagnostic messages. For example:

not ok 3 - simple error
Expand All @@ -213,6 +230,12 @@ form part of the string that throws_ok regular expressions match against.
=cut


sub is_test_deep_cmp {
my ( $expecting ) = @_;

return Scalar::Util::blessed( $expecting ) && $expecting->isa( 'Test::Deep::Cmp' );
}

sub throws_ok (&$;$) {
my ( $coderef, $expecting, $description ) = @_;
unless (defined $expecting) {
Expand All @@ -222,16 +245,28 @@ sub throws_ok (&$;$) {
$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 )
};
my ( $ok, $stack );
my $is_test_deep_cmp = is_test_deep_cmp( $expecting );

if ( $is_test_deep_cmp ) {
( $ok, $stack ) = Test::Deep::cmp_details( $exception, $expecting );
} else {
my $regex = $Tester->maybe_regex( $expecting );
$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 ) );
if ( $is_test_deep_cmp ) {
$Tester->diag( Test::Deep::deep_diag( $stack ) );
} else {
$Tester->diag( _exception_as_string( "expecting:", $expecting ) );
$Tester->diag( _exception_as_string( "found:", $exception ) );
}
};
$@ = $exception;
return $ok;
Expand Down
39 changes: 39 additions & 0 deletions t/throws-ok-with-test-deep.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env perl

use strict;
use warnings;

use Test::More tests => 2;
use Test::Deep;

BEGIN { use_ok( 'Test::Exception' ) };

throws_ok
{ die Local::Error->new( code => 404, message => 'Not Found' ) }
all(
obj_isa( 'Local::Error' ),
methods(
code => 404,
message => re( qr/found/i ),
),
),
'should recognize Test::Deep::Cmp expectation'
;

package
Local::Error;

sub new {
my ( $class, %params ) = @_;

bless \%params, $class;
}

sub code {
$_[0]->{code};
}

sub message {
$_[0]->{message};
}