File Coverage

blib/lib/Test/EOL.pm
Criterion Covered Total %
statement 79 120 65.8
branch 26 60 43.3
condition 13 34 38.2
subroutine 16 21 76.1
pod 2 2 100.0
total 136 237 57.3


line stmt bran cond sub pod time code
1             package Test::EOL; # git description: v1.6-18-g0f23233
2             # ABSTRACT: Check the correct line endings in your project
3              
4 2     2   923 use strict;
  2         5  
  2         57  
5 2     2   10 use warnings;
  2         5  
  2         77  
6              
7             our $VERSION = '2.00';
8              
9 2     2   1019 use Test::Builder;
  2         15833  
  2         60  
10 2     2   14 use File::Spec;
  2         4  
  2         318  
11 2     2   9 use File::Find;
  2         4  
  2         146  
12 2     2   21 use Cwd qw/ cwd /;
  2         5  
  2         465  
13              
14             our $PERL = $^X || 'perl';
15             our $UNTAINT_PATTERN = qr|^([-+@\w./:\\]+)$|;
16             our $PERL_PATTERN = qr/^#!.*perl/;
17              
18             my %file_find_arg = ($] <= 5.006) ? () : (
19             untaint => 1,
20             untaint_pattern => $UNTAINT_PATTERN,
21             untaint_skip => 1,
22             );
23              
24             my $Test = Test::Builder->new;
25              
26             my $no_plan;
27              
28             sub import {
29 2     2   14 my $self = shift;
30 2         4 my $caller = caller;
31             {
32 2     2   12 no strict 'refs';
  2         4  
  2         2167  
  2         4  
33 2         4 *{$caller.'::eol_unix_ok'} = \&eol_unix_ok;
  2         10  
34 2         4 *{$caller.'::all_perl_files_ok'} = \&all_perl_files_ok;
  2         7  
35             }
36 2         9 $Test->exported_to($caller);
37              
38 2 50 33     24 if ($_[0] && $_[0] eq 'no_plan') {
39 0         0 shift;
40 0         0 $no_plan = 1;
41             }
42 2         8 $Test->plan(@_);
43             }
44              
45             sub _all_perl_files {
46 2     2   12 my @all_files = _all_files(@_);
47 2 50 33     6 return grep { _is_perl_module($_) || _is_perl_script($_) || _is_pod_file($_) } @all_files;
  2         9  
48             }
49              
50             sub _all_files {
51 2 50   2   18 my @base_dirs = @_ ? @_ : cwd();
52 2 100       14 my $options = pop(@base_dirs) if ref $base_dirs[-1] eq 'HASH';
53 2         5 my @found;
54             my $want_sub = sub {
55 6 50   6   56 return if ($File::Find::dir =~ m![\\/]?CVS[\\/]|[\\/]?\.svn[\\/]!); # Filter out cvs or subversion dirs/
56 6 50       18 return if ($File::Find::dir =~ m![\\/]?blib[\\/]libdoc$!); # Filter out pod doc in dist
57 6 50       17 return if ($File::Find::dir =~ m![\\/]?blib[\\/]man\d$!); # Filter out pod doc in dist
58 6 50       18 return if ($File::Find::dir =~ m![\\/]?inc!); # Filter out Module::Install stuff
59 6 50       21 return if ($File::Find::name =~ m!Build$!i); # Filter out autogenerated Build script
60 6 100 66     428 return unless (-f $File::Find::name && -r _);
61 2         76 push @found, File::Spec->no_upwards( $File::Find::name );
62 2         17 };
63 2         21 my $find_arg = {
64             %file_find_arg,
65             wanted => $want_sub,
66             no_chdir => 1,
67             };
68 2         307 find( $find_arg, @base_dirs);
69 2         19 return @found;
70             }
71              
72             # Formats various human invisible symbols
73             # to similar visible ones.
74             # Perhaps ^M or something like that
75             # would be more appropriate?
76              
77             sub _show_whitespace {
78 0     0   0 my $string = shift;
79 0         0 $string =~ s/\r/[\\r]/g;
80 0         0 $string =~ s/\t/[\\t]/g;
81 0         0 $string =~ s/ /[\\s]/g;
82 0         0 return $string;
83             }
84              
85             # Format a line record for diagnostics.
86              
87             sub _debug_line {
88 0     0   0 my ( $options, $line ) = @_;
89 0         0 $line->[2] =~ s/\n\z//g;
90             return "line $line->[1]: $line->[0]" . (
91 0 0       0 $options->{show_lines} ? qq{: } . _show_whitespace( $line->[2] ) : q{}
92             );
93             }
94              
95             sub eol_unix_ok {
96 7     7 1 1900 my $file = shift;
97 7         13 my $test_txt;
98 7 100       25 $test_txt = shift if !ref $_[0];
99 7   66     52 $test_txt ||= "No incorrect line endings in '$file'";
100 7 100       21 my $options = shift if ref $_[0] eq 'HASH';
101 7   100     29 $options ||= {
102             trailing_whitespace => 0,
103             all_reasons => 0,
104             };
105 7         18 $file = _module_to_path($file);
106              
107 7 50       197 open my $fh, $file or do { $Test->ok(0, $test_txt); $Test->diag("Could not open $file: $!"); return; };
  0         0  
  0         0  
  0         0  
108             # Windows-- , default is :crlf, which hides \r\n -_-
109 7         55 binmode( $fh, ':raw' );
110 7         15 my $line = 0;
111 7         13 my @fails;
112 7         88 while (<$fh>) {
113 941         1243 $line++;
114 941 50 66     3258 if ( !$options->{trailing_whitespace} && /(\r+)$/ ) {
115 0         0 my $match = $1;
116 0         0 push @fails, [ _show_whitespace( $match ) , $line , $_ ];
117             }
118 941 50 66     2119 if ( $options->{trailing_whitespace} && /([ \t]*\r+|[ \t]+)$/ ) {
119 0         0 my $match = $1;
120 0         0 push @fails, [ _show_whitespace($match), $line , $_ ];
121             }
122             # Minor short-circuit for people who don't need the whole file scanned
123             # once there's an err.
124 941 50 33     2874 last if( @fails > 0 && !$options->{all_reasons} );
125             }
126 7 50       28 if( @fails ){
127 0         0 $Test->ok( 0, $test_txt . " on " . _debug_line({ show_lines => 0 } , $fails[0] ) );
128 0 0 0     0 if ( $options->{all_reasons} || 1 ){
129 0         0 $Test->diag( " Problem Lines: ");
130 0         0 for ( @fails ){
131 0         0 $Test->diag(_debug_line({ show_lines => 1 } , $_ ) );
132             }
133             }
134 0         0 return 0;
135             }
136 7         43 $Test->ok(1, $test_txt);
137 7         2648 return 1;
138             }
139             sub all_perl_files_ok {
140 2 50   2 1 2121 my $options = shift if ref $_[0] eq 'HASH';
141 2         39 my @files = _all_perl_files( @_ );
142 2         11 _make_plan();
143 2         26 foreach my $file ( @files ) {
144 2         9 eol_unix_ok($file, $options);
145             }
146             }
147              
148             sub _is_perl_module {
149 2 50   2   45 $_[0] =~ /\.pm$/i || $_[0] =~ /::/;
150             }
151              
152             sub _is_pod_file {
153 0     0   0 $_[0] =~ /\.pod$/i;
154             }
155              
156             sub _is_perl_script {
157 0     0   0 my $file = shift;
158 0 0       0 return 1 if $file =~ /\.pl$/i;
159 0 0       0 return 1 if $file =~ /\.t$/;
160 0 0       0 open (my $fh, $file) or return;
161 0         0 my $first = <$fh>;
162 0 0 0     0 return 1 if defined $first && ($first =~ $PERL_PATTERN);
163 0         0 return;
164             }
165              
166             sub _module_to_path {
167 7     7   15 my $file = shift;
168 7 50       29 return $file unless ($file =~ /::/);
169 0         0 my @parts = split /::/, $file;
170 0         0 my $module = File::Spec->catfile(@parts) . '.pm';
171 0         0 foreach my $dir (@INC) {
172 0         0 my $candidate = File::Spec->catfile($dir, $module);
173 0 0 0     0 next unless (-e $candidate && -f _ && -r _);
      0        
174 0         0 return $candidate;
175             }
176 0         0 return $file;
177             }
178              
179             sub _make_plan {
180 2 50   2   6 return if $no_plan;
181 2 50       17 unless ($Test->has_plan) {
182 2         44 $Test->plan( 'no_plan' );
183             }
184 2         62 $Test->expected_tests;
185             }
186              
187             sub _untaint {
188 0     0     my @untainted = map { ($_ =~ $UNTAINT_PATTERN) } @_;
  0            
189 0 0         return wantarray ? @untainted : $untainted[0];
190             }
191              
192             1;
193              
194             __END__