File Coverage

blib/lib/Test/Verbose.pm
Criterion Covered Total %
statement 179 306 58.5
branch 67 214 31.3
condition 24 117 20.5
subroutine 21 31 67.7
pod 13 19 68.4
total 304 687 44.2


line stmt bran cond sub pod time code
1             package Test::Verbose;
2              
3             $VERSION = 0.010;
4              
5             #BEGIN {
6             # *CORE::GLOBAL::chdir = \&my_chdir;
7             #}
8             #
9             #sub my_chdir {
10             # warn $_[0], " at ", join " ", map defined $_ ? $_ : "undef", caller(0), "\n";
11             # CORE::chdir( $_[0] );
12             #}
13              
14             =head1 NAME
15              
16             Test::Verbose - Run 'make TEST_VERBOSE=1' on one or more test files
17              
18             =head1 SYNOPSIS
19              
20             # from the command line. man tv for more details.
21             $ tv lib/Foo.pm # test this module
22             $ tv t/*.t # run these tests
23              
24             # from a module
25             use Test::Verbose qw( test_verbose );
26             test_verbose( @module_and_test_script_filenames );
27              
28             For more control, you can use the object oriented interface.
29              
30             See also the L command.
31              
32             =head1 DESCRIPTION
33              
34             Given a list of test scripts, source file names, directories and/or
35             package names, attempts to find and execute the appropriate test
36             scripts.
37              
38             This (via the associated tv command) is useful when developing code or
39             test scripts: just map "tv %" to a key in your editor and press it
40             frequently (where "%" is your editor's macro for "the file being
41             edited).
42              
43             Before doing anything, this module identifies the working directory for
44             the project by scanning the current directory and it's ancestors,
45             stopping at the first directory that contains a "t" directory.
46              
47             If an explicitly named item (other than POD files) cannot be tested, an
48             exception is thrown.
49              
50             Here is how each name passed in is treated:
51              
52             =over
53              
54             =item test script
55              
56             An explicitly mentioned test script is selected, no source files need be
57             parsed. Names of test scripts are recognized by ending in ".t" and, if
58             they exist on the filesystem, by being a file (and not a directory).
59              
60             =item source file
61              
62             Source files ending in ".pl", ".pm", or ".pod" are run through
63             C, then perl -cw before any tests are run. This
64             forces useful POD and does a quick shortcircuit syntax check of the
65             source files before the possibly length make test gets run.
66              
67             Source files are parsed (very naively) looking for C declarations
68             and for test scripts listed in special POD comments:
69              
70             =for test_script foo.t bar.t
71             baz.t
72              
73             Also, all test scripts are parsed looking for C and C
74             statements and for POD that looks like:
75              
76             =for file lib/Foo.pm
77              
78             or
79              
80             =for package Foo
81              
82             . All test scripts pertaining to a given file and any packages in it
83             are then selected.
84              
85             Before any test scripts are run, source files are run through
86             L and through C. The former is to
87             check POD, something normal test suites don't do, and the latter is
88             because running C for a distribution with a lot of
89             modules can be slow and I want to give per-module feedback ASAP.
90              
91             The paths listed in C<=for file> must be paths relative to the project
92             root and not contain "..". Hmmm, they can also be absolute paths, but
93             why would you do that?
94              
95             Names of source files are recognized by not ending in ".t" and not
96             looking like a package name or, if they do look like a package name, by
97             existing on the filesystem.
98              
99             =item directory
100              
101             Directories are travered looking for files with the extensions ".t",
102             ".pm", ".pod", or ".pl". These are then treated as though they had been
103             explicitly named. Note that this notion of "looks like a source file"
104             differs from that used when a source file is explicitly passed (where
105             any extension other than .t may be used).
106              
107             =item package name
108              
109             If a name looks like a legal package name (Contains only word characters
110             and "::" digraphs) and does not exist on the filesystem, then it is
111             assumed to be a package name. In this case, all explicitly mentioned
112             source files and test script files are scanned as normal, as well as
113             those found by scanning the main project directory and (only) it's lib
114             and t subdirectories. Files found there are not selected, but are used
115             to determine what tests to run for a package.
116              
117             =back
118              
119             =head1 .tvrc file
120              
121             If a .tvrc file is found in a project's root directory, it is run just
122             before any tests. This allows you to set important env. vars:
123              
124             $ENV{DBI_USER}="barries";
125             $ENV{DBI_PASS}="yuck";
126              
127             $tv->pure_perl = 1;
128              
129             This support is experimental but should be ok for now. Options set here
130             may be overridden on the command line.
131              
132             =head1 FUNCTIONS
133              
134             test_verbose( @names );
135             test_verbose( @names, \%options );
136              
137             Shortcut for
138              
139             my $tv = Test::Verbose->new( %options )->test( @names );
140              
141             =cut
142              
143             @EXPORT_OK = qw( test_verbose is_win32 );
144             @ISA = qw( Exporter );
145              
146 1     1   14215 use strict;
  1         3  
  1         213  
147              
148 1 50   1   6 use constant debugging => $ENV{TVDEBUG} ? 1 : 0;
  1         2  
  1         178  
149 1     1   7 use constant is_win32 => $^O =~ /Win32/i;
  1         7  
  1         79  
150 1 50   1   7 use constant MAKE => is_win32 ? "nmake.exe" : "make";
  1         2  
  1         119  
151              
152             BEGIN {
153 1     1   7 require Exporter;
154 1         7 require Carp;
155 1         6 require Cwd;
156 1         606 require File::Spec;
157             }
158              
159             sub test_verbose {
160 0 0   0 0 0 my $options = ref $_[-1] eq "HASH" ? pop : {};
161 0         0 return Test::Verbose->new( %$options )->test( @_ );
162             }
163              
164             =head1 METHODS
165              
166             =over
167              
168             =item new
169              
170             Takes a list of options:
171              
172             =over
173              
174             =item Debug
175              
176             Runs the test scripts directly using perl C<-d>. Causes ExtUtils to
177             be ignored.
178              
179             =item Dir
180              
181             What directory to look for t/ and run make(1) in. Undefined causes
182             the instance to search for a directory containing a directory named "t"
183             in the current directory and its parents.
184              
185             =item JustPrint
186              
187             Print out the command to be executed.
188              
189             =item ExtUtils
190              
191             Don't use C, use
192             C
193             instead.
194             Useful if you don't have a Makefile.PL; might not work on all versions
195             of perl.
196              
197             =back
198              
199             =cut
200              
201             sub new {
202 6     6 1 8309 my $proto = shift;
203 6 50       42 my $self = bless {}, ref $proto ? ref $proto : $proto;
204              
205 6         32 $self->load_rc;
206              
207 6         63 my %options = @_;
208              
209 6         81 for ( keys %options ) {
210 0 0       0 $self->{$_} = $options{$_}
211             if defined $options{$_};
212             }
213              
214 6 50 33     185 $self->{TestPOD} = $self->{Compile} = $self->{RunTests} = 1
      33        
215             unless $self->{TestPOD} || $self->{Compile} || $self->{RunTests};
216              
217 6 50       26 $self->{TestPOD} = 0 if $self->{NoPOD};
218 6 50       34 $self->{Compile} = 0 if $self->{NoCompile};
219 6 50       29 $self->{RunTests} = 0 if $self->{NoTests};
220              
221 6   33     55 $self->{DoubleQuiet} ||= $self->{TripleQuiet};
222 6   33     41 $self->{Quiet} ||= $self->{DoubleQuiet};
223              
224 6         340 return $self;
225             }
226              
227             =item load_rc
228              
229             Scans for and loads the .tvrc file.
230              
231             NOTE: may be expanded in the future to load multiple RC files.
232              
233             So far, only a few attributes are available, will add more as I need
234             to.
235              
236             For 100% pure perl modules, a common .tvrc is:
237              
238             $tv->pure_perl = 1;
239              
240             . And a way to shush tv from printing out all the good news is:
241              
242             $tv->quiet = 1;
243              
244             =cut
245              
246             sub load_rc {
247 6     6 1 12 my $self = shift;
248              
249 6         9 my $rc_file = ".tvrc";
250              
251 6         21 my $d = $self->dir;
252              
253 6         129 $self->{ConfigClass} = join "", "Test::Verbose::Config::", int $self;
254            
255             $rc_file = -e $rc_file
256 6 50       120 ? do {
257 0 0       0 open RC_FILE, "<$rc_file" or die "$!: $rc_file";
258 0         0 local $/ = undef;
259 0         0 my $code = ;
260 0         0 close RC_FILE;
261 0         0 my $self_class = ref $self;
262 0         0 bless $self, $self->{ConfigClass};
263 0         0 my $fn = File::Spec->rel2abs( $rc_file, $d );
264 0         0 join "",
265             "package $self->{ConfigClass};\n",
266             "no strict;\n",
267             "\@ISA = qw( ", $self_class, " );\n",
268             "use strict;\n",
269             "our \$tv;",
270             "sub AUTOLOAD {};\n",
271             "#line 1 $fn\n",
272             $code,
273             "\n",
274             "1;";
275             }
276             : undef;
277              
278 6 50       38 if ( defined $rc_file ) {
279             {
280 1     1   5 no strict "refs";
  1         2  
  1         5623  
  0         0  
281 0         0 ${"$self->{ConfigClass}::tv"} = $self;
  0         0  
282             }
283              
284 0 0       0 eval $rc_file or die $@;
285             }
286              
287             }
288              
289             =item dir
290              
291             my $dir = $tv->dir;
292             $tv->dir( undef ); ## clear old setting
293             $tv->dir( "foo" ); ## prevent chdir( ".." ) searching
294             $tv->dir = "foo";
295              
296             Looks for t/ or lib/ in the current directory or in any parent directory.
297             Cs up the directory tree until t/ is found, then back to the
298             directory it started in, so make sure you have permissions to C
299             up and back.
300              
301             Passing a Dir => $dir option to new prevents this method for searching
302             for a name,
303              
304             =cut
305              
306             sub dir: lvalue {
307 26     26 1 72 my $self = shift;
308              
309 26 50       83 $self->{Dir} = shift if @_;
310            
311 26 100 66     254 if ( defined wantarray && ! defined $self->{Dir} ) {
312 6         9 warn "tv: searching for project directory\n" if debugging;
313 6         43557 my $cwd = Cwd::cwd;
314             ## cd up until we find a directory that has a "t" subdirectory
315             ## this is for folks whose editor's working directories might be
316             ## down in t/ or lib/, etc.
317 6         82 my $last_d = $cwd;
318 6   66     471 until ( -d "t" || -d "lib" ) {
319 3 50       165 chdir( File::Spec->updir )
320             or die "tv: $! while cd()ing upwards looking for t/ or lib/";
321 3         14173 my $new_d = Cwd::cwd;
322 3 50       95 die "tv: could not find t/ or lib/ in any parent of $cwd\n"
323             if length $new_d eq length $last_d;
324 3         117 $last_d = $new_d;
325             }
326 6         39136 $self->{Dir} = Cwd::cwd;
327 6         88 warn "tv: ...found $self->{Dir}\n" if debugging;
328 6 50       280 chdir $cwd or die "tv: $! chdir()ing back to '$cwd'";
329             }
330              
331 26         1762 $self->{Dir};
332             }
333              
334              
335             =item pure_perl
336              
337             $tv->pure_perl = 1;
338             print $tv->pure_perl;
339              
340             =cut
341              
342             sub pure_perl: lvalue {
343 0     0 1 0 my $self = shift;
344 0 0       0 $self->{PurePerl} = shift if @_;
345 0         0 $self->{PurePerl};
346             }
347              
348             =item quiet
349              
350             $tv->quiet = 1;
351              
352             =cut
353              
354             sub quiet: lvalue {
355 0     0 1 0 my $self = shift;
356 0 0       0 $self->{Quiet} = shift if @_;
357 0         0 $self->{Quiet};
358             }
359              
360             =item double_quiet
361              
362             $tv->double_quiet = 1;
363              
364             =cut
365              
366             sub double_quiet: lvalue {
367 0     0 1 0 my $self = shift;
368 0 0       0 $self->{DoubleQuiet} = shift if @_;
369 0         0 $self->{DoubleQuiet};
370             }
371              
372             =item triple_quiet
373              
374             $tv->triple_quiet = 1;
375              
376             =cut
377              
378             sub triple_quiet: lvalue {
379 0     0 1 0 my $self = shift;
380 0 0       0 $self->{DoubleQuiet} = shift if @_;
381 0         0 $self->{DoubleQuiet};
382             }
383              
384             =item is_test_script
385              
386             $self->is_test_script; ## tests $_
387             $self->is_test_script( $name );
388              
389             Returns true if the name looks like the name of a test script (ends in .t).
390             File does not need to exist.
391              
392             Overload this to alter Test::Verbose's perceptions.
393              
394             =cut
395              
396             sub is_test_script {
397 30     30 1 57 my $self = shift;
398 30 50       73 local $_ = shift if @_;
399 30 100 66     709 /\.t\z/ && ( ! -e || -f _ );
400             }
401              
402              
403             =item is_pod_file
404              
405             $self->is_pod_file; ## tests $_
406             $self->is_pod_file( $name );
407              
408             Returns true if the name looks like the name of a pod file (ends in
409             .pod). File does not need to exist, but must be a file if it
410             does.
411              
412             Overload this to alter Test::Verbose's perceptions.
413              
414             =cut
415              
416             sub is_pod_file {
417 2     2 1 5 my $self = shift;
418 2 50       6 local $_ = shift if @_;
419 2 50 0     11 /\.(pod)\z/ && ( ! -e || -f _ );
420             }
421              
422              
423             =item is_source_file
424              
425             $self->is_source_file; ## tests $_
426             $self->is_source_file( $name );
427              
428             Returns true if the name looks like the name of a source file (ends in
429             .pm, .pod or .pl). File does not need to exist, but must be a file if it
430             does.
431              
432             This is only used when traversing directory trees, otherwise a file name
433             (ie not a package) is assumed to be a source file if it is not a test
434             file.
435              
436             Overload this to alter Test::Verbose's perceptions.
437              
438             =cut
439              
440             sub is_source_file {
441 18     18 1 34 my $self = shift;
442 18 50       49 local $_ = shift if @_;
443 18 100 33     448 /\.(pm|pl|pod)\z/ && ( ! -e || -f _ );
444             }
445              
446              
447             =item is_package
448              
449             $self->is_test_script; ## tests $_
450             $self->is_test_script( $name );
451              
452             Returns trues if the name looks like the name of a package (contains
453             only /\w/ and "::") and is not a name that exists (ie C).
454              
455             Overload this to alter Test::Verbose's perceptions.
456              
457             =cut
458              
459              
460             sub is_package {
461 9     9 1 13 my $self = shift;
462 9 50       27 local $_ = shift if @_;
463 9 100       504 /\A(\w|::)+\z/ && ! -e;
464             }
465              
466              
467             =item unhandled
468              
469             $self->unhandled( @_ );
470              
471             die()s with any unhandled names.
472              
473             Overload this to alter the default.
474              
475             =cut
476              
477             sub unhandled {
478 0     0 1 0 my $self = shift;
479              
480 0 0       0 warn "tv: no test scripts found for: ", join( ", ", @_ ), "\n",
481             "Try adding '=for test_script ...' to the source",
482             @_ > 1 ? "s" : "",
483             " or 'use ...;' or '=for package ...' to the test scripts\n";
484             }
485              
486             =item look_up_scripts
487              
488             my @scripts = $tv->look_up_test_scripts( @_ );
489              
490             Looks up the scripts for any names that don't look like test scripts.
491              
492             die()s if a non-test script cannot be found.
493              
494             use =for tv dont_test to prevent this error.
495              
496             All test scripts returned will have the form "t/foo.t", and the result
497             is sorted. No test script name will be returned more than once.
498              
499             =cut
500              
501             sub test_scripts_for {
502 6     6 0 21 my $self = shift;
503              
504 6         10 my @test_scripts;
505              
506 6         78 local $self->{Names} = [ $self->_traverse_dirs( @_ ) ];
507              
508 6         45 for ( @{$self->{Names}} ) {
  6         23  
509 12 100       52 if ( $self->is_test_script ) {
    100          
    50          
    50          
510 9         37 push @test_scripts, $_;
511             }
512             elsif ( $self->is_package ) {
513 1         23 my @t = $self->test_scripts_for_package;
514 1 50       13 if ( @t ) {
515 1         19 push @test_scripts, @t;
516             }
517             else {
518 0         0 push @{$self->{Unhandled}}, $_;
  0         0  
519             }
520             }
521             elsif ( -d ) {
522 0         0 Carp::confess "BUG: this code branch should be unreachable";
523             # my @t = $self->test_scripts_for_dir;
524             # if ( @t ) {
525             # push @test_scripts, @t;
526             # }
527             # else {
528             # push @{$self->{Unhandled}}, $_;
529             # }
530             }
531             elsif ( $self->is_pod_file ) {
532 0         0 push @{$self->{PodChecks}}, $_;
  0         0  
533 0         0 push @test_scripts, $self->test_scripts_for_pod_file;
534             # It is not an error for a pod file to not have a test
535             # script.
536             }
537             else {
538             # It's a code file
539 2         2 push @{$self->{CompileChecks}}, $_;
  2         13  
540 2         25 my @t = $self->test_scripts_for_file;
541 2 50       11 if ( @t ) {
542 2         27 push @test_scripts, @t;
543             }
544             else {
545 0         0 push @{$self->{Unhandled}}, $_;
  0         0  
546             }
547             }
548             }
549              
550 6         23 my %seen;
551 22         90 return sort grep !$seen{$_}++, map {
552             ## Make all test scripts look like "t/foo.t"
553 6         22 $_ = File::Spec->canonpath( $_ );
554 22         127 s{^(?![\\/])(t[\\/])?}{t/};
555 22         419 $_;
556             } @test_scripts
557             }
558              
559              
560             sub _slurp_and_split {
561 9     9   67 my @items = split /\s+/, $1;
562 9         14 local $_;
563 9         143 while () {
564 12 100       88 last if /^$/;
565 3         33 push @items, split /\s+/;
566             }
567              
568 9         76 return grep length, @items;
569             }
570              
571              
572             sub _traverse_dirs {
573 10     10   22 my $self = shift;
574 10         68 my @names = @_;
575              
576 13         45 return map {
577 10         35 my $dir = $_;
578             -d $dir
579 13 100       396 ? do {
580 6         13 my @results;
581 6         9 warn "tv: traversing $_\n" if debugging;
582 6         175 require File::Find;
583             File::Find::find(
584             sub {
585 24 50 66 24   1444 if (
      66        
586             -f
587             && ( $self->is_source_file ||
588             $self->is_test_script
589             )
590             ) {
591 18         46 push @results, $File::Find::name;
592 18         24 push @{$self->{FilesInDir}->{$dir}},
  18         960  
593             $File::Find::name;
594             }
595             },
596 6         1566 $_
597             );
598 6 50       146 @results ? @results : $_;
599             }
600             : $dir;
601             } @names;
602             }
603              
604              
605             sub _scan_source_files {
606 3     3   12 my $self = shift;
607              
608 3         11 my @files = grep ! $self->is_package && ! $self->is_test_script,
609 3   66     5 @{$self->{Names}};
610              
611 3 100       7 if ( grep $self->is_package, @{$self->{Names}} ) {
  3         11  
612             ## Scan all likely source files to look for those that
613             ## might contain the package.
614             push @files,
615             $self->_traverse_dirs( File::Spec->catdir( $self->dir, 'lib') ),
616 1         24 do {
617             # Look for source files in the project dir's top level.
618 1         16 opendir D, $self->dir;
619 1   33     86 my @f = grep
620             -f && $self->is_source_file,
621             readdir D;
622 1         7 close D;
623 1         6 @f = map File::Spec->catdir( $self->dir, $_ ), @f;
624             };
625             }
626              
627 3         16075 my $cwd = Cwd::cwd;
628              
629 3         75 for my $code_file ( @files ) {
630 3         8 warn "tv: scanning code file $code_file\n" if debugging;
631 3 50       216 open F, $code_file or die "tv: $!: $code_file";
632 3         377 my $abs_fn = File::Spec->canonpath(
633             File::Spec->rel2abs( $code_file, $cwd )
634             );
635              
636 3         10 my $package = "main";
637 3         20 local $/ = "\n";
638 3         10 local $_;
639 3         56 while () {
640 24 100       271 if ( /^=for\s+test_scripts?\s+(.*)/ ) {
    100          
    100          
641 3         29 my @scripts = _slurp_and_split;
642 3         5 warn "tv: $abs_fn, $package =for test_scripts ",
643             join( " ", @scripts ), "\n"
644             if debugging;
645 3         6 push @{$self->{Files}->{$abs_fn}}, @scripts;
  3         32  
646 3         6 push @{$self->{Packages}->{$package}}, @scripts;
  3         31  
647             }
648             elsif ( /^\s*package\s+(\S+)\s*;/ ) {
649 3         38 $package = $1;
650 3         8 warn "tv: $abs_fn declares $package\n" if debugging;
651 3         6 push @{$self->{PackagesForFile}->{$abs_fn}}, $package;
  3         79  
652             }
653             elsif ( /^=/ ) {
654 3         35 push @{$self->{PodChecks}}, $code_file
  3         28  
655 3 50       8 unless grep $_ eq $code_file, @{$self->{PodChecks}};
656             }
657             }
658 3 50       69 close F or die "tv: $! closing $code_file";
659             }
660              
661 3         54 1;
662             }
663              
664              
665             sub _scan_test_scripts {
666 3     3   10 my $self = shift;
667              
668 3         12709 my $cwd = Cwd::cwd;
669              
670 3 50       128 chdir $self->dir or Carp::croak "$!: ", $self->dir, "\n";
671 3         38 my @all_test_scripts = grep /.t\z/, $self->_traverse_dirs( "t" );
672 3 50       80 chdir $cwd or Carp::croak "$!: $cwd\n";
673              
674 3 50       14 warn "tv: no test scripts (t/*.t) found for project\n" unless @all_test_scripts;
675              
676 3         23 for my $test_script ( @all_test_scripts ) {
677 12         23 warn "tv: scanning test script $test_script\n" if debugging;
678 12 50       42 open F, File::Spec->catfile( $self->dir, $test_script )
679             or Carp::croak "$!: $test_script\n";
680              
681 12         74 local $/ = "\n";
682 12         32 local $_;
683 12         180 while () {
684 84 100       666 if ( /^=for\s+packages?\s+(.*)/ ) {
    100          
    100          
685 3         12 my @pkgs = _slurp_and_split;
686 3         10 warn "tv: $test_script =for packages ", join( " ", @pkgs ), "\n"
687             if debugging;
688 3         8 map push( @{$self->{Packages}->{$_}}, $test_script ), @pkgs;
  3         20  
689             }
690             elsif ( /^=for\s+files?\s+(.*)/ ) {
691 3         13 my @files = map
692             File::Spec->canonpath(
693             File::Spec->rel2abs( $_, $self->dir )
694             ), _slurp_and_split;
695 3         7 warn "tv: $test_script =for files ", join( " ", @files ), "\n"
696             if debugging;
697 3         22 map
698 3         10 push( @{$self->{Files}->{$_}}, $test_script ),
699             @files;
700             }
701             elsif ( /\s*(use|require)\s+([\w:]+)/ ) {
702 15         19 warn "tv: $test_script $1s $2\n" if debugging;
703 15         20 push @{$self->{Packages}->{$2}}, $test_script;
  15         140  
704             }
705             }
706 12 50       193 close F or die "tv: $! closing $test_script";
707             }
708              
709 3         38 1;
710             }
711              
712              
713             sub test_scripts_for_package {
714 3     3 0 15 my $self = shift;
715 3 50       23 local $_ = shift if @_;
716              
717 3   66     36 $self->{ScannedSourceFiles} ||= $self->_scan_source_files;
718 3   66     52 $self->{ScannedTestScripts} ||= $self->_scan_test_scripts;
719              
720 3         57 return exists $self->{Packages}->{$_}
721 3 50       16 ? @{$self->{Packages}->{$_}}
722             : ();
723             }
724              
725              
726             sub test_scripts_for_file {
727 2     2 0 3 my $self = shift;
728 2 50       6 local $_ = shift if @_;
729              
730 2   33     31 $self->{ScannedSourceFiles} ||= $self->_scan_source_files;
731 2   33     138 $self->{ScannedTestScripts} ||= $self->_scan_test_scripts;
732              
733 2         11455 local $_ = File::Spec->canonpath(
734             File::Spec->rel2abs( $_, Cwd::cwd )
735             );
736              
737             return (
738 2         22 exists $self->{Files}->{$_}
739 2         35 ? @{$self->{Files}->{$_}}
740             : (),
741             exists $self->{PackagesForFile}->{$_}
742             ? map $self->test_scripts_for_package,
743 2 50       54 @{$self->{PackagesForFile}->{$_}}
    50          
744             : (),
745             );
746             }
747              
748              
749             sub test_scripts_for_pod_file {
750 0     0 0   my $self = shift;
751 0 0         local $_ = shift if @_;
752              
753 0   0       $self->{ScannedSourceFiles} ||= $self->_scan_source_files;
754 0   0       $self->{ScannedTestScripts} ||= $self->_scan_test_scripts;
755              
756 0           local $_ = File::Spec->canonpath(
757             File::Spec->rel2abs( $_, Cwd::cwd )
758             );
759              
760             return
761 0           exists $self->{Files}->{$_}
762 0 0         ? @{$self->{Files}->{$_}}
763             : ();
764             }
765              
766              
767             #sub test_scripts_for_dir {
768             # my $self = shift;
769             # local $_ = shift if @_;
770             #
771             # $self->{ScannedSourceFiles} ||= $self->_scan_source_files;
772             # $self->{ScannedTestScripts} ||= $self->_scan_test_scripts;
773             #
774             # return
775             # exists $self->{FilesInDir}->{$_}
776             # ? map
777             # $self->is_test_script
778             # ? $_
779             # : $self->test_scripts_for_file,
780             # @{$self->{FilesInDir}->{$_}}
781             # : ();
782             #}
783              
784              
785             =item test
786              
787             $self->test( @test_scripts );
788              
789             chdir()s to C<$self->dir> and Cs make test.
790              
791             =cut
792              
793             sub _esc {
794             map
795             m{[^\w./\\=:-]}
796 0 0   0     ? do {
797 0           local $_ = $_;
798 0           s/([\\'])/\\$1/g;
799 0           "'$_'";
800             }
801             : $_,
802             @_;
803             }
804              
805             sub call_config_handler {
806 0     0 0   my $self = shift;
807 0           my $handler = shift;
808              
809 0           my $sub = $self->{ConfigClass}->can( $handler );
810 0 0         return unless $sub;
811              
812 0           $sub->( $self, @_ );
813             }
814              
815              
816             sub test {
817 0     0 1   my $self = shift;
818              
819 0           my $cwd = Cwd::cwd;
820 0           my $d = $self->dir;
821 0 0         chdir $d or die "tv: $!: $d";
822              
823             ## TODO: an option to name the log file.
824 0 0         open LOG, ">tv.log" unless $self->{NoLog};
825              
826 0           $self->call_config_handler( "before_testing_do", @_ );
827              
828 0           $self->{PodChecks} = [];
829 0           $self->{CompileChecks} = [];
830 0           $self->{Unhandled} = [];
831              
832 0 0         my @scripts = @_ ? $self->test_scripts_for( @_ ) : ();
833              
834 0 0 0       if ( $self->{TestPOD} && @{$self->{PodChecks}} ) {
  0            
835             ## NOTE: not using $^X here because podchecker may be from a
836             ## newer perl. Could lead to unexpected behavior, but very, very
837             ## probably not.
838 0 0 0       warn "tv\$ podchecker ", join( " ", _esc @{$self->{PodChecks}} ), "\n"
  0            
839             if $self->{JustPrint} || !$self->{DoubleQuiet};
840             ## TODO: log the output of this
841 0 0 0       system "podchecker", @{$self->{PodChecks}}
  0            
842             and die "tv: POD checks failed, not running further tests.\n"
843             unless $self->{JustPrint};
844             }
845              
846 0 0 0       if ( $self->{Compile} && @{$self->{CompileChecks}} ) {
  0            
847 0           warn "tv\$ perl -Ilib -cw ",
848 0 0 0       join( " ", _esc @{$self->{CompileChecks}} ),
849             "\n"
850             if $self->{JustPrint} || !$self->{DoubleQuiet};
851              
852             ## TODO: log the output of this
853 0 0 0       system $^X, "-Ilib", "-cw", @{$self->{CompileChecks}}
  0            
854             and die "tv: compile test failed, not running further tests.\n"
855             unless $self->{JustPrint};
856             }
857              
858 0           $self->unhandled( @{$self->{Unhandled}} )
  0            
859 0 0         if @{$self->{Unhandled}};
860              
861 0 0 0       return 0 unless $self->{RunTests} && @scripts;
862              
863 0   0       my $debug = $self->{Debug} || $self->{DebugRun};
864              
865 0 0         my @cmds =
    0          
    0          
    0          
866             $debug
867             ? (
868             [ MAKE, "pm_to_blib" ],
869             map [ $^X, "-w", "-Iblib/lib", "-d", $_ ], @scripts
870             )
871             : $self->{PurePerl}
872             ? map [ $^X, "-w", "-Ilib", $_ ], @scripts
873             : $self->{ExtUtils}
874             ? [
875             $^X,
876             qw( -MExtUtils::Command::MM -e ),
877             "test_harness(1,'lib')",
878             @scripts
879             ]
880             : [ MAKE, qw( test TEST_VERBOSE=1 ),
881             @_
882             ? "TEST_FILES=" . join " ", @scripts
883             : (),
884             ];
885              
886 0   0       my $nonlazy_dyn_link = $self->{ExtUtils} || $debug;
887 0 0         local $ENV{PERL_DL_NONLAZY} = 1 if $nonlazy_dyn_link;
888              
889 0   0       my $db_opts = $ENV{PERLDB_OPTS} || "";
890 0 0         if ( $self->{DebugRun} ) {
891 0 0         $db_opts = " $db_opts" if length $db_opts;
892 0           $db_opts = "NonStop$db_opts";
893             }
894 0 0         local $ENV{PERLDB_OPTS} = $db_opts if length $db_opts;
895              
896 0 0         warn <{DebugRun};
897              
898             tv: ** Running in debug mode, use interrupt (often ^C), \$DB::single=1, **
899             tv: ** or rerun with -dd if you need to enter the debugger on startup. **
900              
901             TOHERE
902              
903 0           my @result_codes;
904              
905 0           for ( @cmds ) {
906 0           my $cmd = join " ", _esc @$_;
907              
908 0 0         $cmd = qq{PERL_DL_NONLAZY=1 $cmd} if $nonlazy_dyn_link;
909 0 0         $cmd = qq{PERLDB_OPTS="$db_opts" $cmd} if length $db_opts;
910              
911 0 0 0       warn "tv\$ $cmd\n"
912             if $self->{JustPrint} || !$self->{DoubleQuiet};
913              
914 0 0         next if $self->{JustPrint};
915              
916 0           require IPC::Open3;
917              
918             ## Collect both stderr and stdout in to one stream; don't
919             ## want select() and this lets the OS interleave output
920             ## better, I hope.
921 0           my $pid = IPC::Open3::open3( \*STDIN, my $out, undef, @$_ );
922 0 0         die "tv: $!: $cmd\n" unless defined $pid;
923              
924 0           my @out;
925             my $saw_lone_not;
926 0           my $last_ok_line = "";
927 0           my $saw_ok;
928 0           while ( <$out> ) {
929 0           print LOG;
930 0 0         print unless $self->{Quiet};
931 0 0         push @out, $_ if $self->{Quiet};
932              
933 0 0         $saw_lone_not = 1, next if /^not\s*$/;
934              
935 0           my ( $not, $ok, $what, $number, $why ) =
936             /\A((?:not\s+)?)(ok\b)\s*(\d*)(?:#\s*(\S+))?/;
937              
938 0 0         next unless $ok;
939              
940 0           $saw_ok = 1;
941              
942 0 0 0       if ( $ok
    0 0        
      0        
      0        
      0        
      0        
      0        
943             && ! $saw_lone_not
944             && ( ! $not || ( $why || "" ) =~ /TODO/i )
945             ) {
946 0           @out = ();
947             }
948             elsif (
949             $not || ( $saw_lone_not && $ok )
950             && $self->{Quiet}
951             && ! $self->{DoubleQuiet}
952             ) {
953 0 0 0       if ( defined $cmd && @cmds > 1 ) {
954 0 0         print $cmd, ":\n" if $self->{Quiet};
955 0           $cmd = undef;
956             }
957 0 0         print $saw_lone_not ? "not $_" : $_;
958             }
959 0           $saw_lone_not = 0;
960 0 0         $last_ok_line = ( $saw_lone_not ? "not " : "" ) . $_ if $ok;
    0          
961             }
962              
963             ## Emit the next bit even in DoubleQuiet mode; it's usually
964             ## the All tests sucessful. At least when I'm driving it ;).
965 0 0 0       if ( ! $self->{TripleQuiet} && @out ) {
966 0 0 0       if ( defined $cmd && @cmds > 1 ) {
967 0 0         print $cmd, ":\n" if $self->{DoubleQuiet};
968 0           $cmd = undef;
969             }
970             print
971 0 0         $saw_ok ? "tv: after last 'ok/not ok':\n" : $last_ok_line,
972             @out;
973             }
974              
975 0 0         waitpid $pid, 0 or warn "$! waiting on PID $pid";
976              
977 0           push @result_codes, $? >> 8;
978             }
979              
980 0           close LOG;
981              
982 0 0         (grep $_, @result_codes )[0] || 0;
983             }
984              
985             =back
986              
987             =head1 ASSumptions and LIMITATIONS
988              
989             =over
990              
991             =item *
992              
993             Test scripts with spaces in their filenames will screw up, since these
994             are interpolated in to a single, space delimited make(1) variable like so:
995              
996             make test TEST_VERBOSE=1 "TEST_FILES=t/spaced out name.t"
997              
998             =item *
999              
1000             Your make must be called "make". I will alter this assumption as soon
1001             as I need this on Win32 again. Feel free to submit patches.
1002              
1003             =item *
1004              
1005             Speaking of which, although this module has a nod to portability, it
1006             has not been tested on platforms other than Unix, so there be dragons
1007             there. They should be easy to fix, so please patch away.
1008              
1009             =item *
1010              
1011             The source code scanners look for /^\s*(use|require)\s+([\w:])/ (in test
1012             scripts) and /^\s*package\s+(\S+);/, and so are easily fooled.
1013              
1014             =back
1015              
1016             =cut
1017              
1018             =head1 COPYRIGHT
1019              
1020             Copyright 2002 R. Barrie Slaymaker, All Rights Reserver
1021              
1022             =head1 LICENSE
1023              
1024             You may use this module under the terms of the BSD, GNU, or Artistic
1025             licenses.
1026              
1027             =head1 AUTHOR
1028              
1029             Barrie Slaymaker
1030              
1031             =cut
1032              
1033             1;