File Coverage

blib/lib/Test/Tabs.pm
Criterion Covered Total %
statement 95 123 77.2
branch 36 64 56.2
condition 5 18 27.7
subroutine 20 22 90.9
pod 2 2 100.0
total 158 229 69.0


line stmt bran cond sub pod time code
1             package Test::Tabs;
2              
3 2     2   21390 use 5.008;
  2         8  
  2         81  
4 2     2   13 use strict;
  2         4  
  2         66  
5 2     2   11 use warnings;
  2         10  
  2         102  
6              
7             BEGIN {
8 2     2   3 $Test::Tabs::AUTHORITY = 'cpan:TOBYINK';
9 2         43 $Test::Tabs::VERSION = '0.005';
10             }
11              
12 2     2   1077 use Test::Builder;
  2         11067  
  2         49  
13 2     2   12 use File::Spec;
  2         2  
  2         44  
14 2     2   1503 use FindBin qw($Bin);
  2         2343  
  2         269  
15 2     2   14 use File::Find;
  2         2  
  2         122  
16              
17 2     2   10 use vars qw( $PERL $UNTAINT_PATTERN $PERL_PATTERN );
  2         4  
  2         2405  
18              
19             $PERL = $^X || 'perl';
20             $UNTAINT_PATTERN = qr|^([-+@\w./:\\]+)$|;
21             $PERL_PATTERN = qr/^#!.*perl/;
22              
23             my %file_find_arg = ($] <= 5.006) ? () : (
24             untaint => 1,
25             untaint_pattern => $UNTAINT_PATTERN,
26             untaint_skip => 1,
27             );
28              
29             my $Test = Test::Builder->new;
30             my $updir = File::Spec->updir();
31              
32             sub import
33             {
34 2     2   17 my $self = shift;
35 2         5 my $caller = caller;
36             {
37 2     2   15 no strict 'refs';
  2         14  
  2         3088  
  2         5  
38 2         13 *{$caller.'::tabs_ok'} = \&tabs_ok;
  2         13  
39 2         5 *{$caller.'::all_perl_files_ok'} = \&all_perl_files_ok;
  2         9  
40             }
41 2         11 $Test->exported_to($caller);
42 2         20 $Test->plan(@_);
43             }
44              
45             sub _all_perl_files
46             {
47 1     1   5 my @all_files = _all_files(@_);
48 1 100       2 return grep { _is_perl_module($_) || _is_perl_script($_) } @all_files;
  3         8  
49             }
50              
51             sub _all_files
52             {
53 1 50   1   6 my @base_dirs = @_ ? @_ : File::Spec->catdir($Bin, $updir);
54 1         2 my @found;
55             my $want_sub = sub
56             {
57 6 50   6   20 return if ($File::Find::dir =~ m![\\/]?CVS[\\/]|[\\/]?\.svn[\\/]!); # Filter out cvs or subversion dirs/
58 6 50       18 return if ($File::Find::dir =~ m![\\/]?blib[\\/]libdoc$!); # Filter out pod doc in dist
59 6 50       14 return if ($File::Find::dir =~ m![\\/]?inc!); # Remove Module::Install
60 6 50       9 return if ($File::Find::dir =~ m![\\/]?blib[\\/]man\d$!); # Filter out pod doc in dist
61 6 50       17 return if ($File::Find::name =~ m!Build$!i); # Filter out autogenerated Build script
62 6 100 66     336 return unless (-f $File::Find::name && -r _);
63 3         76 push @found, File::Spec->no_upwards( $File::Find::name );
64 1         7 };
65 1         10 my $find_arg = {
66             %file_find_arg,
67             wanted => $want_sub,
68             no_chdir => 1,
69             };
70 1         107 find( $find_arg, @base_dirs);
71 1         15 return @found;
72             }
73            
74             sub tabs_ok
75             {
76 3     3 1 4 my $file = shift;
77 3         6 $file = _module_to_path($file);
78 3 50       123 open my $fh, $file or do {
79 0         0 $Test->ok(0, "whitespace for $file");
80 0         0 $Test->diag("Could not open $file: $!");
81 0         0 return;
82             };
83 3         6 my $line = 0;
84 3         3 my $last_indent = 0;
85 3         4 my $ignoring = 0;
86 3         3 my $ok = 1;
87 3         58 while (<$fh>)
88             {
89 210         180 $line++;
90            
91 210         247 my $ignore_line = /##\s*WS/i;
92 210 100       375 $ignoring = 1 if /#\s*no\s*Test::Tabs/;
93 210 100       309 $ignoring = 0 if /#\s*use\s*Test::Tabs/;
94            
95 210 50       327 if (/#\s*skip\s*Test::Tabs/)
96             {
97 0 0       0 $ok
98             ? $Test->skip($file)
99             : $Test->ok($ok, "$file contains skip comment, but problems already encountered");
100 0         0 return $ok;
101             }
102            
103 210 100       355 next if (/^\s*#/);
104 207 50 0     379 next if (/^\s*=.+/ .. (/^\s*=(cut|back|end)/ || eof($fh)));
105 207 100       310 last if (/^\s*(__END__|__DATA__)/);
106 206 100 100     645 next if $ignoring || $ignore_line;
107            
108 204         649 my ($indent, $remaining) = (/^([\s\x20]*)(.*)/);
109 204 100       400 next unless length $remaining;
110            
111 178 50       267 if ($indent =~ /\x20/)
112             {
113 0         0 $Test->diag("$file had space indent on line $line");
114 0         0 $ok = 0;
115             }
116 178 50       801 if ($remaining =~ /\t/)
117             {
118 0         0 $Test->diag("$file had non-indenting tab on line $line");
119 0         0 $ok = 0;
120             }
121 178 50       331 if ($remaining =~ /\s$/)
122             {
123 0         0 $Test->diag("$file had trailing whitespace on line $line");
124 0         0 $ok = 0;
125             }
126 178 50       292 if (length($indent) - $last_indent > 1)
127             {
128 0         0 $Test->diag("$file had jumping indent on line $line");
129 0         0 $ok = 0;
130             }
131 178         498 $last_indent = length $indent;
132             }
133 3         15 $Test->ok($ok, "whitespace for $file");
134 3         1559 return $ok;
135             }
136              
137             sub all_perl_files_ok
138             {
139 1     1 1 8 local $Test::Builder::Level = $Test::Builder::Level + 1;
140 1         4 my @files = _all_perl_files( @_ );
141 1         6 _make_plan();
142 1         10 foreach my $file ( sort @files )
143             {
144 3         11 tabs_ok($file, "OK tabs in '$file'");
145             }
146             }
147              
148             sub _is_perl_module
149             {
150 3 100   3   23 $_[0] =~ /\.pm$/i || $_[0] =~ /::/;
151             }
152              
153             sub _is_perl_script
154             {
155 2     2   4 my $file = shift;
156 2 50       7 return 1 if $file =~ /\.pl$/i;
157 2 50       6 return 1 if $file =~ /\.psgi$/;
158 2 50       14 return 1 if $file =~ /\.t$/;
159 0 0       0 open (my $fh, $file) or return;
160 0         0 my $first = <$fh>;
161 0 0 0     0 return 1 if defined $first && ($first =~ $PERL_PATTERN);
162 0         0 return;
163             }
164              
165             sub _module_to_path
166             {
167 3     3   4 my $file = shift;
168 3 50       10 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             {
173 0         0 my $candidate = File::Spec->catfile($dir, $module);
174 0 0 0     0 next unless (-e $candidate && -f _ && -r _);
      0        
175 0         0 return $candidate;
176             }
177 0         0 return $file;
178             }
179              
180             sub _make_plan
181             {
182 1 50   1   7 unless ($Test->has_plan)
183             {
184 1         24 $Test->plan( 'no_plan' );
185             }
186 1         22 $Test->expected_tests;
187             }
188              
189             sub _untaint
190             {
191 0     0     my @untainted = map { ($_ =~ $UNTAINT_PATTERN) } @_;
  0            
192 0 0         return wantarray ? @untainted : $untainted[0];
193             }
194              
195             sub __silly {
196             # this is just for testing really.
197             print "$_\n"
198 0     0     for 1..3; ##WS
199             }
200              
201             ## no Test::Tabs
202             1;
203             ## use Test::Tabs
204              
205             __END__