File Coverage

blib/lib/Test/PerlTidy.pm
Criterion Covered Total %
statement 103 114 90.3
branch 21 36 58.3
condition 8 9 88.8
subroutine 19 19 100.0
pod 4 4 100.0
total 155 182 85.1


line stmt bran cond sub pod time code
1             $Test::PerlTidy::VERSION = '20220902';
2             use 5.014;
3 5     5   179100 use strict;
  5         49  
4 5     5   23 use warnings;
  5         8  
  5         157  
5 5     5   21 use English qw( -no_match_vars );
  5         10  
  5         117  
6 5     5   2164  
  5         16028  
  5         24  
7             use parent 'Exporter';
8 5     5   3456  
  5         1315  
  5         27  
9             use vars qw( @EXPORT ); ## no critic (Modules::ProhibitAutomaticExportation)
10 5     5   238 @EXPORT = qw( run_tests );
  5         9  
  5         189  
11              
12             use Carp qw( croak );
13 5     5   23 use Path::Tiny 0.100 qw( path );
  5         7  
  5         207  
14 5     5   3701 use File::Spec ();
  5         61272  
  5         272  
15 5     5   34 use IO::File ();
  5         9  
  5         58  
16 5     5   2192 use Perl::Tidy 20220613;
  5         37219  
  5         122  
17 5     5   4945 use Test::Builder ();
  5         1471779  
  5         505  
18 5     5   1238 use Text::Diff qw( diff );
  5         102228  
  5         118  
19 5     5   2324  
  5         35782  
  5         4628  
20             my $test = Test::Builder->new;
21              
22             our $MUTE = 0;
23              
24             my %args = @_;
25             my @opts;
26 2     2 1 219 if ( my $perltidy_options = delete( $args{perltidy_options} ) ) {
27 2         4 push @opts, +{ perltidy_options => $perltidy_options, };
28 2 50       8 }
29 0         0  
30             # Skip all tests if instructed to.
31             $test->skip_all('All tests skipped.') if $args{skip_all};
32              
33 2 50       6 $MUTE = $args{mute} if exists $args{mute};
34              
35 2 50       11 # Get files to work with and set the plan.
36             my @files = list_files(%args);
37             $test->plan( tests => scalar @files );
38 2         15  
39 2         14 # Check each file in turn.
40             foreach my $file (@files) {
41             $test->ok( is_file_tidy( $file, $args{perltidyrc}, @opts, ),
42 2         1422 "'$file'" );
43 15         6120 }
44              
45             return;
46             }
47 2         1199  
48             my ( $file_to_tidy, $perltidyrc, $named_args ) = @_;
49              
50             $named_args //= { perltidy_options => {}, };
51 18     18 1 168 my $code_to_tidy = load_file($file_to_tidy);
52              
53 18   100     151 my $tidied_code = q{};
54 18         77 my $logfile = q{};
55             my $errorfile = q{};
56 18         60  
57 18         46 my $stderr_fh = IO::File->new_tmpfile or croak "IO::File->new_tmpfile: $!";
58 18         45 $stderr_fh->autoflush(1);
59              
60 18 50       3242 Perl::Tidy::perltidy(
61 18         177 source => \$code_to_tidy,
62             destination => \$tidied_code,
63             stderr => $stderr_fh,
64             logfile => \$logfile,
65             errorfile => \$errorfile,
66             perltidyrc => $perltidyrc,
67             %{ $named_args->{perltidy_options} },
68             );
69              
70 18         1071 # If there were perltidy errors report them and return.
  18         142  
71             $stderr_fh->seek( 0, 0 );
72             binmode $stderr_fh, ':encoding(UTF-8)' or croak "error setting binmode $!";
73             my $stderr = do {
74 18         6112785 local $INPUT_RECORD_SEPARATOR = undef;
75 18 50   3   1438 <$stderr_fh>;
  3         44  
  3         10  
  3         32  
76 18         5566 };
77 18         109 if ($stderr) {
78 18         4132 unless ($MUTE) {
79             $test->diag("perltidy reported the following errors:\n");
80 18 50       135 $test->diag($stderr);
81 0 0       0 }
82 0         0 return 0;
83 0         0 }
84              
85 0         0 # Compare the pre and post tidy code and return result.
86             # Do not worry about trailing newlines.
87             #
88             $code_to_tidy =~ s/[\r\n]+$//;
89             $tidied_code =~ s/[\r\n]+$//;
90             if ( $code_to_tidy eq $tidied_code ) {
91 18         1028 return 1;
92 18         898 }
93 18 100       106 else {
94 17         305 unless ($MUTE) {
95             $test->diag("The file '$file_to_tidy' is not tidy\n");
96             $test->diag(
97 1 50       5 diff( \$code_to_tidy, \$tidied_code, { STYLE => 'Table' } ) );
98 0         0 }
99 0         0  
100             return 0;
101             }
102             }
103 1         14  
104             my (@args) = @_;
105              
106             my %args;
107             my $path;
108 4     4 1 182  
109             # Expect either a hashref of args, or a single "path" argument:
110 4         9 #
111             # The only reason for allowing a single path argument is for
112             # backward compatibility with Test::PerlTidy::list_files, on the
113             # off chance that someone was calling it directly...
114             #
115             if ( @args > 1 ) {
116             %args = @args;
117             $path = $args{path};
118             }
119 4 50       15 else {
120 4         15 %args = ();
121 4         10 $path = $args[0];
122             }
123              
124 0         0 $path ||= q{.};
125 0         0  
126             $test->BAIL_OUT(qq{The directory "$path" does not exist}) unless -d $path;
127              
128 4   100     15 my $excludes = $args{exclude}
129             || [ $OSNAME eq 'MSWin32' ? qr{^blib[/\\]} : 'blib/' ]
130 4 50       61 ; # exclude blib by default
131              
132             $test->BAIL_OUT('exclude should be an array')
133 4   50     64 unless ref $excludes eq 'ARRAY';
134              
135             my @files;
136 4 50       18 path($path)
137             ->visit( sub { push @files, $_ if $_->is_file && /[.](?:pl|pm|PL|t)\z/; },
138             { recurse => 1 } );
139 4         9  
140             my %keep = map { File::Spec->canonpath($_) => 1 } @files;
141 289 100 100 289   32249 my @excluded = ();
142 4         16  
143             foreach my $file ( keys %keep ) {
144 4         579  
  72         385  
145 4         77 foreach my $exclude ( @{$excludes} ) {
146              
147 4         23 my $exclude_me =
148             ref $exclude ? ( $file =~ $exclude ) : ( $file =~ /^$exclude/ );
149 72         79  
  72         102  
150             if ($exclude_me) {
151 179 100       705 delete $keep{$file};
152             push @excluded, $file if $args{debug};
153             last; # no need to check more exclusions...
154 179 100       362 }
155 38         51 }
156 38 50       87 }
157 38         68  
158             # Sort the output so that it is repeatable
159             @files = sort keys %keep;
160              
161             if ( $args{debug} ) {
162             $test->diag( 'Files excluded: ', join( "\n\t", sort @excluded ), "\n" );
163 4         49 $test->diag( 'Files remaining ', join( "\n\t", @files ), "\n" );
164             }
165 4 50       16  
166 0         0 return @files;
167 0         0 }
168              
169             my $filename = shift;
170 4         26  
171             # If the file is not regular then return undef.
172             return unless -f $filename;
173              
174 18     18 1 50 # Slurp the file.
175             my $content = path($filename)->slurp_utf8;
176             return $content;
177 18 50       397 }
178              
179             1;
180 18         140  
181 18         8225  
182             =pod
183              
184             =encoding UTF-8
185              
186             =head1 NAME
187              
188             Test::PerlTidy - check that all your files are tidy.
189              
190             =head1 VERSION
191              
192             version 20220902
193              
194             =head1 SYNOPSIS
195              
196             # In a file like 't/perltidy.t':
197              
198             use Test::PerlTidy qw( run_tests );
199              
200             run_tests();
201              
202             =head1 DESCRIPTION
203              
204             This rather unflattering comment was made in a piece by Ken Arnold:
205              
206             "Perl is a vast swamp of lexical and syntactic swill and nobody
207             knows how to format even their own code well, but it's the only
208             major language I can think of (with the possible exception of the
209             recent, yet very Java-like C#) that doesn't have at least one
210             style that's good enough."
211             http://www.artima.com/weblogs/viewpost.jsp?thread=74230
212              
213             Hmmm... He is sort of right in a way. Then again the piece he wrote
214             was related to Python which is somewhat strict about formatting
215             itself.
216              
217             Fear not though - now you too can have your very own formatting
218             gestapo in the form of Test::PerlTidy! Simply add a test file as
219             suggested above and any file ending in .pl, .pm, .t or .PL will cause
220             a test fail unless it is exactly as perltidy would like it to be.
221              
222             =for stopwords Hmmm perltidy cvs perltidyrc subdirectories listref canonified pre von der Leszczynski perl
223              
224             =head1 REASONS TO DO THIS
225              
226             If the style is mandated in tests then it will be adhered to.
227              
228             If perltidy decides what is a good style then there should be no
229             quibbling.
230              
231             If the style never changes then cvs diffs stop catching changes that
232             are not really there.
233              
234             Readability might even improve.
235              
236             =head1 HINTS
237              
238             If you want to change the default style then muck around with
239             '.perltidyrc';
240              
241             To quickly make a file work then try 'perltidy -b the_messy_file.pl'.
242              
243             =head1 HOW IT WORKS
244              
245             Runs B<perltidy> on files and reports errors if any of the files
246             differ after having been tidied. Does not permanently modify the
247             files being tested.
248              
249             By default, B<perltidy> will be run on files under the current
250             directory and its subdirectories with extensions matching:
251             C<.pm .pl .PL .t>
252              
253             =head1 METHODS
254              
255             =head2 run_tests ( [ I<%args> ] )
256              
257             This is the main entry point for running tests.
258              
259             A number of options can be specified when running the tests, e.g.:
260              
261             run_tests(
262             path => $start_dir,
263             perltidyrc => $path_to_config_file,
264             exclude => [ qr{\.t$}, 'inc/'],
265             );
266              
267             =over 4
268              
269             =item debug
270              
271             Set C<debug> to a true value to enable additional diagnostic
272             output, in particular info about any processing done as a result of
273             specifying the C<exclude> option. Default is false.
274              
275             =item exclude
276              
277             C<run_tests()> will look for files to test under the current
278             directory and its subdirectories. By default, it will exclude files
279             in the "C<./blib/>" directory. Set C<exclude> to a listref of
280             exclusion criteria if you need to specify additional rules by which
281             files will be excluded.
282              
283             If an item in the C<exclude> list is a string, e.g. "C<./blib/>",
284             it will be assumed to be a path prefix. Files will be excluded if
285             that string matches their path at the beginning.
286              
287             If an item in the C<exclude> list is a regex object, e.g.
288             "C<qr{\.t$}>", files will be excluded if that regex matches their
289             path.
290              
291             Note that the paths of files to be tested are canonified using
292             L<File::Spec|File::Spec>C<< ->canonpath >> before any matching is
293             attempted, which can impact how the exclusion rules apply. If your
294             exclusion rules do not seem to be working, turn on the C<debug>
295             option to see the paths of the files that are being kept/excluded.
296              
297             =item path
298              
299             Set C<path> to the path to the top-level directory which contains
300             the files to be tested. Defaults to the current directory (i.e.
301             "C<.>").
302              
303             =item perltidyrc
304              
305             By default, B<perltidy> will attempt to read its options from the
306             F<.perltidyrc> file on your system. Set C<perltidyrc> to the path
307             to a custom file if you would like to control the B<perltidy>
308             options used during testing.
309              
310             =item mute
311              
312             By default, C<run_tests()> will output diagnostics about any errors
313             reported by B<perltidy>, as well as any actual differences found
314             between the pre-tidied and post-tidied files. Set C<mute> to a
315             true value to turn off that diagnostic output.
316              
317             =item skip_all
318              
319             Set C<skip_all> to a true value to skip all tests. Default is false.
320              
321             =item perltidy_options
322              
323             Pass these to Perl::Tidy::perltidy().
324             (Added in version 20200411 .)
325              
326             =back
327              
328             =head2 list_files ( [ I<start_path> | I<%args> ] )
329              
330             Generate the list of files to be tested. Generally not called directly.
331              
332             =head2 load_file ( I<path_to_file> )
333              
334             Load the file to be tested from disk and return the contents.
335             Generally not called directly.
336              
337             =head2 is_file_tidy ( I<path_to_file> [ , I<path_to_perltidyrc> ] [, I<$named_args>] )
338              
339             Test if a file is tidy or not. Generally not called directly.
340              
341             $named_args can be a hash ref which may have a key called 'perltidy_options'
342             that refers to a hash ref of options that will be passed to Perl::Tidy::perltidy().
343             ($named_args was added in version 20200411).
344              
345             =head1 SEE ALSO
346              
347             L<Perl::Tidy>
348              
349             =head1 ORIGINAL AUTHOR
350              
351             Edmund von der Burg, C<< <evdb at ecclestoad.co.uk> >>
352              
353             =head1 CONTRIBUTORS
354              
355             Duncan J. Ferguson, C<< <duncan_j_ferguson at yahoo.co.uk> >>
356              
357             Stephen, C<< <stephen at enterity.com> >>
358              
359             Larry Leszczynski, C<< <larryl at cpan.org> >>
360              
361             Shlomi Fish, L<https://www.shlomifish.org/>
362              
363             =head1 SUGGESTIONS
364              
365             Please let me know if you have any comments or suggestions.
366              
367             L<http://ecclestoad.co.uk/>
368              
369             =head1 COPYRIGHT
370              
371             Copyright 2007 Edmund von der Burg, all rights reserved.
372              
373             =head1 LICENSE
374              
375             This library is free software . You can redistribute it and/or modify
376             it under the same terms as perl itself.
377              
378             =for :stopwords cpan testmatrix url bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan
379              
380             =head1 SUPPORT
381              
382             =head2 Websites
383              
384             The following websites have more information about this module, and may be of help to you. As always,
385             in addition to those websites please use your favorite search engine to discover more resources.
386              
387             =over 4
388              
389             =item *
390              
391             MetaCPAN
392              
393             A modern, open-source CPAN search engine, useful to view POD in HTML format.
394              
395             L<https://metacpan.org/release/Test-PerlTidy>
396              
397             =item *
398              
399             RT: CPAN's Bug Tracker
400              
401             The RT ( Request Tracker ) website is the default bug/issue tracking system for CPAN.
402              
403             L<https://rt.cpan.org/Public/Dist/Display.html?Name=Test-PerlTidy>
404              
405             =item *
406              
407             CPANTS
408              
409             The CPANTS is a website that analyzes the Kwalitee ( code metrics ) of a distribution.
410              
411             L<http://cpants.cpanauthors.org/dist/Test-PerlTidy>
412              
413             =item *
414              
415             CPAN Testers
416              
417             The CPAN Testers is a network of smoke testers who run automated tests on uploaded CPAN distributions.
418              
419             L<http://www.cpantesters.org/distro/T/Test-PerlTidy>
420              
421             =item *
422              
423             CPAN Testers Matrix
424              
425             The CPAN Testers Matrix is a website that provides a visual overview of the test results for a distribution on various Perls/platforms.
426              
427             L<http://matrix.cpantesters.org/?dist=Test-PerlTidy>
428              
429             =item *
430              
431             CPAN Testers Dependencies
432              
433             The CPAN Testers Dependencies is a website that shows a chart of the test results of all dependencies for a distribution.
434              
435             L<http://deps.cpantesters.org/?module=Test::PerlTidy>
436              
437             =back
438              
439             =head2 Bugs / Feature Requests
440              
441             Please report any bugs or feature requests by email to C<bug-test-perltidy at rt.cpan.org>, or through
442             the web interface at L<https://rt.cpan.org/Public/Bug/Report.html?Queue=Test-PerlTidy>. You will be automatically notified of any
443             progress on the request by the system.
444              
445             =head2 Source Code
446              
447             The code is open to the world, and available for you to hack on. Please feel free to browse it and play
448             with it, or whatever. If you want to contribute patches, please send me a diff or prod me to pull
449             from your repository :)
450              
451             L<https://github.com/shlomif/test-perltidy>
452              
453             git clone https://github.com/shlomif/Test-PerlTidy
454              
455             =head1 AUTHOR
456              
457             Shlomi Fish <shlomif@cpan.org>
458              
459             =head1 BUGS
460              
461             Please report any bugs or feature requests on the bugtracker website
462             L<https://github.com/shlomif/test-perltidy/issues>
463              
464             When submitting a bug or request, please include a test-file or a
465             patch to an existing test-file that illustrates the bug or desired
466             feature.
467              
468             =head1 COPYRIGHT AND LICENSE
469              
470             This software is copyright (c) 2022 by Edmund von der Burg.
471              
472             This is free software; you can redistribute it and/or modify it under
473             the same terms as the Perl 5 programming language system itself.
474              
475             =cut