File Coverage

blib/lib/Test/Warnings.pm
Criterion Covered Total %
statement 57 57 100.0
branch 15 16 93.7
condition 20 23 86.9
subroutine 16 16 100.0
pod 5 5 100.0
total 113 117 96.5


line stmt bran cond sub pod time code
1 22     22   1377014 use strict;
  22         189  
  22         602  
2 22     22   106 use warnings;
  22         34  
  22         1115  
3             package Test::Warnings; # git description: v0.029-2-g97d1c9f
4             # vim: set ts=8 sts=4 sw=4 tw=115 et :
5             # ABSTRACT: Test for warnings and the lack of them
6             # KEYWORDS: testing tests warnings
7              
8             our $VERSION = '0.030';
9              
10 22     22   9151 use parent 'Exporter';
  22         6241  
  22         107  
11 22     22   1112 use Test::Builder;
  22         42  
  22         11326  
12              
13             our @EXPORT_OK = qw(
14             allow_warnings allowing_warnings
15             had_no_warnings
16             warnings warning
17             );
18             our %EXPORT_TAGS = ( all => \@EXPORT_OK );
19              
20             my $warnings_allowed;
21             my $forbidden_warnings_found;
22             my $done_testing_called;
23             my $no_end_test;
24             my $fail_on_warning;
25             my $report_warnings;
26             my @collected_warnings;
27              
28             sub import
29             {
30 23     23   173 my $class = shift @_;
31              
32 23         69 my %names; @names{@_} = ();
  23         67  
33             # END block will check for this status
34 23         48 $no_end_test = exists $names{':no_end_test'};
35             # __WARN__ handler will check for this status
36 23         36 $fail_on_warning = exists $names{':fail_on_warning'};
37             # Collect and report warnings at the end
38 23         47 $report_warnings = exists $names{':report_warnings'};
39              
40 23         60 delete @names{qw(:no_end_test :fail_on_warning :report_warnings)};
41 23         16144 __PACKAGE__->export_to_level(1, $class, keys %names);
42             }
43              
44             # for testing this module only!
45             my $tb;
46             sub _builder(;$)
47             {
48 38 100   38   2970 if (not @_)
49             {
50 35   66     149 $tb ||= Test::Builder->new;
51 35         237 return $tb;
52             }
53              
54 3         8 $tb = shift;
55             }
56              
57             my $_orig_warn_handler = $SIG{__WARN__};
58             $SIG{__WARN__} = sub {
59             if ($warnings_allowed)
60             {
61             Test::Builder->new->note($_[0]);
62             }
63             else
64             {
65             $forbidden_warnings_found++;
66             push @collected_warnings, $_[0] if $report_warnings;
67              
68             # TODO: this doesn't handle blessed coderefs... does anyone care?
69             goto &$_orig_warn_handler if $_orig_warn_handler
70             and ( (ref $_orig_warn_handler eq 'CODE')
71             or ($_orig_warn_handler ne 'DEFAULT'
72             and $_orig_warn_handler ne 'IGNORE'
73             and defined &$_orig_warn_handler));
74              
75             if ($_[0] =~ /\n$/) {
76             warn $_[0];
77             } else {
78             require Carp;
79             Carp::carp($_[0]);
80             }
81             _builder->ok(0, 'unexpected warning') if $fail_on_warning;
82             }
83             };
84              
85             sub warnings(;&)
86             {
87             # if someone manually does warnings->import in the same namespace this is
88             # imported into, this sub will be called. in that case, just return the
89             # string "warnings" so it calls the correct method.
90 12 100   12 1 3643 if (!@_) {
91 1         43 return 'warnings';
92             }
93 11         21 my $code = shift;
94 11         16 my @warnings;
95             local $SIG{__WARN__} = sub {
96 10     10   142 push @warnings, shift;
97 11         57 };
98 11         35 $code->();
99 11         1253 @warnings;
100             }
101              
102             sub warning(&)
103             {
104 4     4 1 1814 my @warnings = &warnings(@_);
105 4 100       22 return @warnings == 1 ? $warnings[0] : \@warnings;
106             }
107              
108             if (Test::Builder->can('done_testing'))
109             {
110             # monkeypatch Test::Builder::done_testing:
111             # check for any forbidden warnings, and record that we have done so
112             # so we do not check again via END
113              
114 22     22   202 no strict 'refs';
  22         42  
  22         962  
115             my $orig = *{'Test::Builder::done_testing'}{CODE};
116 22     22   125 no warnings 'redefine';
  22         75  
  22         8038  
117             *{'Test::Builder::done_testing'} = sub {
118             # only do this at the end of all tests, not at the end of a subtest
119 16     16   23961 my $builder = _builder;
120 16         109 my $in_subtest_sub = $builder->can('in_subtest');
121 16 50 100     78 if (not $no_end_test
    100          
122             and not ($in_subtest_sub ? $builder->$in_subtest_sub : $builder->parent))
123             {
124 4         493 local $Test::Builder::Level = $Test::Builder::Level + 3;
125 4         18 had_no_warnings('no (unexpected) warnings (via done_testing)');
126 4         9 $done_testing_called = 1;
127             }
128              
129 16         187 $orig->(@_);
130             };
131             }
132              
133             END {
134 19 100 100 19   19249 if (not $no_end_test
      100        
      100        
135             and not $done_testing_called
136             # skip this if there is no plan and no tests have been run (e.g.
137             # compilation tests of this module!)
138             and (_builder->expected_tests or _builder->current_test > 0)
139             )
140             {
141 2         226 local $Test::Builder::Level = $Test::Builder::Level + 1;
142 2         7 had_no_warnings('no (unexpected) warnings (via END block)');
143             }
144             }
145              
146             # setter
147             sub allow_warnings(;$)
148             {
149 3 100 66 3 1 24 $warnings_allowed = @_ || defined $_[0] ? $_[0] : 1;
150             }
151              
152             # getter
153 3     3 1 20 sub allowing_warnings() { $warnings_allowed }
154              
155             # call at any time to assert no (unexpected) warnings so far
156             sub had_no_warnings(;$)
157             {
158 9   100 9 1 394 _builder->ok(!$forbidden_warnings_found, shift || 'no (unexpected) warnings');
159 9 100 66     2824 if ($report_warnings and $forbidden_warnings_found) {
160 1         3 _builder->diag("Got the following unexpected warnings:");
161 1         102 for my $i (1 .. @collected_warnings) {
162 1         3 _builder->diag(" $i: $collected_warnings[ $i - 1 ]");
163             }
164             }
165             }
166              
167             1;
168              
169             __END__