File Coverage

blib/lib/Test/Perl/Critic.pm
Criterion Covered Total %
statement 47 85 55.2
branch 4 18 22.2
condition 0 6 0.0
subroutine 13 17 76.4
pod 3 3 100.0
total 67 129 51.9


line stmt bran cond sub pod time code
1             package Test::Perl::Critic;
2              
3 2     2   18686 use 5.006001;
  2         5  
  2         65  
4              
5 2     2   8 use strict;
  2         2  
  2         48  
6 2     2   16 use warnings;
  2         2  
  2         65  
7              
8 2     2   16 use Carp qw(croak);
  2         4  
  2         151  
9 2     2   1095 use English qw(-no_match_vars);
  2         4924  
  2         12  
10 2     2   1522 use MCE::Grep chunk_size => 1;
  2         80309  
  2         12  
11              
12 2     2   447 use Test::Builder qw();
  2         2  
  2         24  
13 2     2   1030 use Perl::Critic qw();
  2         2178994  
  2         51  
14 2     2   15 use Perl::Critic::Violation qw();
  2         3  
  2         24  
15 2     2   15 use Perl::Critic::Utils;
  2         4  
  2         26  
16              
17             #---------------------------------------------------------------------------
18              
19             our $VERSION = '1.02_002';
20              
21             #---------------------------------------------------------------------------
22              
23             my $TEST = Test::Builder->new;
24             my $DIAG_INDENT = q{ };
25             my %CRITIC_ARGS = ();
26              
27             #---------------------------------------------------------------------------
28              
29             sub import {
30              
31 2     2   17 my ( $self, %args ) = @_;
32 2         4 my $caller = caller;
33              
34             {
35 2     2   1248 no strict 'refs'; ## no critic qw(ProhibitNoStrict)
  2         3  
  2         887  
  2         2  
36 2         4 *{ $caller . '::critic_ok' } = \&critic_ok;
  2         8  
37 2         4 *{ $caller . '::all_critic_ok' } = \&all_critic_ok;
  2         7  
38             }
39              
40             # -format is supported for backward compatibility
41 2 50       8 if ( exists $args{-format} ) { $args{-verbose} = $args{-format}; }
  0         0  
42 2         4 %CRITIC_ARGS = %args;
43              
44 2         7 $TEST->exported_to($caller);
45              
46 2         46 return 1;
47             }
48              
49             #---------------------------------------------------------------------------
50              
51             sub critic_ok {
52              
53 2     2 1 1522 my ( $file, $test_name ) = @_;
54 2 100       79 croak q{no file specified} if not defined $file;
55 1 50       190 croak qq{"$file" does not exist} if not -f $file;
56 0   0       $test_name ||= qq{Test::Perl::Critic for "$file"};
57              
58 0           my $critic = undef;
59 0           my @violations = ();
60 0           my $ok = 0;
61              
62             # Run Perl::Critic
63 0           my $status = eval {
64 0           $critic = Perl::Critic->new( %CRITIC_ARGS );
65 0           @violations = $critic->critique( $file );
66 0           $ok = not scalar @violations;
67 0           1;
68             };
69              
70             # Evaluate results
71 0           $TEST->ok($ok, $test_name );
72              
73 0 0 0       if (!$status || $EVAL_ERROR) { # Trap exceptions from P::C
    0          
74 0           $TEST->diag( "\n" ); # Just to get on a new line.
75 0           $TEST->diag( qq{Perl::Critic had errors in "$file":} );
76 0           $TEST->diag( qq{\t$EVAL_ERROR} );
77             }
78             elsif ( not $ok ) { # Report Policy violations
79 0           $TEST->diag( "\n" ); # Just to get on a new line.
80 0           my $verbose = $critic->config->verbose();
81 0           Perl::Critic::Violation::set_format( $verbose );
82 0           for my $viol (@violations) { $TEST->diag($DIAG_INDENT . $viol) }
  0            
83             }
84              
85 0           return $ok;
86             }
87              
88             #---------------------------------------------------------------------------
89              
90             sub all_critic_ok {
91              
92 0     0 1   my @dirs = @_;
93 0 0         if (not @dirs) {
94 0           @dirs = _starting_points();
95             }
96              
97             # Since tests are running in forked MCE workers, test results could arrive
98             # in any order. The test numbers will be meaningless, so turn them off.
99 0           $TEST->use_numbers(0);
100              
101             # The parent won't know about any of the tests that were run by the forked
102             # workers. So we disable the T::B sanity checks at the end of its life.
103 0           $TEST->no_ending(1);
104              
105 0           my @files = all_code_files( @dirs );
106 0     0     my $okays = mce_grep { critic_ok($_) } @files;
  0            
107 0           my $pass = $okays == @files;
108              
109             # To make Test::Harness happy, we must emit a test plan and a sensible exit
110             # status. Usually, T::B does this for us, but we disabled the ending above.
111 0 0         $pass || eval 'END { $? = 1 }'; ## no critic qw(Eval Interpolation)
112 0           $TEST->done_testing(scalar @files);
113              
114 0           return $pass;
115             }
116              
117             #---------------------------------------------------------------------------
118              
119             sub all_code_files {
120              
121 0     0 1   my @dirs = @_;
122 0 0         if (not @dirs) {
123 0           @dirs = _starting_points();
124             }
125              
126 0           return Perl::Critic::Utils::all_perl_files(@dirs);
127             }
128              
129             #---------------------------------------------------------------------------
130              
131             sub _starting_points {
132 0 0   0     return -e 'blib' ? 'blib' : 'lib';
133             }
134              
135             #---------------------------------------------------------------------------
136              
137             1;
138              
139              
140             __END__
141              
142             =pod
143              
144             =for stopwords API
145              
146             =head1 NAME
147              
148             Test::Perl::Critic - Use Perl::Critic in test programs
149              
150             =head1 SYNOPSIS
151              
152             Test one file:
153              
154             use Test::Perl::Critic;
155             use Test::More tests => 1;
156             critic_ok($file);
157              
158             Or test all files in one or more directories:
159              
160             use Test::Perl::Critic;
161             all_critic_ok($dir_1, $dir_2, $dir_N );
162              
163             Or test all files in a distribution:
164              
165             use Test::Perl::Critic;
166             all_critic_ok();
167              
168             Recommended usage for CPAN distributions:
169              
170             use strict;
171             use warnings;
172             use File::Spec;
173             use Test::More;
174             use English qw(-no_match_vars);
175              
176             if ( not $ENV{TEST_AUTHOR} ) {
177             my $msg = 'Author test. Set $ENV{TEST_AUTHOR} to a true value to run.';
178             plan( skip_all => $msg );
179             }
180              
181             eval { require Test::Perl::Critic; };
182              
183             if ( $EVAL_ERROR ) {
184             my $msg = 'Test::Perl::Critic required to criticise code';
185             plan( skip_all => $msg );
186             }
187              
188             my $rcfile = File::Spec->catfile( 't', 'perlcriticrc' );
189             Test::Perl::Critic->import( -profile => $rcfile );
190             all_critic_ok();
191              
192              
193             =head1 DESCRIPTION
194              
195             Test::Perl::Critic wraps the L<Perl::Critic> engine in a convenient subroutine
196             suitable for test programs written using the L<Test::More> framework. This
197             makes it easy to integrate coding-standards enforcement into the build
198             process. For ultimate convenience (at the expense of some flexibility), see
199             the L<criticism> pragma.
200              
201             If you have an large existing code base, you might prefer to use
202             L<Test::Perl::Critic::Progressive>, which allows you to clean your code
203             incrementally instead of all at once..
204              
205             If you'd like to try L<Perl::Critic> without installing anything, there is a
206             web-service available at L<http://perlcritic.com>. The web-service does not
207             support all the configuration features that are available in the native
208             Perl::Critic API, but it should give you a good idea of what Perl::Critic can
209             do.
210              
211             =head1 SUBROUTINES
212              
213             =over
214              
215             =item critic_ok( $FILE [, $TEST_NAME ] )
216              
217             Okays the test if Perl::Critic does not find any violations in $FILE. If it
218             does, the violations will be reported in the test diagnostics. The optional
219             second argument is the name of test, which defaults to "Perl::Critic test for
220             $FILE".
221              
222             If you use this form, you should load L<Test::More> and emit your own test plan
223             first or call C<done_testing()> afterwards.
224              
225             =item all_critic_ok( [ @DIRECTORIES ] )
226              
227             Runs C<critic_ok()> for all Perl files beneath the given list of
228             C<@DIRECTORIES>. If C<@DIRECTORIES> is empty or not given, this function
229             tries to find all Perl files in the F<blib/> directory. If the F<blib/>
230             directory does not exist, then it tries the F<lib/> directory. Returns true
231             if all files are okay, or false if any file fails.
232              
233             This subroutine emits its own test plan, so you do not need to specify the
234             expected number of tests or call C<done_testing()>. Therefore, C<all_critic_ok>
235             generally cannot be used in a test script that includes other sorts of tests.
236              
237             =item all_code_files ( [@DIRECTORIES] )
238              
239             B<DEPRECATED:> Use the C<all_perl_files> subroutine that is exported by
240             L<Perl::Critic::Utils> instead.
241              
242             Returns a list of all the Perl files found beneath each DIRECTORY, If
243             @DIRECTORIES is an empty list, defaults to F<blib/>. If F<blib/> does not
244             exist, it tries F<lib/>. Skips any files in CVS or Subversion directories.
245              
246             A Perl file is:
247              
248             =over
249              
250             =item * Any file that ends in F<.PL>, F<.pl>, F<.pm>, or F<.t>
251              
252             =item * Any file that has a first line with a shebang containing 'perl'
253              
254             =back
255              
256             =back
257              
258             =head1 CONFIGURATION
259              
260             L<Perl::Critic> is highly configurable. By default, Test::Perl::Critic
261             invokes Perl::Critic with its default configuration. But if you have
262             developed your code against a custom Perl::Critic configuration, you will want
263             to configure Test::Perl::Critic to do the same.
264              
265             Any arguments passed through the C<use> pragma (or via C<<
266             Test::Perl::Critic->import() >> )will be passed into the L<Perl::Critic>
267             constructor. So if you have developed your code using a custom
268             F<~/.perlcriticrc> file, you can direct L<Test::Perl::Critic> to use your
269             custom file too.
270              
271             use Test::Perl::Critic (-profile => 't/perlcriticrc');
272             all_critic_ok();
273              
274             Now place a copy of your own F<~/.perlcriticrc> file in the distribution as
275             F<t/perlcriticrc>. Then, C<critic_ok()> will be run on all Perl files in this
276             distribution using this same Perl::Critic configuration. See the
277             L<Perl::Critic> documentation for details on the F<.perlcriticrc> file format.
278              
279             Any argument that is supported by the L<Perl::Critic> constructor can be
280             passed through this interface. For example, you can also set the minimum
281             severity level, or include & exclude specific policies like this:
282              
283             use Test::Perl::Critic (-severity => 2, -exclude => ['RequireRcsKeywords']);
284             all_critic_ok();
285              
286             See the L<Perl::Critic> documentation for complete details on its
287             options and arguments.
288              
289             =head1 DIAGNOSTIC DETAILS
290              
291             By default, Test::Perl::Critic displays basic information about each Policy
292             violation in the diagnostic output of the test. You can customize the format
293             and content of this information by using the C<-verbose> option. This behaves
294             exactly like the C<-verbose> switch on the F<perlcritic> program. For
295             example:
296              
297             use Test::Perl::Critic (-verbose => 6);
298              
299             #or...
300              
301             use Test::Perl::Critic (-verbose => '%f: %m at %l');
302              
303             If given a number, L<Test::Perl::Critic> reports violations using one of the
304             predefined formats described below. If given a string, it is interpreted to be
305             an actual format specification. If the C<-verbose> option is not specified, it
306             defaults to 3.
307              
308             Verbosity Format Specification
309             ----------- -------------------------------------------------------
310             1 "%f:%l:%c:%m\n",
311             2 "%f: (%l:%c) %m\n",
312             3 "%m at %f line %l\n",
313             4 "%m at line %l, column %c. %e. (Severity: %s)\n",
314             5 "%f: %m at line %l, column %c. %e. (Severity: %s)\n",
315             6 "%m at line %l, near '%r'. (Severity: %s)\n",
316             7 "%f: %m at line %l near '%r'. (Severity: %s)\n",
317             8 "[%p] %m at line %l, column %c. (Severity: %s)\n",
318             9 "[%p] %m at line %l, near '%r'. (Severity: %s)\n",
319             10 "%m at line %l, column %c.\n %p (Severity: %s)\n%d\n",
320             11 "%m at line %l, near '%r'.\n %p (Severity: %s)\n%d\n"
321              
322             Formats are a combination of literal and escape characters similar to the way
323             C<sprintf> works. See L<String::Format> for a full explanation of the
324             formatting capabilities. Valid escape characters are:
325              
326             Escape Meaning
327             ------- ----------------------------------------------------------------
328             %c Column number where the violation occurred
329             %d Full diagnostic discussion of the violation (DESCRIPTION in POD)
330             %e Explanation of violation or page numbers in PBP
331             %F Just the name of the logical file where the violation occurred.
332             %f Path to the logical file where the violation occurred.
333             %G Just the name of the physical file where the violation occurred.
334             %g Path to the physical file where the violation occurred.
335             %l Logical line number where the violation occurred
336             %L Physical line number where the violation occurred
337             %m Brief description of the violation
338             %P Full name of the Policy module that created the violation
339             %p Name of the Policy without the Perl::Critic::Policy:: prefix
340             %r The string of source code that caused the violation
341             %C The class of the PPI::Element that caused the violation
342             %s The severity level of the violation
343              
344              
345             =head1 CAVEATS
346              
347             Despite the convenience of using a test script to enforce your coding
348             standards, there are some inherent risks when distributing those tests to
349             others. Since you don't know which version of L<Perl::Critic> the end-user
350             has and whether they have installed any additional Policy modules, you can't
351             really be sure that your code will pass the Test::Perl::Critic tests on
352             another machine.
353              
354             B<For these reasons, we strongly advise you to make your perlcritic tests
355             optional, or exclude them from the distribution entirely.>
356              
357             The recommended usage in the L<"SYNOPSIS"> section illustrates one way to make
358             your F<perlcritic.t> test optional. Another option is to put F<perlcritic.t>
359             and other author-only tests in a separate directory (F<xt/> seems to be
360             common), and then use a custom build action when you want to run them. Also,
361             you should B<not> list Test::Perl::Critic as a requirement in your build
362             script. These tests are only relevant to the author and should not be a
363             prerequisite for end-use.
364              
365             See L<http://chrisdolan.net/talk/2005/11/14/private-regression-tests/>
366             for an interesting discussion about Test::Perl::Critic and other types
367             of author-only regression tests.
368              
369             =head1 EXPORTS
370              
371             critic_ok()
372             all_critic_ok()
373              
374             =head1 BUGS
375              
376             If you find any bugs, please submit them to
377             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Perl-Critic>. Thanks.
378              
379              
380             =head1 SEE ALSO
381              
382             L<Module::Starter::PBP>
383              
384             L<Perl::Critic>
385              
386             L<Test::More>
387              
388             =head1 CREDITS
389              
390             Andy Lester, whose L<Test::Pod> module provided most of the code and
391             documentation for Test::Perl::Critic. Thanks, Andy.
392              
393             =head1 AUTHOR
394              
395             Jeffrey Ryan Thalhammer <jeff@thaljef.org>
396              
397             =head1 COPYRIGHT
398              
399             Copyright (c) 2005-2014 Jeffrey Ryan Thalhammer.
400              
401             This program is free software; you can redistribute it and/or modify
402             it under the same terms as Perl itself. The full text of this license
403             can be found in the LICENSE file included with this module.
404              
405             =cut
406              
407             ##############################################################################
408             # Local Variables:
409             # mode: cperl
410             # cperl-indent-level: 4
411             # fill-column: 78
412             # indent-tabs-mode: nil
413             # c-indentation-style: bsd
414             # End:
415             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :