File Coverage

blib/lib/Test/Perl/Critic.pm
Criterion Covered Total %
statement 47 79 59.4
branch 4 18 22.2
condition 0 6 0.0
subroutine 13 15 86.6
pod 2 2 100.0
total 66 120 55.0


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