File Coverage

blib/lib/Test/EOL.pm
Criterion Covered Total %
statement 80 121 66.1
branch 31 60 51.6
condition 22 43 51.1
subroutine 16 21 76.1
pod 2 2 100.0
total 151 247 61.1


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