File Coverage

lib/Test/Spelling/Comment.pm
Criterion Covered Total %
statement 134 134 100.0
branch 47 48 97.9
condition 6 6 100.0
subroutine 17 17 100.0
pod 3 3 100.0
total 207 208 99.5


line stmt bran cond sub pod time code
1             package Test::Spelling::Comment;
2              
3 8     8   504946 use 5.006;
  8         71  
4 8     8   32 use strict;
  8         10  
  8         132  
5 8     8   43 use warnings;
  8         11  
  8         338  
6              
7             our $VERSION = '0.004';
8              
9 8     8   3221 use Moo;
  8         65533  
  8         32  
10              
11 8     8   8608 use Carp ();
  8         14  
  8         88  
12 8     8   2783 use Comment::Spell::Check ();
  8         4404887  
  8         184  
13 8     8   71 use File::Find ();
  8         15  
  8         98  
14 8     8   37 use Pod::Wordlist ();
  8         13  
  8         105  
15 8     8   37 use Scalar::Util ();
  8         15  
  8         101  
16 8     8   32 use Test::Builder ();
  8         17  
  8         7854  
17              
18             has _skip => (
19             is => 'ro',
20             init_arg => 'skip',
21             );
22              
23             has _stopwords => (
24             is => 'ro',
25             isa => sub { Carp::croak q{stopwords must have method 'wordlist'} if !Scalar::Util::blessed( $_[0] ) || !$_[0]->can('wordlist'); },
26             init_arg => 'stopwords',
27             lazy => 1,
28             default => sub { Pod::Wordlist->new },
29             predicate => 1,
30             );
31              
32             my $TEST = Test::Builder->new();
33              
34             # - Do not use subtests because subtests cannot be tested with
35             # Test::Builder:Tester.
36             # - Do not use a plan because a method that sets a plan cannot be tested
37             # with Test::Builder:Tester.
38             # - Do not call done_testing in a method that should be tested by
39             # Test::Builder::Tester because TBT cannot test them.
40              
41             sub add_stopwords {
42 6     6 1 16501 my $self = shift;
43              
44 6         278 my $wordlist = $self->_stopwords->wordlist;
45              
46             STOPWORD:
47 6         2043 for (@_) {
48              
49             # explicit copy
50 9         74 my $stopword = $_;
51 9         55 $stopword =~ s{ ^ \s* }{}xsm;
52 9         63 $stopword =~ s{ \s+ $ }{}xsm;
53 9 50       38 next STOPWORD if $stopword eq q{};
54              
55 9         42 $wordlist->{$stopword} = 1;
56             }
57              
58 6         81 return $self;
59             }
60              
61             sub all_files_ok {
62 15     15 1 41944 my $self = shift;
63              
64 15 100       118 my @args = scalar @_ ? @_ : $self->_default_dirs();
65 15 100       50 if ( !@args ) {
66 1         8 $TEST->skip_all("No files found\n");
67 1         22 return 1;
68             }
69              
70 14         40 my @files;
71             ARG:
72 14         29 for my $arg (@args) {
73 17 100       233 if ( !-e $arg ) {
74 1         7 $TEST->carp("File '$arg' does not exist");
75 1         7 next ARG;
76             }
77              
78 16 100       160 if ( -l $arg ) {
79 1         7 $TEST->carp("Ignoring symlink '$arg'");
80 1         7 next ARG;
81             }
82              
83 15 100       145 if ( -f $arg ) {
84 3         7 push @files, $arg;
85 3         7 next ARG;
86             }
87              
88 12 100       110 if ( !-d $arg ) {
89 1         7 $TEST->carp("File '$arg' is not a file nor a directory. Ignoring it.");
90 1         7 next ARG;
91             }
92              
93             File::Find::find(
94             {
95             no_chdir => 1,
96             preprocess => sub {
97 17     17   55 my @sorted = sort grep { !-l "$File::Find::dir/$_" } @_;
  51         609  
98 17         550 return @sorted;
99             },
100             wanted => sub {
101 26 100   26   1066 return if !-f $File::Find::name;
102 9         115 push @files, $File::Find::name;
103             },
104             },
105 11         1321 $arg,
106             );
107             }
108              
109 14 100       40 if ( !@files ) {
110 7         35 $TEST->skip_all("No files found in (@args)\n");
111 7         89 return 1;
112             }
113              
114 7         15 my $rc = 1;
115 7         17 for my $file ( grep { $_ !~ m{ [~] $ }xsm } @files ) {
  12         53  
116 12 100       61 if ( !$self->file_ok($file) ) {
117 1         17 $rc = 0;
118             }
119             }
120              
121 7         53 $TEST->done_testing;
122              
123 7 100       93 return 1 if $rc;
124 1         86 return;
125             }
126              
127             sub file_ok {
128 15     15 1 41393 my ( $self, $file ) = @_;
129              
130 15 100 100     342 Carp::croak 'usage: file_ok(FILE)' if @_ != 2 || !defined $file;
131              
132 12 100       207 if ( !-f $file ) {
133 1         9 $TEST->ok( 0, $file );
134 1         1101 $TEST->diag("\n");
135 1         180 $TEST->diag("File $file does not exist or is not a file");
136              
137 1         203 return;
138             }
139              
140 11         25 my $fh;
141 11 100       308 if ( !open $fh, '<', $file ) {
142 1         7 $TEST->ok( 0, $file );
143 1         853 $TEST->diag("\n");
144 1         172 $TEST->diag("Cannot read file '$file': $!");
145              
146 1         165 return;
147             }
148              
149 10         203 my @lines = <$fh>;
150 10         28 chomp @lines;
151              
152 10 100       82 if ( !close $fh ) {
153 1         9 $TEST->ok( 0, $file );
154 1         907 $TEST->diag("\n");
155 1         169 $TEST->diag("Cannot read file '$file': $!");
156              
157 1         176 return;
158             }
159              
160 9         33 my $skips_ref = $self->_skip;
161 9 100       16 if ( defined $skips_ref ) {
162 5 100 100     32 if ( ( !defined Scalar::Util::reftype($skips_ref) )
163             || ( Scalar::Util::reftype($skips_ref) ne Scalar::Util::reftype( [] ) ) )
164             {
165 3         7 $skips_ref = [$skips_ref];
166             }
167              
168 5         11 for my $line (@lines) {
169 20         24 for my $skip ( @{$skips_ref} ) {
  20         28  
170             ## no critic (RegularExpressions::RequireDotMatchAnything)
171             ## no critic (RegularExpressions::RequireExtendedFormatting)
172             ## no critic (RegularExpressions::RequireLineBoundaryMatching)
173 28         134 $line =~ s{$skip}{}g;
174             ## use critic
175             }
176             }
177             }
178              
179 9 100       173 my $speller = Comment::Spell::Check->new( $self->_has_stopwords ? ( stopwords => $self->_stopwords ) : () );
180 9         1739 my $buf;
181 9         33 $speller->set_output_string($buf);
182 9         368 my $result;
183 9 100       13 if ( !eval { $result = $speller->parse_from_string( join "\n", @lines, q{} ); 1 } ) {
  9         33  
  7         116  
184 2         14 my $error_msg = $@;
185 2         7 $TEST->ok( 0, $file );
186 2         1422 $TEST->diag("\n$error_msg\n\n");
187              
188 2         348 return;
189             }
190              
191 7 100       9 if ( @{ $result->{fails} } == 0 ) {
  7         16  
192 6         21 $TEST->ok( 1, $file );
193              
194 6         1223 return 1;
195             }
196              
197 1         4 $TEST->ok( 0, $file );
198 1         761 $TEST->diag("\n$buf\n\n");
199              
200 1         177 return;
201             }
202              
203             sub _default_dirs {
204 14     14   25636 my ($self) = @_;
205              
206 14         46 my @dirs;
207 14 100       312 if ( -d 'blib' ) {
    100          
208 3         21 push @dirs, 'blib';
209             }
210             elsif ( -d 'lib' ) {
211 6         52 push @dirs, 'lib';
212             }
213              
214 14 100       151 if ( -d 'bin' ) {
215 4         18 push @dirs, 'bin';
216             }
217              
218 14 100       146 if ( -d 'script' ) {
219 2         23 push @dirs, 'script';
220             }
221              
222 14         58 my @sorted = sort @dirs;
223 14         93 return @sorted;
224             }
225              
226 8     8   63 no Moo;
  8         15  
  8         51  
227              
228             1;
229              
230             __END__