File Coverage

blib/lib/Test/Perl/Critic/Policy.pm
Criterion Covered Total %
statement 112 142 78.8
branch 23 42 54.7
condition 2 6 33.3
subroutine 21 26 80.7
pod 1 1 100.0
total 159 217 73.2


line stmt bran cond sub pod time code
1             package Test::Perl::Critic::Policy;
2              
3 1     1   573 use 5.010001;
  1         10  
4              
5 1     1   5 use strict;
  1         2  
  1         20  
6 1     1   5 use warnings;
  1         1  
  1         35  
7              
8 1     1   7 use Carp qw< croak confess >;
  1         1  
  1         94  
9 1     1   479 use English qw< -no_match_vars >;
  1         3593  
  1         5  
10 1     1   884 use List::SomeUtils qw( all none );
  1         13030  
  1         89  
11 1     1   509 use Readonly;
  1         3840  
  1         53  
12              
13 1     1   650 use Test::Builder qw<>;
  1         66442  
  1         33  
14 1     1   645 use Test::More;
  1         6044  
  1         8  
15              
16 1     1   798 use Perl::Critic::Violation;
  1         5  
  1         44  
17 1         19 use Perl::Critic::TestUtils qw<
18             pcritique_with_violations fcritique_with_violations subtests_in_tree
19 1     1   509 >;
  1         4  
20              
21             #-----------------------------------------------------------------------------
22              
23             our $VERSION = '1.146';
24              
25             #-----------------------------------------------------------------------------
26              
27 1     1   137 use Exporter 'import';
  1         6  
  1         1555  
28              
29             Readonly::Array our @EXPORT_OK => qw< all_policies_ok >;
30             Readonly::Hash our %EXPORT_TAGS => (all => \@EXPORT_OK);
31              
32             #-----------------------------------------------------------------------------
33              
34             Perl::Critic::Violation::set_format( "%m at line %l, column %c. (%r)\n" );
35             Perl::Critic::TestUtils::block_perlcriticrc();
36              
37             #-----------------------------------------------------------------------------
38              
39             my $TEST = Test::Builder->new();
40              
41             #-----------------------------------------------------------------------------
42              
43             sub all_policies_ok {
44 1     1 1 11 my (%args) = @_;
45 1         4 my $wanted_policies = $args{-policies};
46 1   50     8 my $test_dir = $args{'-test-directory'} || 't';
47              
48 1         5 my $subtests_with_extras = subtests_in_tree( $test_dir, 'include extras' );
49              
50 1 50       6 if ($wanted_policies) {
51 0         0 _validate_wanted_policy_names($wanted_policies, $subtests_with_extras);
52 0         0 _filter_unwanted_subtests($wanted_policies, $subtests_with_extras);
53             }
54              
55 1         7 $TEST->plan( tests => _compute_test_count($subtests_with_extras) );
56 1         920 my $policies_to_test = join q{, }, keys %{$subtests_with_extras};
  1         79  
57 1         32 $TEST->note("Running tests for policies: $policies_to_test");
58              
59 1         398 for my $policy ( sort keys %{$subtests_with_extras} ) {
  1         82  
60              
61 139         1875 my ($full_policy_name, $method) = ("Perl::Critic::Policy::$policy", 'violates');
62 139         680 my $can_ok_label = qq{Class '$full_policy_name' has method '$method'};
63 139         3283 $TEST->ok( $full_policy_name->can($method), $can_ok_label );
64              
65 139         54570 for my $subtest ( @{ $subtests_with_extras->{$policy}{subtests} } ) {
  139         854  
66 2642         11386 my $todo = $subtest->{TODO};
67 2642 100       6924 if ($todo) { $TEST->todo_start( $todo ); }
  22         132  
68              
69 2642         11237 my ($error, @violations) = _run_subtest($policy, $subtest);
70 2642         9921 my ($ok, @diag)= _evaluate_test_results($subtest, $error, \@violations);
71 2642         9078 $TEST->ok( $ok, _create_test_name($policy, $subtest) );
72              
73 2642 100       1387550 if (@diag) { $TEST->diag(@diag); }
  22         92  
74 2642 100       26471 if ($todo) { $TEST->todo_end(); }
  22         127  
75             }
76             }
77              
78 1         5510 return;
79             }
80              
81             #-----------------------------------------------------------------------------
82              
83             sub _validate_wanted_policy_names {
84 0     0   0 my ($wanted_policies, $subtests_with_extras) = @_;
85 0 0       0 return 1 if not $wanted_policies;
86 0         0 my @all_testable_policies = keys %{ $subtests_with_extras };
  0         0  
87 0         0 my @wanted_policies = @{ $wanted_policies };
  0         0  
88              
89              
90 0     0   0 my @invalid = grep {my $p = $_; none { $_ =~ $p } @all_testable_policies} @wanted_policies;
  0         0  
  0         0  
  0         0  
91 0 0       0 croak( q{No tests found for policies matching: } . join q{, }, @invalid ) if @invalid;
92 0         0 return 1;
93             }
94              
95             #-----------------------------------------------------------------------------
96              
97             sub _filter_unwanted_subtests {
98 0     0   0 my ($wanted_policies, $subtests_with_extras) = @_;
99 0 0       0 return 1 if not $wanted_policies;
100 0         0 my @all_testable_policies = keys %{ $subtests_with_extras };
  0         0  
101 0         0 my @wanted_policies = @{ $wanted_policies };
  0         0  
102              
103 0         0 for my $p (@all_testable_policies) {
104 0 0   0   0 if (none {$p =~ m/$_/xism} @wanted_policies) {
  0         0  
105 0         0 delete $subtests_with_extras->{$p}; # side-effects!
106             }
107             }
108 0         0 return 1;
109             }
110              
111             #-----------------------------------------------------------------------------
112              
113             sub _run_subtest {
114 2642     2642   5990 my ($policy, $subtest) = @_;
115              
116 2642         4849 my @violations;
117             my $error;
118 2642 100       8105 if ( $subtest->{filename} ) {
119             eval {
120             @violations =
121             fcritique_with_violations(
122             $policy,
123             \$subtest->{code},
124             $subtest->{filename},
125             $subtest->{parms},
126 30         140 );
127 30         124 1;
128 30 50       56 } or do {
129 0   0     0 $error = $EVAL_ERROR || 'An unknown problem occurred.';
130             };
131             }
132             else {
133             eval {
134             @violations =
135             pcritique_with_violations(
136             $policy,
137             \$subtest->{code},
138             $subtest->{parms},
139 2612         12244 );
140 2610         1090753 1;
141 2612 100       3956 } or do {
142 2   50     38 $error = $EVAL_ERROR || 'An unknown problem occurred.';
143             };
144             }
145              
146 2642         11933 return ($error, @violations);
147             }
148              
149             #-----------------------------------------------------------------------------
150              
151             sub _evaluate_test_results {
152 2642     2642   6655 my ($subtest, $error, $violations) = @_;
153              
154 2642 100       11167 if ($subtest->{error}) {
    50          
155 2         16 return _evaluate_error_case($subtest, $error);
156             }
157             elsif ($error) {
158 0         0 confess $error;
159             }
160             else {
161 2640         7543 return _evaluate_violation_case($subtest, $violations);
162             }
163             }
164              
165             #-----------------------------------------------------------------------------
166              
167             sub _evaluate_violation_case {
168 2640     2640   5958 my ($subtest, $violations) = @_;
169 2640         5047 my ($ok, @diagnostics);
170              
171 2640         6107 my @violations = @{$violations};
  2640         6273  
172 2640         6524 my $have = scalar @violations;
173 2640         7151 my $want = _compute_wanted_violation_count($subtest);
174 2640 100       9719 if ( not $ok = $have == $want ) {
175 22         114 my $msg = qq(Expected $want violations, got $have. );
176 22 100       89 if (@violations) { $msg .= q(Found violations follow...); }
  9         27  
177 22         77 push @diagnostics, $msg . "\n";
178 22         73 push @diagnostics, map { qq(Found violation: $_) } @violations;
  16         263  
179             }
180              
181 2640         10444 return ($ok, @diagnostics)
182             }
183              
184             #-----------------------------------------------------------------------------
185              
186             sub _evaluate_error_case {
187 2     2   10 my ($subtest, $error) = @_;
188 2         9 my ($ok, @diagnostics);
189              
190 2 50       14 if ( 'Regexp' eq ref $subtest->{error} ) {
191             $ok = $error =~ $subtest->{error}
192 2 50       15 or push @diagnostics, qq(Error message '$error' doesn't match $subtest->{error}.);
193             }
194             else {
195             $ok = $subtest->{error}
196 0 0       0 or push @diagnostics, q(Didn't get an error message when we expected one.);
197             }
198              
199 2         3305 return ($ok, @diagnostics);
200             }
201              
202             #-----------------------------------------------------------------------------
203              
204             sub _compute_test_count {
205 1     1   5 my ($subtests_with_extras) = @_;
206              
207             # one can_ok() for each policy
208 1         3 my $npolicies = scalar keys %{ $subtests_with_extras };
  1         9  
209              
210 1         3 my $nsubtests = 0;
211 1         3 for my $subtest_with_extras ( values %{$subtests_with_extras} ) {
  1         15  
212             # one [pf]critique() test per subtest
213 139         168 $nsubtests += @{ $subtest_with_extras->{subtests} };
  139         328  
214             }
215              
216 1         13 return $nsubtests + $npolicies;
217             }
218              
219             #-----------------------------------------------------------------------------
220              
221             sub _compute_wanted_violation_count {
222 2640     2640   5695 my ($subtest) = @_;
223              
224             # If any optional modules are NOT available, then there should be no violations.
225 2640 50       6730 return 0 if not _all_optional_modules_are_available($subtest);
226 2640         9710 return $subtest->{failures};
227             }
228              
229             #-----------------------------------------------------------------------------
230              
231             sub _all_optional_modules_are_available {
232 2640     2640   5735 my ($subtest) = @_;
233 2640 50       11865 my $optional_modules = $subtest->{optional_modules} or return 1;
234 0 0   0   0 return all {eval "require $_;" or 0;} split m/,\s*/xms, $optional_modules;
  0         0  
235             }
236              
237             #-----------------------------------------------------------------------------
238              
239             sub _create_test_name {
240 2642     2642   6524 my ($policy, $subtest) = @_;
241 2642         25189 return join ' - ', $policy, "line $subtest->{lineno}", $subtest->{name};
242             }
243              
244             #-----------------------------------------------------------------------------
245             1;
246              
247             __END__
248              
249             #-----------------------------------------------------------------------------
250              
251             =pod
252              
253             =for stopwords subtest subtests RCS
254              
255             =head1 NAME
256              
257             Test::Perl::Critic::Policy - A framework for testing your custom Policies
258              
259             =head1 SYNOPSIS
260              
261             use Test::Perl::Critic::Policy qw< all_policies_ok >;
262              
263             # Assuming .run files are inside 't' directory...
264             all_policies_ok()
265              
266             # Or if your .run files are in a different directory...
267             all_policies_ok( '-test-directory' => 'run' );
268              
269             # And if you just want to run tests for some polices...
270             all_policies_ok( -policies => ['Some::Policy', 'Another::Policy'] );
271              
272             # If you want your test program to accept short Policy names as
273             # command-line parameters...
274             #
275             # You can then test a single policy by running
276             # "perl -Ilib t/policy-test.t My::Policy".
277             my %args = @ARGV ? ( -policies => [ @ARGV ] ) : ();
278             all_policies_ok(%args);
279              
280              
281             =head1 DESCRIPTION
282              
283             This module provides a framework for function-testing your custom
284             L<Perl::Critic::Policy|Perl::Critic::Policy> modules. Policy testing usually
285             involves feeding it a string of Perl code and checking its behavior. In the
286             old days, those strings of Perl code were mixed directly in the test script.
287             That sucked.
288              
289             =head1 IMPORTABLE SUBROUTINES
290              
291             =over
292              
293             =item all_policies_ok('-test-directory' => $path, -policies => \@policy_names)
294              
295             Loads all the F<*.run> files beneath the C<-test-directory> and runs the
296             tests. If C<-test-directory> is not specified, it defaults to F<t/>.
297             C<-policies> is an optional reference to an array of shortened Policy names.
298             If C<-policies> specified, only the tests for Policies that match one of the
299             C<m/$POLICY_NAME/imx> will be run.
300              
301              
302             =back
303              
304              
305             =head1 CREATING THE *.run FILES
306              
307             Testing a policy follows a very simple pattern:
308              
309             * Policy name
310             * Subtest name
311             * Optional parameters
312             * Number of failures expected
313             * Optional exception expected
314             * Optional filename for code
315              
316             Each of the subtests for a policy is collected in a single F<.run>
317             file, with test properties as comments in front of each code block
318             that describes how we expect Perl::Critic to react to the code. For
319             example, say you have a policy called Variables::ProhibitVowels:
320              
321             (In file t/Variables/ProhibitVowels.run)
322              
323             ## name Basics
324             ## failures 1
325             ## cut
326              
327             my $vrbl_nm = 'foo'; # Good, vowel-free name
328             my $wango = 12; # Bad, pronouncable name
329              
330              
331             ## name Sometimes Y
332             ## failures 1
333             ## cut
334              
335             my $yllw = 0; # "y" not a vowel here
336             my $rhythm = 12; # But here it is
337              
338             These are called "subtests", and two are shown above. The beauty of
339             incorporating multiple subtests in a file is that the F<.run> is
340             itself a (mostly) valid Perl file, and not hidden in a HEREDOC, so
341             your editor's color-coding still works, and it is much easier to work
342             with the code and the POD.
343              
344             If you need to pass any configuration parameters for your subtest, do
345             so like this:
346              
347             ## parms { allow_y => '0' }
348              
349             Note that all the values in this hash must be strings because that's
350             what Perl::Critic will hand you from a F<.perlcriticrc>.
351              
352             If it's a TODO subtest (probably because of some weird corner of PPI
353             that we exercised that Adam is getting around to fixing, right?), then
354             make a C<##TODO> entry.
355              
356             ## TODO Should pass when PPI 1.xxx comes out
357              
358             If the code is expected to trigger an exception in the policy,
359             indicate that like so:
360              
361             ## error 1
362              
363             If you want to test the error message, mark it with C</.../> to
364             indicate a C<like()> test:
365              
366             ## error /Can't load Foo::Bar/
367              
368             If the policy you are testing cares about the filename of the code,
369             you can indicate that C<fcritique> should be used like so (see
370             C<fcritique> for more details):
371              
372             ## filename lib/Foo/Bar.pm
373              
374             The value of C<parms> will get C<eval>ed and passed to C<pcritique()>,
375             so be careful.
376              
377             In general, a subtest document runs from the C<## cut> that starts it to
378             either the next C<## name> or the end of the file. In very rare circumstances
379             you may need to end the test document earlier. A second C<## cut> will do
380             this. The only known need for this is in
381             F<t/Miscellanea/RequireRcsKeywords.run>, where it is used to prevent the RCS
382             keywords in the file footer from producing false positives or negatives in the
383             last test.
384              
385             Note that nowhere within the F<.run> file itself do you specify the
386             policy that you're testing. That's implicit within the filename.
387              
388              
389             =head1 BUGS AND CAVEATS AND TODO ITEMS
390              
391             Add policy_ok() method for running subtests in just a single TODO file.
392              
393             Can users mark this entire test as TODO or SKIP, using the normal mechanisms?
394              
395             Allow us to specify the nature of the failures, and which one. If there are
396             15 lines of code, and six of them fail, how do we know they're the right six?
397              
398             Consolidate code from L<Perl::Critic::TestUtils|Perl::Critic::TestUtils> and possibly deprecate some
399             functions there.
400              
401             Write unit tests for this module.
402              
403             Test that we have a t/*/*.run for each lib/*/*.pm
404              
405             =head1 AUTHOR
406              
407             Andy Lester, Jeffrey Ryan Thalhammer <thaljef@cpan.org>
408              
409             =head1 COPYRIGHT
410              
411             Copyright (c) 2009-2021 Andy Lester
412              
413             This program is free software; you can redistribute it and/or modify
414             it under the same terms as Perl itself. The full text of this license
415             can be found in the LICENSE file included with this module.
416              
417             =cut
418              
419             ##############################################################################
420             # Local Variables:
421             # mode: cperl
422             # cperl-indent-level: 4
423             # fill-column: 78
424             # indent-tabs-mode: nil
425             # c-indentation-style: bsd
426             # End:
427             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :