File Coverage

blib/lib/Test/Run/CmdLine/Prove.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Test::Run::CmdLine::Prove;
2              
3 1     1   26380 use strict;
  1         3  
  1         42  
4 1     1   6 use warnings;
  1         2  
  1         30  
5              
6 1     1   1810 use Moose;
  0            
  0            
7              
8             with 'MooseX::Getopt::Basic';
9              
10             has 'dry' => (
11             traits => ['Getopt'], is => "rw",
12             isa => "Bool", cmd_aliases => [qw(D)],
13             );
14              
15             has '_ext_regex' => (accessor => "ext_regex", is => "rw", isa => "RegexpRef");
16             has '_ext_regex_string' =>
17             (accessor => "ext_regex_string", is => "rw", isa => "Str")
18             ;
19             has 'recurse' => (traits => ['Getopt'], is => "rw",
20             isa => "Bool", cmd_aliases => [qw(r)],
21             );
22             has 'shuffle' => (
23             traits => ['Getopt'], is => "rw",
24             isa => "Bool", cmd_aliases => [qw(s)],
25             );
26             has 'Verbose' => (
27             traits => ['Getopt'], is => "rw",
28             isa => "Bool", cmd_aliases => [qw(v)],
29             );
30             has 'Debug' => (
31             traits => ['Getopt'], is => "rw",
32             isa => "Bool", cmd_aliases => [qw(d)],
33             );
34              
35             has '_Switches' => (accessor => "Switches", is => "rw", isa => "ArrayRef");
36             has 'Test_Interpreter' => (
37             traits => ['Getopt'], is => "rw",
38             isa => "Str", cmd_aliases => [qw(perl)],
39             );
40             has 'Timer' => (
41             traits => ['Getopt'], is => "rw",
42             isa => "Bool",
43             cmd_aliases => [qw(timer)],
44             );
45             has 'proto_includes' => (
46             traits => ['Getopt'],
47             is => "rw", isa => "ArrayRef",
48             cmd_aliases => [qw(I)],
49             default => sub { return []; },
50             );
51             has 'blib' => (
52             traits => ['Getopt'], is => "rw",
53             isa => "Bool", cmd_aliases => [qw(b)],
54             );
55              
56             has 'lib' => (
57             traits => ['Getopt'], is => "rw",
58             isa => "Bool", cmd_aliases => [qw(l)],
59             );
60              
61             has 'taint' => (
62             traits => ['Getopt'], is => "rw",
63             isa => "Bool", cmd_aliases => [qw(t)],
64             );
65              
66             has 'uc_taint' => (
67             traits => ['Getopt'], is => "rw",
68             isa => "Bool", cmd_aliases => [qw(T)],
69             );
70              
71             has 'help' => (
72             traits => ['Getopt'], is => "rw",
73             isa => "Bool", cmd_aliases => [qw(h ?)],
74             );
75              
76             has 'man' => (
77             traits => ['Getopt'], is => "rw",
78             isa => "Bool", cmd_aliases => [qw(H)],
79             );
80              
81             has 'version' => (
82             traits => ['Getopt'], is => "rw",
83             isa => "Bool", cmd_aliases => [qw(V)],
84             );
85              
86             has 'ext' => (
87             is => "rw", isa => "ArrayRef",
88             default => sub { return []; },
89             );
90              
91             use MRO::Compat;
92              
93             use Test::Run::CmdLine::Iface;
94             use Getopt::Long;
95             use Pod::Usage 1.12;
96             use File::Spec;
97              
98             use vars qw($VERSION);
99             $VERSION = '0.0126';
100              
101              
102             =head1 NAME
103              
104             Test::Run::CmdLine::Prove - A Module for running tests from the command line
105              
106             =head1 SYNOPSIS
107              
108             use Test::Run::CmdLine::Prove;
109              
110             my $tester = Test::Run::CmdLine::Prove->new({'args' => [@ARGV]});
111              
112             $tester->run();
113              
114             =cut
115              
116             =begin removed_code
117              
118             around '_parse_argv' => sub {
119             my $orig = shift;
120             my $self = shift;
121              
122             my %params = $self->$orig(@_);
123             delete($params{'usage'});
124             return %params;
125             };
126              
127             =end removed_code
128              
129             =cut
130              
131             sub create
132             {
133             my $class = shift;
134             my $args = shift;
135              
136             my @argv = @{$args->{'args'}};
137             my $env_switches = $args->{'env_switches'};
138              
139             if (defined($env_switches))
140             {
141             unshift @argv, split(" ", $env_switches);
142             }
143              
144             Getopt::Long::Configure( "no_ignore_case" );
145             Getopt::Long::Configure( "bundling" );
146              
147             my $self;
148             {
149             # Temporary workaround for MooseX::Getopt;
150             local @ARGV = @argv;
151             $self = $class->new_with_options(
152             argv => \@argv,
153             "no_ignore_case" => 1,
154             "bundling" => 1,
155             );
156             }
157              
158             $self->_initial_process($args);
159              
160             return $self;
161             }
162              
163             sub _initial_process
164             {
165             my ($self, $args) = @_;
166              
167             $self->maybe::next::method($args);
168              
169             my @switches = ();
170              
171             if ($self->version())
172             {
173             $self->_print_version();
174             exit(0);
175             }
176              
177             if ($self->help())
178             {
179             $self->_usage(1);
180             }
181              
182             if ($self->man())
183             {
184             $self->_usage(2);
185             }
186              
187             if ($self->taint())
188             {
189             unshift @switches, "-t";
190             }
191              
192             if ($self->uc_taint())
193             {
194             unshift @switches, "-T";
195             }
196              
197             my @includes = @{$self->proto_includes()};
198              
199             if ($self->blib())
200             {
201             unshift @includes, ($self->_blibdirs());
202             }
203              
204             # Handle the lib include path
205             if ($self->lib())
206             {
207             unshift @includes, "lib";
208             }
209              
210             $self->proto_includes(\@includes);
211              
212             push @switches, (map { $self->_include_map($_) } @includes);
213              
214             $self->Switches(\@switches);
215              
216             $self->_set_ext([ @{$self->ext()} ]);
217              
218             return 0;
219             }
220              
221             sub _include_map
222             {
223             my $self = shift;
224             my $arg = shift;
225             my $ret = "-I$arg";
226             if (($arg =~ /\s/) &&
227             (! (($arg =~ /^"/) && ($arg =~ /"$/)) )
228             )
229             {
230             return "\"$ret\"";
231             }
232             else
233             {
234             return $ret;
235             }
236             }
237              
238             sub _print_version
239             {
240             my $self = shift;
241             printf("runprove v%s, using Test::Run v%s, Test::Run::CmdLine v%s and Perl v%s\n",
242             $VERSION,
243             $Test::Run::Obj::VERSION,
244             $Test::Run::CmdLine::VERSION,
245             $^V
246             );
247             }
248              
249             =head1 Interface Functions
250              
251             =head2 $prove = Test::Run::CmdLine::Prove->create({'args' => [@ARGV], 'env_switches' => $env_switches});
252              
253             Initializes a new object. C<'args'> is a keyed parameter that gives the
254             command line for the prove utility (as an array ref of strings).
255              
256             C<'env_switches'> is a keyed parameter that gives a string containing more
257             arguments, or undef if not wanted.
258              
259             =head2 $prove->run()
260              
261             Runs the tests.
262              
263             =cut
264              
265             sub run
266             {
267             my $self = shift;
268              
269             my $tests = $self->_get_test_files();
270              
271             if ($self->_should_run_tests($tests))
272             {
273             return $self->_actual_run_tests($tests);
274             }
275             else
276             {
277             return $self->_dont_run_tests($tests);
278             }
279             }
280              
281             sub _should_run_tests
282             {
283             my ($self, $tests) = @_;
284              
285             return scalar(@$tests);
286             }
287              
288             sub _actual_run_tests
289             {
290             my ($self, $tests) = @_;
291              
292             my $method = $self->dry() ? "_dry_run" : "_wet_run";
293              
294             return $self->$method($tests);
295             }
296              
297             sub _dont_run_tests
298             {
299             return 0;
300             }
301              
302             sub _wet_run
303             {
304             my $self = shift;
305             my $tests = shift;
306              
307             my $test_run =
308             Test::Run::CmdLine::Iface->new(
309             {
310             'test_files' => [@$tests],
311             'backend_params' => $self->_get_backend_params(),
312             }
313             );
314              
315             return $test_run->run();
316             }
317              
318             sub _dry_run
319             {
320             my $self = shift;
321             my $tests = shift;
322             print join("\n", @$tests, "");
323             return 0;
324             }
325              
326             # Stolen directly from blib.pm
327             sub _blibdirs {
328             my $self = shift;
329             my $dir = File::Spec->curdir;
330             if ($^O eq 'VMS') {
331             ($dir = VMS::Filespec::unixify($dir)) =~ s-/\z--;
332             }
333             my $archdir = "arch";
334             if ( $^O eq "MacOS" ) {
335             # Double up the MP::A so that it's not used only once.
336             $archdir = $MacPerl::Architecture = $MacPerl::Architecture;
337             }
338              
339             my $i = 5;
340             while ($i--) {
341             my $blib = File::Spec->catdir( $dir, "blib" );
342             my $blib_lib = File::Spec->catdir( $blib, "lib" );
343             my $blib_arch = File::Spec->catdir( $blib, $archdir );
344              
345             if ( -d $blib && -d $blib_arch && -d $blib_lib ) {
346             return ($blib_arch,$blib_lib);
347             }
348             $dir = File::Spec->catdir($dir, File::Spec->updir);
349             }
350             warn "Could not find blib dirs";
351             return;
352             }
353              
354             sub _get_backend_params_keys
355             {
356             return [qw(Verbose Debug Timer Test_Interpreter Switches)];
357             }
358              
359             sub _get_backend_params
360             {
361             my $self = shift;
362             my $ret = +{};
363             foreach my $key (@{$self->_get_backend_params_keys()})
364             {
365             my $value = $self->$key();
366             if (ref($value) eq "ARRAY")
367             {
368             $ret->{$key} = join(" ", @$value);
369             }
370             else
371             {
372             if (defined($value))
373             {
374             $ret->{$key} = $value;
375             }
376             }
377             }
378             return $ret;
379             }
380              
381             sub _usage
382             {
383             my $self = shift;
384             my $verbosity = shift;
385              
386             Pod::Usage::pod2usage(
387             {
388             '-verbose' => $verbosity,
389             '-exitval' => 0,
390             }
391             );
392              
393             return;
394             }
395              
396             sub _default_ext
397             {
398             my $self = shift;
399             my $ext = shift;
400             return (@$ext ? $ext : ["t"]);
401             }
402              
403             sub _normalize_extensions
404             {
405             my $self = shift;
406              
407             my $ext = shift;
408             $ext = [ map { split(/,/, $_) } @$ext ];
409             foreach my $e (@$ext)
410             {
411             $e =~ s{^\.}{};
412             }
413             return $ext;
414             }
415              
416             sub _set_ext
417             {
418             my $self = shift;
419             my $ext = $self->_default_ext(shift);
420              
421             $self->ext_regex_string('\.(?:' .
422             join("|", map { quotemeta($_) }
423             @{$self->_normalize_extensions($ext)}
424             )
425             . ')$'
426             );
427             $self->_set_ext_re();
428             }
429              
430             sub _set_ext_re
431             {
432             my $self = shift;
433             my $s = $self->ext_regex_string();
434             $self->ext_regex(qr/$s/);
435             }
436              
437             sub _post_process_test_files_list
438             {
439             my ($self, $list) = @_;
440             if ($self->shuffle())
441             {
442             return $self->_perform_shuffle($list);
443             }
444             else
445             {
446             return $list;
447             }
448             }
449              
450             sub _perform_shuffle
451             {
452             my ($self, $list) = @_;
453             my @ret = @$list;
454             my $i = @ret;
455             while ($i)
456             {
457             my $place = int(rand($i--));
458             @ret[$i,$place] = @ret[$place, $i];
459             }
460             return \@ret;
461             }
462              
463             sub _get_arguments
464             {
465             my $self = shift;
466             my $args = $self->extra_argv();
467             if (defined($args) && @$args)
468             {
469             return $args;
470             }
471             else
472             {
473             return [ File::Spec->curdir() ];
474             }
475             }
476              
477             sub _get_test_files
478             {
479             my $self = shift;
480             return
481             $self->_post_process_test_files_list(
482             [
483             map
484             { $self->_get_test_files_from_arg($_) }
485             @{$self->_get_arguments()}
486             ]
487             );
488             }
489              
490             sub _get_test_files_from_arg
491             {
492             my ($self, $arg) = @_;
493             return (map { $self->_get_test_files_from_globbed_entry($_) } glob($arg));
494             }
495              
496             sub _get_test_files_from_globbed_entry
497             {
498             my ($self, $entry) = @_;
499             if (-d $entry)
500             {
501             return $self->_get_test_files_from_dir($entry);
502             }
503             else
504             {
505             return $self->_get_test_files_from_file($entry);
506             }
507             }
508              
509             sub _get_test_files_from_file
510             {
511             my ($self, $entry) = @_;
512             return ($entry);
513             }
514              
515             sub _get_test_files_from_dir
516             {
517             my ($self, $path) = @_;
518             if (opendir my $dir, $path)
519             {
520             my @files = sort readdir($dir);
521             closedir($dir);
522             return
523             (map { $self->_get_test_files_from_dir_entry($path, $_) } @files);
524             }
525             else
526             {
527             warn "$path: $!\n";
528             return ();
529             }
530             }
531              
532             sub _should_ignore_dir_entry
533             {
534             my ($self, $dir, $file) = @_;
535             return
536             (
537             ($file eq File::Spec->updir()) ||
538             ($file eq File::Spec->curdir()) ||
539             ($file eq ".svn") ||
540             ($file eq "CVS")
541             );
542             }
543              
544             sub _get_test_files_from_dir_entry
545             {
546             my ($self, $dir, $file) = @_;
547             if ($self->_should_ignore_dir_entry($dir, $file))
548             {
549             return ();
550             }
551             my $path = File::Spec->catfile($dir, $file);
552             if (-d $path)
553             {
554             return $self->_get_test_files_from_dir_path($path);
555             }
556             else
557             {
558             return $self->_get_test_files_from_file_path($path);
559             }
560             }
561              
562             sub _get_test_files_from_dir_path
563             {
564             my ($self, $path) = @_;
565             if ($self->recurse())
566             {
567             return $self->_get_test_files_from_dir($path);
568             }
569             else
570             {
571             return ();
572             }
573             }
574              
575             sub _get_test_files_from_file_path
576             {
577             my ($self, $path) = @_;
578             if ($path =~ $self->ext_regex())
579             {
580             return ($path);
581             }
582             else
583             {
584             return ();
585             }
586             }
587              
588             =head1 AUTHOR
589              
590             Shlomi Fish, C<< <shlomif@iglu.org.il> >>
591              
592             =head1 BUGS
593              
594             Please report any bugs or feature requests to
595             C<bug-test-run-cmdline@rt.cpan.org>, or through the web interface at
596             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-Run-CmdLine>.
597             I will be notified, and then you'll automatically be notified of progress on
598             your bug as I make changes.
599              
600             =head1 ACKNOWLEDGEMENTS
601              
602             =head1 COPYRIGHT & LICENSE
603              
604             Copyright 2005 Shlomi Fish, all rights reserved.
605              
606             This program is released under the MIT X11 License.
607              
608             =cut
609              
610             1;