File Coverage

blib/lib/Test/EOF.pm
Criterion Covered Total %
statement 73 99 73.7
branch 26 54 48.1
condition 4 11 36.3
subroutine 15 16 93.7
pod 1 2 50.0
total 119 182 65.3


line stmt bran cond sub pod time code
1 1     1   70902 use 5.10.1;
  1         13  
2 1     1   5 use strict;
  1         2  
  1         20  
3 1     1   4 use warnings;
  1         2  
  1         65  
4              
5             package Test::EOF;
6              
7             our $VERSION = '0.0804';
8             # ABSTRACT: Check correct end of files in a project.
9             our $AUTHORITY = 'cpan:CSSON'; # AUTHORITY
10              
11 1     1   7 use Cwd qw/cwd/;
  1         3  
  1         55  
12 1     1   6 use File::Find;
  1         2  
  1         64  
13 1     1   526 use File::ReadBackwards;
  1         2424  
  1         29  
14 1     1   7 use Test::Builder;
  1         2  
  1         67  
15              
16             my $perlstart = qr/^#!.*perl/;
17             my $test = Test::Builder->new;
18              
19             sub import {
20 1     1   7 my $self = shift;
21 1         2 my $caller = caller;
22             {
23 1     1   6 no strict 'refs';
  1         2  
  1         1183  
  1         2  
24 1         2 *{ $caller.'::all_perl_files_ok'} = \&all_perl_files_ok;
  1         9  
25             }
26 1         3 $test->exported_to($caller);
27 1         10 $test->plan(@_);
28             }
29              
30             sub all_perl_files_ok {
31 2 100   2 1 114 my $options = ref $_[0] eq 'HASH' ? shift : ref $_[-1] eq 'HASH' ? pop : {};
    50          
32 2         21 my @files = _all_perl_files(@_);
33              
34 2         10 $test->expected_tests;
35              
36             # no need to check then...
37 2 50 66     322 if(exists $options->{'minimum_newlines'} && $options->{'minimum_newlines'} <= 0) {
38 0         0 return 1;
39             }
40              
41 2         6 foreach my $file (@files) {
42 2         4 _check_perl_file($file, $options);
43             }
44             }
45              
46             sub _check_perl_file {
47 2     2   5 my $file = shift;
48 2         3 my $options = shift;
49              
50 2   100     9 $options->{'minimum_newlines'} ||= 1;
51 2 50 0     6 if(!exists $options->{'maximum_newlines'}) {
    0          
52 2         5 $options->{'maximum_newlines'} = $options->{'minimum_newlines'} + 3;
53             }
54             elsif(exists $options->{'maximum_newlines'} && $options->{'maximum_newlines'} < $options->{'minimum_newlines'}) {
55 0         0 $options->{'maximum_newlines'} = $options->{'minimum_newlines'};
56             }
57              
58 2 50       5 if($options->{'strict'}) {
59 0         0 $options->{'minimum_newlines'} = 1;
60 0         0 $options->{'maximum_newlines'} = 1;
61             }
62              
63 2         4 $file = _module_to_path($file);
64              
65 2 50       10 my $reader = File::ReadBackwards->new($file) or return;
66              
67 2         176 my $linecount = 0;
68              
69             LINE:
70 2         7 while(my $line = $reader->readline) {
71 4 50       315 ++$linecount if $line =~ m{\v$};
72 4 100       13 next LINE if $line =~ m{^\v$};
73 2         4 last LINE;
74             }
75              
76 2 50       10 if($linecount < $options->{'minimum_newlines'}) {
    50          
77 0         0 my $wanted = make_wanted($options);
78 0         0 $test->ok(0, "Not enough line breaks (had $linecount, wanted $wanted) at the end of $file");
79 0         0 return 0;
80             }
81             elsif($linecount > $options->{'maximum_newlines'}) {
82 0         0 my $wanted = make_wanted($options);
83 0         0 $test->ok(0, "Too many line breaks (had $linecount, wanted $wanted) at the end of $file ");
84 0         0 return 0;
85             }
86 2         10 $test->ok(1, "Just the right number of line breaks at the end of $file");
87 2         742 return 1;
88              
89             }
90              
91             sub make_wanted {
92 0     0 0 0 my $options = shift;
93 0 0       0 return $options->{'minimum_newlines'} if $options->{'minimum_newlines'} == $options->{'maximum_newlines'};
94 0         0 return sprintf "%d to %d" => $options->{'minimum_newlines'}, $options->{'maximum_newlines'};
95             }
96              
97             sub _all_perl_files {
98 2 50   2   9 my @base_dirs = @_ ? @_ : cwd();
99 2         3 my @found;
100              
101             my $wants = sub {
102 4 50   4   24 return if $File::Find::dir =~ m{ [\\/]? (?:CVS|\.svn) [\\/] }x;
103 4 50       10 return if $File::Find::dir =~ m{ [\\/]? blib [\\/] (?: libdoc | man\d) $ }x;
104 4 50       10 return if $File::Find::dir =~ m{ [\\/]? inc }x;
105 4 50       11 return if $File::Find::name =~ m{ Build $ }xi;
106 4 100       273 return unless -f -r $File::Find::name;
107 2         43 push @found => File::Spec->no_upwards($File::Find::name);
108 2         8 };
109 2         8 my $find_arg = {
110             wanted => $wants,
111             no_chdir => 1,
112             };
113              
114 2         197 find($find_arg, @base_dirs);
115              
116 2 50       6 my @perls = grep { _is_perl($_) || _is_perl($_) } @found;
  2         5  
117              
118 2         13 return @perls;
119             }
120              
121             sub _is_perl {
122 2     2   5 my $file = shift;
123              
124             # module
125 2 100       14 return 1 if $file =~ m{\.pm$}i;
126 1 50       6 return 1 if $file =~ m{::};
127              
128             # script
129 1 50       4 return 1 if $file =~ m{\.pl}i;
130 1 50       8 return 1 if $file =~ m{\.t$};
131              
132 0 0       0 open my $fh, '<', $file or return;
133 0         0 my $first = <$fh>;
134 0 0 0     0 if(defined $first && $first =~ $perlstart) {
135 0         0 close $fh;
136 0         0 return 1;
137             }
138              
139             # nope
140 0         0 return;
141             }
142              
143             sub _module_to_path {
144 2     2   4 my $file = shift;
145 2 50       7 return $file unless $file =~ m{::};
146 0           my @parts = split /::/ => $file;
147 0           my $module = File::Spec->catfile(@parts) . '.pm';
148              
149             CANDIDATE:
150 0           foreach my $dir (@INC) {
151 0           my $candidate = File::Spec->catfile($dir, $module);
152 0 0         next CANDIDATE if !-e -f -r $candidate;
153 0           return $candidate;
154             }
155 0           return $file;
156             }
157              
158             1;
159              
160             __END__