File Coverage

blib/lib/Test/NoPlan.pm
Criterion Covered Total %
statement 27 109 24.7
branch 0 56 0.0
condition 0 26 0.0
subroutine 9 13 69.2
pod 3 3 100.0
total 39 207 18.8


line stmt bran cond sub pod time code
1             package Test::NoPlan;
2              
3 1     1   35955 use warnings;
  1         2  
  1         32  
4 1     1   6 use strict;
  1         3  
  1         54  
5              
6 1     1   988 use version; our $VERSION = version->new('0.0.6');
  1         2421  
  1         5  
7              
8 1     1   90 use base 'Exporter';
  1         2  
  1         91  
9 1     1   6 use Test::Builder::Module;
  1         2  
  1         8  
10              
11 1     1   952 use FindBin qw($Bin);
  1         1135  
  1         125  
12 1     1   7 use Cwd;
  1         3  
  1         57  
13 1     1   6 use File::Spec;
  1         2  
  1         19  
14 1     1   14 use Carp;
  1         3  
  1         1662  
15              
16             our @EXPORT = qw( all_plans_ok ); ## no critic (ProhibitAutomaticExportation)
17             our @EXPORT_OK = qw( get_file_list check_file_for_no_plan );
18              
19             {
20             my $CLASS = __PACKAGE__;
21              
22             my @allowed_args
23             = qw/ check_files recurse topdir _stdout _stderr method ignore_files /;
24              
25             sub all_plans_ok {
26 0     0 1   my ($arg_ref) = @_;
27 0   0       $arg_ref->{method} ||= 'create';
28 0           _check_args($arg_ref);
29              
30 0           my @files = get_file_list($arg_ref);
31              
32 0           my $method = $arg_ref->{method};
33 0           my $test = Test::Builder->$method;
34 0 0         if ( $arg_ref->{_stdout} ) {
35 0 0         if ( ref $arg_ref->{_stdout} ne 'IO::Scalar' ) {
36 0           croak '_stdout is not an IO::Scalar';
37             }
38 0           $test->output( $arg_ref->{_stdout} );
39             }
40 0 0         if ( $arg_ref->{_stderr} ) {
41 0 0         if ( ref $arg_ref->{_stderr} ne 'IO::Scalar' ) {
42 0           croak '_stderr is not an IO::Scalar';
43             }
44 0           $test->failure_output( $arg_ref->{_stderr} );
45             }
46              
47 0 0         if ( $method eq 'create' ) {
48 0           $test->plan( tests => scalar @files );
49             }
50             else {
51 0           $test->no_ending();
52             }
53              
54 0           foreach my $file (@files) {
55 0           $test->ok( check_file_for_no_plan($file),
56             "'$file' has 'no_plan' set" );
57             }
58              
59 0 0         if ( $method ne 'create' ) {
60 0           $test->reset_outputs();
61             }
62              
63 0           return scalar @files;
64             }
65              
66             sub _check_args {
67 0     0     my ($arg_ref) = @_;
68 0 0 0       if ( defined($arg_ref) && ref($arg_ref) ne 'HASH' ) {
69 0           croak 'arguments do not seem to be a hash -> ', ref($arg_ref);
70             }
71              
72 0           my @unknown_args;
73              
74 0           foreach my $arg ( sort( keys(%$arg_ref) ) ) {
75 0 0         if ( !grep {/^$arg$/} @allowed_args ) {
  0            
76 0           push @unknown_args, $arg;
77             }
78             }
79 0 0         if (@unknown_args) {
80 0           die 'Unknown arguments: ', join( ',', @unknown_args );
81             }
82              
83 0 0         if ( $arg_ref->{method} ) {
84 0 0 0       if ( $arg_ref->{method} ne 'create'
85             && $arg_ref->{method} ne 'new' )
86             {
87 0           croak 'Method must be one of "create" or "new", not "',
88             $arg_ref->{method}, '"';
89             }
90             }
91 0           return;
92             }
93              
94             sub get_file_list {
95 0     0 1   my ($arg_ref) = @_;
96              
97 0           _check_args($arg_ref);
98              
99 0           my $topdir = $Bin;
100 0 0 0       if ( $arg_ref->{topdir} && $arg_ref->{topdir} ne '.' ) {
101 0           $topdir = $arg_ref->{topdir};
102             }
103 0 0 0       if ( defined($topdir) && length $topdir && !-d $topdir ) {
      0        
104 0           die( 'Invalid topdir provided: "' . $topdir . '"' );
105             }
106 0           my $cwd = getcwd();
107 0           $topdir =~ s!$cwd/!!;
108              
109 0           my $check_files = qr/\.t$/xsm;
110 0 0         if ( $arg_ref->{check_files} ) {
111 0           $check_files = $arg_ref->{check_files};
112             }
113 0 0         if ( ref($check_files) ne 'Regexp' ) {
114 0           die 'invalid check_files provided';
115             }
116              
117 0           my $ignore_files = qr/^\..*/;
118 0 0         if ( $arg_ref->{ignore_files} ) {
119 0           $ignore_files = $arg_ref->{ignore_files};
120             }
121              
122 0           my @files = ();
123 0 0         opendir( my $topdir_dh, $topdir )
124             or die 'Unable to read ', $topdir, ': ', $!;
125              
126 0           while ( my $dir_entry = readdir($topdir_dh) ) {
127 0 0         next if ( $dir_entry =~ m/^\./xsm );
128              
129 0           my $resolved_entry = File::Spec->catfile( $topdir, $dir_entry );
130              
131 0 0         if ( -d $resolved_entry ) {
132 0 0         if ( $arg_ref->{recurse} ) {
133 0           my %new_args = %$arg_ref;
134 0           $new_args{topdir} = $resolved_entry;
135 0           push @files, get_file_list( \%new_args );
136              
137             #{ %{$arg_ref}, topdir => $resolved_entry, } );
138             }
139 0           next;
140             }
141              
142 0 0 0       if ( $dir_entry =~ $check_files && $dir_entry !~ $ignore_files ) {
143 0           push @files, $resolved_entry;
144             }
145             }
146              
147 0 0         closedir($topdir_dh) or die 'Unable to close ', $topdir, ': ', $!;
148              
149 0 0         return wantarray ? sort @files : "@files";
150             }
151              
152             sub check_file_for_no_plan {
153 0     0 1   my ($file) = @_;
154              
155 0 0         if ( !-s $file ) {
156 0           croak "'$file' does not exist or is empty";
157             }
158              
159 0 0         open( my $file_fh, '<', $file )
160             or die 'Unable to read ' . $file . ': ', $!;
161 0           my $file_contents;
162             {
163 0           local $/ = undef;
  0            
164 0           $file_contents = <$file_fh>;
165             }
166 0 0         close($file_fh)
167             or die 'Unable to close ' . $file . ': ', $!;
168              
169             # by default everything is ok, for those tests that do not use
170             # Test::More directly
171 0           my $return_code = 1;
172              
173             # look for uncommented lines containing Test::More or plan
174             # followed by uncommented test keyword - these are ok
175 0 0 0       if ( $file_contents =~ m/^[^#]*\bTest::More\b[^#]*\btests\b/xm
    0 0        
176             || $file_contents =~ m/^[^#]*\bplan\b[^#]*\btests\b/xm )
177             {
178 0           $return_code = 1;
179             }
180              
181             # look for uncommented lines containing Test::More or plan
182             # followed by uncommented no_plan keyword - these are problems
183             elsif ($file_contents =~ m/^[^#]*\bTest::More\b[^#]*\bno_plan\b/xm
184             || $file_contents =~ m/^[^#]*\bplan\b[^#]*\bno_plan\b/xm )
185             {
186 0           $return_code = 0;
187             }
188              
189 0           return $return_code;
190             }
191             }
192              
193             1; # End of Test::NoPlan
194              
195             __END__