| 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__ |