1#!/usr/bin/perl -w
2
3use strict;
4
5use Test::Harness;
6use Getopt::Long;
7use Pod::Usage 1.12;
8use File::Spec;
9
10use vars qw( $VERSION );
11$VERSION = "1.04";
12
13my @ext = ();
14my $shuffle = 0;
15my $dry = 0;
16my $blib = 0;
17my $lib = 0;
18my $recurse = 0;
19my @includes = ();
20my @switches = ();
21
22# Allow cuddling the paths with the -I
23@ARGV = map { /^(-I)(.+)/ ? ($1,$2) : $_ } @ARGV;
24
25# Stick any default switches at the beginning, so they can be overridden
26# by the command line switches.
27unshift @ARGV, split( " ", $ENV{PROVE_SWITCHES} ) if defined $ENV{PROVE_SWITCHES};
28
29Getopt::Long::Configure( "no_ignore_case" );
30Getopt::Long::Configure( "bundling" );
31GetOptions(
32    'b|blib'        => \$blib,
33    'd|debug'	    => \$Test::Harness::debug,
34    'D|dry'         => \$dry,
35    'h|help|?'      => sub {pod2usage({-verbose => 1, -input => \*DATA}); exit},
36    'H|man'         => sub {pod2usage({-verbose => 2, -input => \*DATA}); exit},
37    'I=s@'          => \@includes,
38    'l|lib'	    => \$lib,
39    'r|recurse'     => \$recurse,
40    's|shuffle'     => \$shuffle,
41    't'		    => sub { unshift @switches, "-t" }, # Always want -t up front
42    'T'		    => sub { unshift @switches, "-T" }, # Always want -T up front
43    'v|verbose'     => \$Test::Harness::verbose,
44    'V|version'     => sub { print_version(); exit; },
45    'ext=s@'        => \@ext,
46) or exit 1;
47
48# Build up extensions regex
49@ext = map { split /,/ } @ext;
50s/^\.// foreach @ext;
51@ext = ("t") unless @ext;
52my $ext_regex = join( "|", map { quotemeta } @ext );
53$ext_regex = qr/\.($ext_regex)$/;
54
55# Handle blib includes
56if ( $blib ) {
57    my @blibdirs = blibdirs();
58    if ( @blibdirs ) {
59	unshift @includes, @blibdirs;
60    } else {
61	warn "No blib directories found.\n";
62    }
63}
64
65# Handle lib includes
66if ( $lib ) {
67    unshift @includes, "lib";
68}
69
70# Build up TH switches
71push( @switches, map { /\s/ && !/^".*"$/ ? qq["-I$_"] : "-I$_" } @includes );
72$Test::Harness::Switches = join( " ", @switches );
73print "# \$Test::Harness::Switches: $Test::Harness::Switches\n" if $Test::Harness::debug;
74
75my @tests;
76@ARGV = File::Spec->curdir unless @ARGV;
77push( @tests, -d $_ ? all_in( $_ ) : $_ ) for @ARGV;
78
79if ( @tests ) {
80    shuffle(@tests) if $shuffle;
81    if ( $dry ) {
82        print join( "\n", @tests, "" );
83    } else {
84	print "# ", scalar @tests, " tests to run\n" if $Test::Harness::debug;
85        runtests(@tests);
86    }
87}
88
89sub all_in {
90    my $start = shift;
91
92    my @hits = ();
93
94    local *DH;
95    if ( opendir( DH, $start ) ) {
96        while ( my $file = readdir DH ) {
97            next if $file eq File::Spec->updir || $file eq File::Spec->curdir;
98            next if $file eq ".svn";
99            next if $file eq "CVS";
100
101            my $currfile = File::Spec->catfile( $start, $file );
102            if ( -d $currfile ) {
103                push( @hits, all_in( $currfile ) ) if $recurse;
104            } else {
105                push( @hits, $currfile ) if $currfile =~ $ext_regex;
106            }
107        }
108    } else {
109        warn "$start: $!\n";
110    }
111
112    return @hits;
113}
114
115sub shuffle {
116    # Fisher-Yates shuffle
117    my $i = @_;
118    while ($i) {
119        my $j = rand $i--;
120        @_[$i, $j] = @_[$j, $i];
121    }
122}
123
124sub print_version {
125    printf( "prove v%s, using Test::Harness v%s and Perl v%vd\n",
126	$VERSION, $Test::Harness::VERSION, $^V );
127}
128
129# Stolen directly from blib.pm
130sub blibdirs {
131    my $dir = File::Spec->curdir;
132    if ($^O eq 'VMS') {
133	($dir = VMS::Filespec::unixify($dir)) =~ s-/\z--;
134    }
135    my $archdir = "arch";
136    if ( $^O eq "MacOS" ) {
137	# Double up the MP::A so that it's not used only once.
138	$archdir = $MacPerl::Architecture = $MacPerl::Architecture;
139    }
140
141    my $i = 5;
142    while ($i--) {
143        my $blib      = File::Spec->catdir( $dir, "blib" );
144        my $blib_lib  = File::Spec->catdir( $blib, "lib" );
145        my $blib_arch = File::Spec->catdir( $blib, $archdir );
146
147	if ( -d $blib && -d $blib_arch && -d $blib_lib ) {
148	    return ($blib_arch,$blib_lib);
149	}
150	$dir = File::Spec->catdir($dir, File::Spec->updir);
151    }
152    warn "$0: Cannot find blib\n";
153    return;
154}
155
156__END__
157
158=head1 NAME
159
160prove -- A command-line tool for running tests against Test::Harness
161
162=head1 SYNOPSIS
163
164prove [options] [files/directories]
165
166Options:
167
168    -b, --blib      Adds blib/lib to the path for your tests, a la "use blib".
169    -d, --debug	    Includes extra debugging information.
170    -D, --dry       Dry run: Show the tests to run, but don't run them.
171        --ext=x     Extensions (defaults to .t)
172    -h, --help      Display this help
173    -H, --man       Longer manpage for prove
174    -I              Add libraries to @INC, as Perl's -I
175    -l, --lib	    Add lib to the path for your tests.
176    -r, --recurse   Recursively descend into directories.
177    -s, --shuffle   Run the tests in a random order.
178    -T	 	    Enable tainting checks
179    -t		    Enable tainting warnings
180    -v, --verbose   Display standard output of test scripts while running them.
181    -V, --version   Display version info
182
183Single-character options may be stacked.  Default options may be set by
184specifying the PROVE_SWITCHES environment variable.
185
186=head1 OVERVIEW
187
188F<prove> is a command-line interface to the test-running functionality
189of C<Test::Harness>.  With no arguments, it will run all tests in the
190current directory.
191
192Shell metacharacters may be used with command lines options and will be exanded 
193via C<glob>.
194
195=head1 PROVE VS. "MAKE TEST"
196
197F<prove> has a number of advantages over C<make test> when doing development.
198
199=over 4
200
201=item * F<prove> is designed as a development tool
202
203Perl users typically run the test harness through a makefile via
204C<make test>.  That's fine for module distributions, but it's
205suboptimal for a test/code/debug development cycle.
206
207=item * F<prove> is granular 
208
209F<prove> lets your run against only the files you want to check.
210Running C<prove t/live/ t/master.t> checks every F<*.t> in F<t/live>,
211plus F<t/master.t>.
212
213=item * F<prove> has an easy verbose mode
214
215F<prove> has a C<-v> option to see the raw output from the tests.
216To do this with C<make test>, you must set C<HARNESS_VERBOSE=1> in
217the environment.
218
219=item * F<prove> can run under taint mode
220
221F<prove>'s C<-T> runs your tests under C<perl -T>, and C<-t> runs them
222under C<perl -t>.
223
224=item * F<prove> can shuffle tests
225
226You can use F<prove>'s C<--shuffle> option to try to excite problems
227that don't show up when tests are run in the same order every time.
228
229=item * F<prove> doesn't rely on a make tool
230
231Not everyone wants to write a makefile, or use L<ExtUtils::MakeMaker>
232to do so.  F<prove> has no external dependencies.
233
234=item * Not everything is a module
235
236More and more users are using Perl's testing tools outside the
237context of a module distribution, and may not even use a makefile
238at all.
239
240=back
241
242=head1 COMMAND LINE OPTIONS
243
244=head2 -b, --blib
245
246Adds blib/lib to the path for your tests, a la "use blib".
247
248=head2 -d, --debug
249
250Include debug information about how F<prove> is being run.  This
251option doesn't show the output from the test scripts.  That's handled
252by -v,--verbose.
253
254=head2 -D, --dry
255
256Dry run: Show the tests to run, but don't run them.
257
258=head2 --ext=extension
259
260Specify extensions of the test files to run.  By default, these are .t,
261but you may have other non-.t test files, most likely .sh shell scripts.
262The --ext is repeatable.
263
264=head2 -I
265
266Add libraries to @INC, as Perl's -I.
267
268=head2 -l, --lib
269
270Add C<lib> to @INC.  Equivalent to C<-Ilib>.
271
272=head2 -r, --recurse
273
274Descends into subdirectories of any directories specified, looking for tests.
275
276=head2 -s, --shuffle
277
278Sometimes tests are accidentally dependent on tests that have been
279run before.  This switch will shuffle the tests to be run prior to
280running them, thus ensuring that hidden dependencies in the test
281order are likely to be revealed.  The author hopes the run the
282algorithm on the preceding sentence to see if he can produce something
283slightly less awkward.
284
285=head2 -t
286
287Runs test programs under perl's -t taint warning mode.
288
289=head2 -T
290
291Runs test programs under perl's -T taint mode.
292
293=head2 -v, --verbose
294
295Display standard output of test scripts while running them.
296
297=head2 -V, --version
298
299Display version info.
300
301=head1 BUGS
302
303Please use the CPAN bug ticketing system at L<http://rt.cpan.org/>.
304You can also mail bugs, fixes and enhancements to 
305C<< <bug-test-harness@rt.cpan.org> >>.
306
307=head1 TODO
308
309=over 4
310
311=item *
312
313Shuffled tests must be recreatable
314
315=back
316
317=head1 AUTHORS
318
319Andy Lester C<< <andy@petdance.com> >>
320
321=head1 COPYRIGHT
322
323Copyright 2003 by Andy Lester C<< <andy@petdance.com> >>.
324
325This program is free software; you can redistribute it and/or 
326modify it under the same terms as Perl itself.
327
328See L<http://www.perl.com/perl/misc/Artistic.html>.
329
330=cut
331