File Coverage

lib/Test/NoBreakpoints.pm
Criterion Covered Total %
statement 60 65 92.3
branch 24 34 70.5
condition 3 6 50.0
subroutine 9 10 90.0
pod 3 3 100.0
total 99 118 83.9


line stmt bran cond sub pod time code
1             # ABSTRACT: test that files do not contain soft breakpoints
2              
3              
4             package Test::NoBreakpoints;
5             {
6             $Test::NoBreakpoints::VERSION = '0.15';
7             }
8             {
9             $Test::NoBreakpoints::DIST = 'Test-NoBreakpoints';
10             }
11              
12 5     5   299036 use strict;
  5         13  
  5         225  
13              
14 5     5   37 use File::Spec;
  5         17  
  5         121  
15 5     5   26 use File::Find;
  5         22  
  5         459  
16 5     5   132 use Test::Builder;
  5         11  
  5         183  
17              
18             require Exporter;
19 5     5   29 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  5         16  
  5         6416  
20              
21             @ISA = 'Exporter';
22             @EXPORT = qw|
23             all_files_no_breakpoints_ok
24             all_files_no_brkpts_ok
25             no_breakpoints_ok
26             no_brkpts_ok
27             |;
28             @EXPORT_OK = qw|all_perl_files|;
29             %EXPORT_TAGS = (
30             all => [ @EXPORT, @EXPORT_OK ],
31             );
32              
33             # get a Test singleton to use
34             my $Test = Test::Builder->new;
35              
36             # a regular expression to find soft breakpoints
37             my $brkpt_rx = qr/
38             ( # match it
39             \$DB # The DB package
40             (?:::|') # Perl 4 or 5 package seperator
41             si(?:ngle|gnal) # signal or single
42             \s*=\s* # an equal with optional whitespace
43             [1-9] # a digit other than zero
44             # (am I being stupid here? Is there
45             ) # no easier way to say that?)
46             /x;
47              
48             # check that there are no breakpoints in a file
49             sub no_breakpoints_ok($;$)
50             {
51            
52 21     21 1 23663 my($file, $name) = @_;
53 21   66     113 $name ||= "no breakpoint test of $file";
54            
55             # slurp in the file
56 21         23 my $fh;
57 21 50       762 unless( open($fh, $file) ) {
58 0         0 $Test->ok(0, $name);
59 0         0 $Test->diag("could not open $file: $!");
60 0         0 return;
61             }
62 21         33 my $text = do { local( $/ ) ; <$fh> } ;
  21         57  
  21         486  
63 21         196 close($fh);
64            
65             # check the file against our regex
66 21         152 my($matched) = $text =~ m/$brkpt_rx/;
67 21 100       47 if( ! $matched ) {
68 11         66 $Test->ok(1, $name);
69             }
70             else {
71 10         61 $Test->ok(0, $name);
72 10         1091 $Test->diag("breakpoint found in $file: $matched");
73             }
74            
75 21 100       1424 return $matched ? 0 : 1;
76            
77             }
78              
79             # find all perl files in a given directory
80             # graciously borrwed from Test::Pod::all_pod_files by
81             # Andy Lester / brian d foy
82             sub all_perl_files
83             {
84              
85 2 50   2 1 153 my @queue = @_ ? @_ : _starting_points();
86 2         6 my @files = ();
87              
88 2         9 while ( @queue ) {
89 48         69 my $file = shift @queue;
90 48 100       600 if ( -d $file ) {
91 8         18 local *DH;
92 8 50       242 opendir DH, $file or next;
93 8         136 my @newfiles = readdir DH;
94 8         100 closedir DH;
95              
96 8         141 @newfiles = File::Spec->no_upwards( @newfiles );
97 8 50       20 @newfiles = grep { $_ ne "CVS" && $_ ne ".svn" } @newfiles;
  46         179  
98              
99 8         68 push @queue, map "$file/$_", @newfiles;
100             }
101 48 100       526 if ( -f $file ) {
102 40 100       675 push @files, $file if _is_perl( $file );
103             }
104             } # while
105              
106 2         29 return @files;
107              
108             }
109              
110              
111             sub _starting_points {
112 0 0   0   0 return 'blib' if -e 'blib';
113 0         0 return 'lib';
114             }
115              
116             sub _is_perl {
117 40     40   54 my $file = shift;
118              
119 40 50       90 return 1 if $file =~ /\.PL$/;
120 40 100       93 return 1 if $file =~ /\.p(l|m)$/;
121 36 100       168 return 1 if $file =~ /\.t$/;
122              
123 14         21 local *FH;
124 14 50       418 open FH, $file or return;
125 14         143 my $first = ;
126 14         124 close FH;
127              
128 14 50 33     71 return 1 if defined $first && ($first =~ /^#!.*perl/);
129              
130 14         57 return;
131             }
132              
133             # run no_breakpoints_ok on all files in a given directory
134             sub all_files_no_breakpoints_ok
135             {
136              
137 1 50   1 1 7 my @files = @_ ? @_ : all_perl_files();
138              
139 1         2 my $ok = 1; # presume all succeed
140 1         3 for( @files ) {
141 13 100       23 no_breakpoints_ok($_) or $ok = 0;
142             }
143 1         5 return $ok;
144            
145             }
146              
147             # keep require happy
148             1;
149              
150              
151              
152              
153             =pod
154              
155             =head1 NAME
156              
157             Test::NoBreakpoints - test that files do not contain soft breakpoints
158              
159             =head1 VERSION
160              
161             version 0.15
162              
163             =head1 SYNOPSIS
164              
165             use Test::NoBreakpoints;
166             plan tests => $num_tests;
167             no_breakpoints_ok( $file, 'Contains no soft breakpoints' );
168              
169             Module authors can include the following in a t/nobreakpoints.t file to add
170             such checking to a module distribution:
171              
172             use Test::More;
173             eval "use Test::NoBreakpoints 0.10";
174             plan skip_all => "Test::NoBreakpoints 0.10 required for testing" if $@;
175             all_files_no_breakpoints_ok();
176              
177             =head1 DESCRIPTION
178              
179             I love soft breakpoints (C<$DB::single = 1>) in the Perl debugger.
180             Unfortunately, I have a habit of putting them in my code during development
181             and forgetting to take them out before I upload it to CPAN, necessitating a
182             hasty fix/package/bundle cycle followed by much cursing.
183              
184             Test::NoBreakpoints checks that files contain neither the string
185             C<$DB::single = 1> nor C<$DB::signal = 1>. By adding such a test to all my
186             modules, I swear less and presumably lighten the load on the CPAN in some
187             small way.
188              
189             =head1 FUNCTIONS
190              
191             Unless otherwise noted, all functions are tests built on top of
192             Test::Builder, so the standard admonition about having made a plan before
193             you run them apply.
194              
195             =head2 no_breakpoints_ok($file, [$description] )
196              
197             Checks that $file contains no breakpoints. If the optional $description is
198             not passed it defaults to "no breakpoint test of $file".
199              
200             If the test fails, the line number of the file where the breakpoint was
201             found will be emitted.
202              
203             For compatibility with old versions of this module, the deprecated name
204             C may also be used (but see L).
205              
206             =head2 all_perl_files( [@dirs] )
207              
208             Returns a list of all F<*.pl>, F<*.pm> and F<*.t> files in the directories
209             listed. If C<@dirs> is not passed, defaults to C and C.
210              
211             The order of the files returned is machine-dependent. If you want them
212             sorted, you'll have to sort them yourself.
213              
214             =head2 all_files_no_breakpoints_ok( [@files] )
215              
216             Checks all files that look like they contain Perl using no_breakpoints_ok(). If
217             C<@files> is not provided, it defaults to the return of B.
218              
219             For compatibility with old versions of this module, the deprecated name
220             C may also be used (but see L
221             FUNCTIONS">).
222              
223             =head1 EXPORTS
224              
225             By default B and B.
226              
227             For the time being, the deprecated forms the above
228             (B and B) are also exported (but see
229             L).
230              
231             On request, B.
232              
233             Everything with the tag B<:all>.
234              
235             =head1 DEPRECATED FUNCTIONS
236              
237             Prior to v0.13 of this module, no_breakpoints_ok was called no_brkpts_ok and
238             all_files_no_breakpoints_ok was similarly abbreviated.
239              
240             In v0.13, these older names were deprecated. They are still exported by
241             default, but will emit a warning unless you disable the B
242             lexical warning category:
243              
244             {
245             no warnings 'deprecated';
246             no_brkpts_ok(...);
247             }
248              
249             In the next release, the deprecated functions will have to be pulled in via
250             an import tag. In the release after that, they will cease to be.
251              
252             =head1 ACKNOWLEDGEMENTS
253              
254             Michael Schwern for Test::Builder.
255              
256             Andy Lester for Test::Pod, which is where I got the idea and borrowed the
257             logic of B from.
258              
259             =head1 BUGS
260              
261             =over 4
262              
263             =item * doesn't catch some breakpoints
264              
265             This is a valid breakpoint:
266              
267             package DB;
268             $single = 1;
269             package main;
270              
271             as is this:
272              
273             my $break = \$DB::single;
274             $$break = 1;
275              
276             but neither are currently caught.
277              
278             =back
279              
280             =head1 TODO
281              
282             =over 4
283              
284             =item * enhance regex to find esoteric setting of breakpoints
285              
286             If you have a legitimate breakpoint set that isn't caught, please send me an
287             example and I'll try to augment the regex to match it.
288              
289             =item * only look at code rather than the entire file
290              
291             This is not as easy as simply stripping out POD, because there might be
292             inline tests or examples that are code in there (using Test::Inline).
293             Granted, those should be caught when the generated .t files are themselves
294             tested, but I'd like to make it smarter.
295              
296             =item * not use regular expressions
297              
298             The ideal way to find a breakpoint would be to compile the code and then
299             walk the opcode tree to find places where the breakpoint is set.
300             B::FindAmpersand does something similar to this to find use of the C<$&> in
301             regular expressions, so this is probably the direction I'm going to head in.
302              
303             =back
304              
305             =head1 SEE ALSO
306              
307             L
308              
309             L
310              
311             =head1 AUTHORS
312              
313             =over 4
314              
315             =item *
316              
317             James FitzGibbon
318              
319             =item *
320              
321             Apocalypse
322              
323             =item *
324              
325             Chisel
326              
327             =back
328              
329             =head1 COPYRIGHT AND LICENSE
330              
331             This software is copyright (c) 2012 by James FitzGibbon and Chisel Wright.
332              
333             This is free software; you can redistribute it and/or modify it under
334             the same terms as the Perl 5 programming language system itself.
335              
336             =cut
337              
338              
339             __END__