| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Assert::Refute::T::Errors; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 11 |  |  | 11 |  | 547496 | use 5.006; | 
|  | 11 |  |  |  |  | 120 |  | 
| 4 | 11 |  |  | 11 |  | 75 | use strict; | 
|  | 11 |  |  |  |  | 30 |  | 
|  | 11 |  |  |  |  | 303 |  | 
| 5 | 11 |  |  | 11 |  | 93 | use warnings; | 
|  | 11 |  |  |  |  | 25 |  | 
|  | 11 |  |  |  |  | 630 |  | 
| 6 |  |  |  |  |  |  | our $VERSION = '0.17'; | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | =head1 NAME | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | Assert::Refute::T::Errors - exception and warning check for Assert::Refute suite | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | use Assert::Refute qw(:all); | 
| 15 |  |  |  |  |  |  | use Assert::Refute::T::Errors; | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | my $c = contract { | 
| 18 |  |  |  |  |  |  | my $foo = shift; | 
| 19 |  |  |  |  |  |  | dies_like { | 
| 20 |  |  |  |  |  |  | $foo->bar; | 
| 21 |  |  |  |  |  |  | } "Bar requires an argument"; | 
| 22 |  |  |  |  |  |  | dies_like { | 
| 23 |  |  |  |  |  |  | $foo->bar(1); | 
| 24 |  |  |  |  |  |  | } '', "Bar works fine with 1"; | 
| 25 |  |  |  |  |  |  | }; | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | $c->apply( $my_foo ); # check whether foo lives/dies as expected | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | Ditto with L (although there are more fine-grained L | 
| 30 |  |  |  |  |  |  | and L): | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | use Test::More; | 
| 33 |  |  |  |  |  |  | use Assert::Refute::T::Errors; # always *after* Test::More | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | use My::Module; | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | dies_like { | 
| 38 |  |  |  |  |  |  | My::Module->foo; | 
| 39 |  |  |  |  |  |  | } qw/foo requires/, "Epmty argument prohibited"; | 
| 40 |  |  |  |  |  |  | dies_like { | 
| 41 |  |  |  |  |  |  | My::Module->bar; | 
| 42 |  |  |  |  |  |  | } '', "Works without arguments"; | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | =head1 EXPORTED FUNCTIONS | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | All functions below are exported by default. | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | =cut | 
| 49 |  |  |  |  |  |  |  | 
| 50 | 11 |  |  | 11 |  | 88 | use Carp; | 
|  | 11 |  |  |  |  | 21 |  | 
|  | 11 |  |  |  |  | 750 |  | 
| 51 | 11 |  |  | 11 |  | 3617 | use parent qw(Exporter); | 
|  | 11 |  |  |  |  | 2529 |  | 
|  | 11 |  |  |  |  | 62 |  | 
| 52 |  |  |  |  |  |  | our @EXPORT = qw(foobar); | 
| 53 |  |  |  |  |  |  |  | 
| 54 | 11 |  |  | 11 |  | 4223 | use Assert::Refute::Build; | 
|  | 11 |  |  |  |  | 30 |  | 
|  | 11 |  |  |  |  | 727 |  | 
| 55 | 11 |  |  | 11 |  | 4864 | use Assert::Refute::Contract; | 
|  | 11 |  |  |  |  | 29 |  | 
|  | 11 |  |  |  |  | 4797 |  | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | =head2 dies_like | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | dies_like { | 
| 60 |  |  |  |  |  |  | # shoddy code here | 
| 61 |  |  |  |  |  |  | } 'pattern', 'explanation'; | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | Check that supplied code throws the expected exception. | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | If pattern is empty, expect the code to live through. | 
| 66 |  |  |  |  |  |  |  | 
| 67 |  |  |  |  |  |  | Otherwise convert it to regular expression if needed | 
| 68 |  |  |  |  |  |  | and match C<$@> against it. | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | =cut | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  | build_refute dies_like => sub { | 
| 73 | 25 |  |  | 25 |  | 70 | my ($block, $rex) = @_; | 
| 74 |  |  |  |  |  |  |  | 
| 75 | 25 |  |  |  |  | 47 | my $lived = eval { | 
| 76 | 25 |  |  |  |  | 77 | $block->(); | 
| 77 | 4 |  |  |  |  | 14 | 1; | 
| 78 |  |  |  |  |  |  | }; | 
| 79 |  |  |  |  |  |  |  | 
| 80 | 25 | 100 |  |  |  | 793 | if ($rex) { | 
| 81 | 21 |  |  |  |  | 118 | $rex = qr/$rex/; | 
| 82 | 21 | 100 |  |  |  | 68 | return "Block didn't die" if $lived; | 
| 83 | 20 | 50 |  |  |  | 53 | return "Exception wasn't true" unless $@; | 
| 84 | 20 | 100 |  |  |  | 260 | return $@ =~ $rex ? '' : "Exception was: $@\nExpected: $rex"; | 
| 85 |  |  |  |  |  |  | } else { | 
| 86 | 4 | 100 |  |  |  | 21 | return if $lived; | 
| 87 | 1 | 50 |  |  |  | 8 | return $@ | 
| 88 |  |  |  |  |  |  | ? "Exception was: $@\nExpected to live" | 
| 89 |  |  |  |  |  |  | : Carp::shortmess "Block died"."Expected to live"; | 
| 90 |  |  |  |  |  |  | } | 
| 91 |  |  |  |  |  |  | }, block => 1, export => 1, args => 1; | 
| 92 |  |  |  |  |  |  |  | 
| 93 |  |  |  |  |  |  | =head2 warns_like { ... } | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | warns_like { | 
| 96 |  |  |  |  |  |  | warn "Foo"; | 
| 97 |  |  |  |  |  |  | warn "Bar"; | 
| 98 |  |  |  |  |  |  | } [qr/Foo/, "Bar"], "Human comment"; | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | warns_like { | 
| 101 |  |  |  |  |  |  | # Shoddy code here | 
| 102 |  |  |  |  |  |  | } '', "No warnings"; | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | Check that exactly the specified warnings were emitted by block. | 
| 105 |  |  |  |  |  |  | A single string or regex value is accepted and converted to 1-element array. | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | An empty array or a false value mean no warnings at all. | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | Note that this block does NOT catch exceptions. | 
| 110 |  |  |  |  |  |  | This MAY change in the future. | 
| 111 |  |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | =cut | 
| 113 |  |  |  |  |  |  |  | 
| 114 |  |  |  |  |  |  | # TODO better diagnostic | 
| 115 |  |  |  |  |  |  | my $multi_like = Assert::Refute::Contract->new( code => sub { | 
| 116 |  |  |  |  |  |  | my ($self, $got, $exp) = @_; | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | for (my $i = 0; $i < @$got or $i < @$exp; $i++) { | 
| 119 |  |  |  |  |  |  | defined $exp->[$i] | 
| 120 |  |  |  |  |  |  | ? $self->like( $got->[$i], $exp->[$i] ) | 
| 121 |  |  |  |  |  |  | : $self->is ( $got->[$i], undef ); | 
| 122 |  |  |  |  |  |  | }; | 
| 123 |  |  |  |  |  |  | }, need_object => 1 ); | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | build_refute warns_like => sub { | 
| 126 | 11 |  |  | 11 |  | 32 | my ($block, $exp) = @_; | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 11 | 100 |  |  |  | 49 | $exp = $exp ? [ $exp ] : [] | 
|  |  | 100 |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | unless ref $exp eq 'ARRAY'; | 
| 130 | 11 |  |  |  |  | 61 | $_ = qr/$_/ for @$exp; | 
| 131 |  |  |  |  |  |  |  | 
| 132 | 11 |  |  |  |  | 20 | my @warn; | 
| 133 |  |  |  |  |  |  | { | 
| 134 | 11 |  |  | 9 |  | 18 | local $SIG{__WARN__} = sub { push @warn, shift }; | 
|  | 11 |  |  |  |  | 73 |  | 
|  | 9 |  |  |  |  | 540 |  | 
| 135 | 11 |  |  |  |  | 33 | $block->(); | 
| 136 |  |  |  |  |  |  | }; | 
| 137 |  |  |  |  |  |  |  | 
| 138 | 11 |  |  |  |  | 62 | my $c = $multi_like->apply( \@warn, $exp ); | 
| 139 | 11 | 100 |  |  |  | 30 | return $c->is_passing ? '' : $c->get_tap; | 
| 140 |  |  |  |  |  |  | }, block => 1, args => 1, export => 1; | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | =head1 LICENSE AND COPYRIGHT | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | This module is part of L suite. | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | Copyright 2017-2018 Konstantin S. Uvarin. C<<  >> | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | This program is free software; you can redistribute it and/or modify it | 
| 149 |  |  |  |  |  |  | under the terms of the the Artistic License (2.0). You may obtain a | 
| 150 |  |  |  |  |  |  | copy of the full license at: | 
| 151 |  |  |  |  |  |  |  | 
| 152 |  |  |  |  |  |  | L | 
| 153 |  |  |  |  |  |  |  | 
| 154 |  |  |  |  |  |  | =cut | 
| 155 |  |  |  |  |  |  |  | 
| 156 |  |  |  |  |  |  | 1; |