File Coverage

blib/lib/Test/Smoke/Smoker.pm
Criterion Covered Total %
statement 206 591 34.8
branch 69 316 21.8
condition 12 81 14.8
subroutine 21 47 44.6
pod 22 22 100.0
total 330 1057 31.2


line stmt bran cond sub pod time code
1             package Test::Smoke::Smoker;
2 11     11   1287 use warnings;
  11         25  
  11         469  
3 11     11   60 use strict;
  11         22  
  11         537  
4              
5             our $VERSION = '0.046';
6              
7 11     11   82 use Config;
  11         21  
  11         524  
8 11     11   56 use Cwd;
  11         29  
  11         796  
9 11     11   103 use File::Spec::Functions qw( :DEFAULT abs2rel rel2abs );
  11         23  
  11         2223  
10 11     11   6108 use Capture::Tiny 'capture';
  11         217257  
  11         671  
11 11     11   84 use Test::Smoke::LogMixin;
  11         24  
  11         624  
12 11     11   64 use Test::Smoke::Util qw( get_smoked_Config skip_filter );
  11         65  
  11         478  
13              
14 11     11   638 BEGIN { eval q{ use Time::HiRes qw( time ) } }
  11     11   78  
  11         62  
  11         56  
15             { my $_orig_dft = select(STDERR); $|++; select(STDOUT); $|++; select($_orig_dft); $|++ }
16              
17             my %CONFIG = (
18             df_ddir => curdir(),
19             df_v => 0,
20             df_run => 1,
21             df_fdir => undef,
22             df_is56x => 0,
23             df_locale => '',
24             df_force_c_locale => 0,
25             df_defaultenv => 0,
26             df_harness_destruct => 2,
27              
28             df_is_vms => $^O eq 'VMS',
29             df_vmsmake => 'MMK',
30             df_harnessonly => scalar ($^O =~ /VMS/),
31             df_hasharness3 => 0,
32             df_harness3opts => '',
33              
34             df_is_win32 => $^O eq 'MSWin32',
35             df_w32cc => 'MSVC60',
36             df_w32make => 'nmake',
37             df_w32args => [ ],
38              
39             df_makeopt => "",
40             df_testmake => undef,
41              
42             df_skip_tests => undef,
43             );
44              
45             # Define some constants that we can use for
46             # specifying how far "make" got.
47             sub BUILD_MINIPERL() { -1 } # but no perl
48             sub BUILD_PERL () { 1 } # ok
49             sub BUILD_NOTHING () { 0 } # not ok
50              
51             sub HARNESS_RE1 () {
52             '(\S+\.t)(?:\s+[\d?]+){0,4}(?:\s+[\d?.]*%)?\s+([\d?]+(?:[-\s]+\d+-?)*)$'
53             }
54             sub HARNESS_RE2() { '^\s+(\d+(?:[-\s]+\d+)*-?)$' }
55              
56              
57             sub HARNESS3_RE_EXTRA() {
58             '^\s+(\d[0-9, -]*)'
59             }
60              
61             sub HARNESS3_RE_FAILED() {
62             '^(?:
63             (?:\ \ Failed\ tests?(?:\ number\(s\))?:\ \ )
64             )
65             (\d[0-9, -]*)'
66             }
67              
68             sub HARNESS3_RE_TODO() {
69             '^(?:
70             (?:\ \ TODO\ passed(?:\ number\(s\))?:\ \ \ )
71             )
72             (\d[0-9, -]*)'
73             }
74              
75              
76             =head1 NAME
77              
78             Test::Smoke::Smoker - OO interface to do one smoke cycle.
79              
80             =head1 SYNOPSIS
81              
82             use Test::Smoke;
83             use Test::Smoke::Smoker;
84              
85             open LOGFILE, "> mktest.out" or die "Cannot create 'mktest.out': $!";
86             my $buildcfg = Test::SmokeBuildCFG->new( $conf->{cfg} );
87             my $policy = Test::Smoke::Policy->new( '../', $conf->{v} );
88             my $smoker = Test::Smoke::Smoker->new( \*LOGFILE, $conf );
89              
90             foreach my $config ( $buildcfg->configurations ) {
91             $smoker->smoke( $config, $policy );
92             }
93              
94             =head1 DESCRIPTION
95              
96             The Test::Smoke::Smoker module, an OO interface to do one smoke cycle.
97              
98             =head1 CONSTANTS
99              
100             =over
101              
102             =item BUILD_MINIPERL
103              
104             =item BUILD_NOTHING
105              
106             =item BUILD_PERL
107              
108             =item HARNESS3_RE_EXTRA
109              
110             =item HARNESS3_RE_FAILED
111              
112             =item HARNESS3_RE_TODO
113              
114             =item HARNESS_RE1
115              
116             =item HARNESS_RE2
117              
118             =back
119              
120             =head1 METHODS
121              
122             =head2 Test::Smoke::Smoker->new( \*GLOB, %args )
123              
124             C takes a mandatory (opened) filehandle and some other options:
125              
126             ddir build directory
127             fdir The forest source
128             v verbose level: 0..2
129             defaultenv 'make test' without $ENV{PERLIO}
130             is56x skip the PerlIO stuff?
131             locale do another testrun with $ENV{LC_ALL}
132             force_c_locale set $ENV{LC_ALL} = 'C' for all smoke runs
133              
134             is_win32 is this MSWin32?
135             w32cc the CCTYPE for MSWin32 (MSVCxx BORLAND GCC)
136             w32make the maker to use for CCTYPE
137              
138             =cut
139              
140             sub new {
141 20     20 1 34147 my $proto = shift;
142 20   33     129 my $class = ref $proto || $proto;
143              
144 20         43 my $fh = shift;
145              
146 20 50       68 unless ( ref $fh eq 'GLOB' ) {
147 0         0 require Carp;
148 0         0 Carp::croak(sprintf "Usage: %s->new( \\*FH, %%args )", __PACKAGE__);
149             }
150              
151 20 50       175 my %args_raw = @_ ? UNIVERSAL::isa( $_[0], 'HASH' ) ? %{ $_[0] } : @_ : ();
  0 50       0  
152              
153             my %args = map {
154 20         67 ( my $key = $_ ) =~ s/^-?(.+)$/lc $1/e;
  28         204  
  28         125  
155 28         128 ( $key => $args_raw{ $_ } );
156             } keys %args_raw;
157              
158             my %fields = map {
159 420 100       880 my $value = exists $args{$_} ? $args{ $_ } : $CONFIG{ "df_$_" };
160 420         709 ( $_ => $value )
161 20         40 } keys %{ Test::Smoke::Smoker->config( 'all_defaults' ) };
  20         67  
162              
163 20         113 $fields{logfh} = $fh;
164 20         151 select( ( select( $fh ), $|++ )[0] );
165 20 50       55 $fields{defaultenv} = 1 if $fields{is56x};
166 20 50       92 $^O =~ /VMS/i and $fields{is_vms} = 1;
167              
168 20 100       48 unless ( defined $fields{testmake} ) {
169 18         42 $fields{testmake} = 'make';
170 18 50       47 $fields{is_win32} and $fields{testmake} = $fields{w32make};
171 18 50       41 $fields{is_vms} and $fields{testmake} = $fields{vmsmake};
172             }
173 20         202 my $self = bless { %fields }, $class;
174              
175 20         150 return $self;
176             }
177              
178             =head2 $smoker->verbose
179              
180             Get verbosity.
181              
182             =cut
183              
184 332     332 1 1025 sub verbose { $_[0]->{v} }
185              
186             =head2 $smoker->mark_in()
187              
188             Write the current timestamp with 'Start' marker to the logfile.
189              
190             =cut
191              
192             sub mark_in {
193 0     0 1 0 my $self = shift;
194 0         0 $self->log( sprintf "Started smoke at %d\n", time() );
195             }
196              
197             =head2 $smoker->mark_out()
198              
199             Write the current timestamp with 'Stopped' marker to the logfile.
200              
201             =cut
202              
203             sub mark_out {
204 0     0 1 0 my $self = shift;
205 0         0 $self->log( sprintf "Stopped smoke at %d\n", time() );
206             }
207              
208             =head2 Test::Smoke::Smoker->config( $key[, $value] )
209              
210             C is an interface to the package lexical C<%CONFIG>,
211             which holds all the default values for the C arguments.
212              
213             With the special key B this returns a reference
214             to a hash holding all the default values.
215              
216             =cut
217              
218             sub config {
219 38     38 1 564 my $dummy = shift;
220              
221 38         73 my $key = lc shift;
222              
223 38 100       80 if ( $key eq 'all_defaults' ) {
224             my %default = map {
225 21         321 my( $pass_key ) = $_ =~ /^df_(.+)/;
  441         1062  
226 441         1051 ( $pass_key => $CONFIG{ $_ } );
227             } grep /^df_/ => keys %CONFIG;
228 21         165 return \%default;
229             }
230              
231 17 50       42 return undef unless exists $CONFIG{ "df_$key" };
232              
233 17 50       27 $CONFIG{ "df_$key" } = shift if @_;
234              
235 17         35 return $CONFIG{ "df_$key" };
236             }
237              
238             =head2 $smoker->tty( $message )
239              
240             Prints a message to the default filehandle.
241              
242             =cut
243              
244             sub tty {
245 0     0 1 0 my $self = shift;
246 0         0 my $message = join "", @_;
247 0         0 $self->log_warn($message);
248             }
249              
250             =head2 $smoker->log( $message )
251              
252             Prints a message to the logfile, filehandle.
253              
254             =cut
255              
256             sub log {
257 0     0 1 0 my $self = shift;
258 0         0 my $message = join "", @_;
259 0         0 print { $self->{logfh} } $message;
  0         0  
260             }
261              
262             =head2 $smoker->ttylog( $message )
263              
264             Prints a message to both the default and the logfile filehandles.
265              
266             =cut
267              
268             sub ttylog {
269 0     0 1 0 my $self = shift;
270 0         0 $self->log( @_ );
271 0         0 $self->tty( @_ );
272             }
273              
274             =head2 $smoker->smoke( $config[, $policy] )
275              
276             C takes a B object and runs all
277             the basic steps as (private) object methods.
278              
279             =cut
280              
281             sub smoke {
282 0     0 1 0 my( $self, $config, $policy ) = @_;
283              
284 0 0       0 $self->{is_vms} and $self->_vms_rooted_logical;
285              
286 0         0 $self->make_distclean;
287              
288 0 0       0 $self->{v} > 1 and $self->extra_manicheck;
289              
290 0         0 $self->handle_policy( $policy, $config->policy );
291              
292 0         0 my $c_result = $self->Configure( $config );
293             # Log the compiler info now, the last config could fail
294             { # can we config.sh without Configure success?
295 0         0 my %cinfo = get_smoked_Config( $self->{ddir} => qw(
  0         0  
296             cc ccversion gccversion
297             ));
298 0   0     0 my $version = $cinfo{gccversion} || $cinfo{ccversion};
299             $self->log( "\nCompiler info: $cinfo{cc} version $version\n" )
300 0 0       0 if $cinfo{cc};
301             }
302              
303 0 0       0 $c_result or do {
304 0         0 $self->ttylog( "Unable to configure perl in this configuration\n" );
305 0         0 return 0;
306             };
307              
308 0         0 my %sconf = get_smoked_Config( $self->{ddir} => 'ldlibpthname' );
309 0 0       0 exists $sconf{ldlibpthname} or $sconf{ldlibpthname} = "";
310             $sconf{ldlibpthname} and
311             local $ENV{ $sconf{ldlibpthname} } = $ENV{ $sconf{ldlibpthname} } || '',
312 0 0 0     0 substr( $ENV{ $sconf{ldlibpthname} }, 0, 0) =
313             "$self->{ddir}$Config{path_sep}";
314              
315 0         0 my $build_stat = $self->make_( $config );
316              
317 0 0       0 $build_stat == BUILD_MINIPERL and do {
318 0         0 $self->ttylog( "Unable to make anything but miniperl",
319             " in this configuration\n" );
320 0         0 return $self->make_minitest;
321             };
322              
323 0 0       0 $build_stat == BUILD_NOTHING and do {
324 0         0 $self->ttylog( "Unable to make perl in this configuration\n" );
325 0         0 return 0;
326             };
327              
328 0 0       0 $self->make_test_prep or do {
329 0         0 $self->ttylog( "Unable to test perl in this configuration\n" );
330 0         0 return 0;
331             };
332              
333 0         0 $self->make_test( $config );
334              
335             # $self->{is_vms} and $self->_unset_rooted_logical;
336 0         0 return 1;
337             }
338              
339             =head2 $smoker->make_distclean( )
340              
341             C runs C<< make -i distclean 2>/dev/null >>
342              
343             =cut
344              
345             sub make_distclean {
346 0     0 1 0 my $self = shift;
347              
348 0         0 $self->tty( "make distclean ..." );
349 0 0 0     0 if ( $self->{fdir} && -d $self->{fdir} ) {
350 0         0 require Test::Smoke::Syncer;
351             my %options = (
352             hdir => $self->{fdir},
353 0         0 ddir => cwd(),
354             v => 0,
355             );
356 0         0 my $distclean = Test::Smoke::Syncer->new( hardlink => %options );
357 0         0 $distclean->clean_from_directory( $self->{fdir}, 'mktest.out' );
358             } else {
359 0 0       0 my $target = $self->{is_vms} ? 'realclean' : '-i distclean';
360 0         0 $self->_make( "$target 2>/dev/null" );
361             }
362             }
363              
364             =head2 $smoker->extra_manicheck( )
365              
366             C will only work for C<< $self->{v} > 1 >> and does
367             an extra integrity check comparing F and the
368             source-tree. Output is send to the tty.
369              
370             =cut
371              
372             sub extra_manicheck {
373 0     0 1 0 my $self = shift;
374 0 0       0 $self->{v} > 1 or return;
375              
376 0         0 require Test::Smoke::SourceTree;
377 0         0 Test::Smoke::SourceTree->import( qw( :mani_const ) );
378 0         0 my $tree = Test::Smoke::SourceTree->new( $self->{ddir} );
379 0         0 my $mani_check = $tree->check_MANIFEST(qw( mktest.out mktest.rpt ));
380 0         0 foreach my $file ( sort keys %$mani_check ) {
381 0 0       0 if ( $mani_check->{ $file } == ST_MISSING() ) {
    0          
382 0         0 $self->tty( "manicheck: missing '$file' (not in source-tree)\n" );
383             } elsif ( $mani_check->{ $file } == ST_UNDECLARED() ) {
384 0         0 $self->tty( "manicheck: extra '$file' (not in MANIFEST)\n" );
385             }
386             }
387             }
388              
389             =head2 $smoker->handle_policy( $policy, @substs );
390              
391             C will try to apply the substition rules and then
392             write the file F.
393              
394             =cut
395              
396             sub handle_policy {
397 0     0 1 0 my $self = shift;
398 0         0 my( $policy, @substs ) = @_;
399              
400 0 0       0 return unless UNIVERSAL::isa( $policy, 'Test::Smoke::Policy' );
401              
402 0         0 $self->tty( "\nCopy Policy.sh ..." );
403 0         0 $policy->reset_rules;
404 0 0       0 if ( @substs ) {
405 0         0 $policy->set_rules( $_ ) foreach @substs;
406             }
407 0         0 $policy->write;
408             }
409              
410             =head2 $smoker->Configure( $config )
411              
412             C sorts out the MSWin32 mess and calls F<./Configure>
413              
414             returns true if a makefile was created
415              
416             =cut
417              
418             sub Configure {
419 0     0 1 0 my $self = shift;
420 0         0 my( $config, $policy ) = @_;
421              
422 0         0 $self->tty( "\nConfigure ..." );
423 0         0 my $makefile = '';
424 0 0       0 if ( $self->{is_win32} ) {
    0          
425 0         0 my @w32args = @{ $self->{w32args} };
  0         0  
426 0         0 @w32args = @w32args[ 4 .. $#w32args ];
427 0 0       0 my $w32_cfg = "$config" =~ /-DCCTYPE=/
428             ? "$config" : "$config -DCCTYPE=$self->{w32cc}";
429              
430             $makefile = $self->_run( "./Configure $w32_cfg",
431             \&Test::Smoke::Util::Configure_win32,
432 0         0 $self->{w32make}, @w32args );
433             } elsif ( $self->{is_vms} ) {
434 0         0 my $vms_cfg = $config->vms;
435 0         0 $self->_run( qq/\@configure -"des" $vms_cfg/ );
436 0         0 $makefile = 'DESCRIP.MMS';
437             } else {
438 0         0 $self->_run( "./Configure -des $config" );
439 0         0 $makefile = 'Makefile';
440             }
441 0         0 return -f $makefile;
442             }
443              
444             =head2 $smoker->make_( )
445              
446             C will run make.
447              
448             returns true if a perl executable is found
449              
450             =cut
451              
452             sub make_ {
453 0     0 1 0 my $self = shift;
454 0         0 my $config = shift;
455              
456 0         0 $self->tty( "\nmake ..." );
457 0         0 my $make_args = "";
458 0 0 0     0 $self->{is_vms} && $config->has_arg( '-Dusevmsdebug' ) and
459             $make_args = qq[/macro=("__DEBUG__=1")];
460              
461 0 0 0     0 $self->{is_win32} && $config->has_arg( '-Uuseshrplib' ) and
462             $make_args = "static";
463              
464 0         0 my $make_output = $self->_make( $make_args );
465              
466 0 0       0 if ( $self->{is_win32} ) { # Win32 creates config.sh during make
467 0         0 my %cinfo = get_smoked_Config( $self->{ddir} => qw(
468             cc ccversion gccversion
469             ));
470 0   0     0 my $version = $cinfo{gccversion} || $cinfo{ccversion};
471             $self->log( "\nCompiler info: $cinfo{cc} version $version\n" )
472 0 0       0 if $cinfo{cc};
473              
474 0 0       0 $self->{w32cc} =~ /MSVC|BORLAND|GCC/ and $self->tty( "\n$make_output\n" );
475             }
476              
477 0   0     0 my $exe_ext = $Config{_exe} || $Config{exe_ext};
478 0         0 my $miniperl = "miniperl$exe_ext";
479 0         0 my $perl = "perl$exe_ext";
480             $perl = "ndbg$perl"
481 0 0 0     0 if $self->{is_vms} && $config->has_arg( '-Dusevmsdebug' );
482             $perl = "perl-static$exe_ext"
483 0 0 0     0 if $self->{is_win32} && $config->has_arg( '-Uuseshrplib' );
484              
485 0         0 $self->{_miniperl_bin} = $miniperl;
486 0         0 $self->{_perl_bin} = $perl;
487              
488 0 0       0 -x $miniperl or return BUILD_NOTHING;
489             return -x $perl
490 0 0       0 ? $self->{_run_exit} ? BUILD_MINIPERL : BUILD_PERL
    0          
491             : BUILD_MINIPERL;
492             }
493              
494             =head2 make_test_prep( )
495              
496             Run C<< I >> and check if F exists.
497              
498             =cut
499              
500             sub make_test_prep {
501 0     0 1 0 my $self = shift;
502 0 0       0 $self->{harnessonly} and return 1; # no test-prep target
503              
504 0         0 my $perl = catfile( "t", $self->{_perl_bin} );
505              
506 0 0       0 $self->{run} and unlink $perl;
507 0         0 $self->_make( "test-prep" );
508              
509 0 0       0 return $self->{is_win32} ? -f $perl : -l $perl;
510             }
511              
512             =head2 $smoker->make_test( )
513              
514             =cut
515              
516             sub make_test {
517 0     0 1 0 my $self = shift;
518              
519 0         0 $self->set_skip_tests;
520              
521 0         0 my( $config ) = @_;
522 0         0 my $config_args = "$config";
523              
524 0         0 $self->tty( "\n Tests start here:\n" );
525              
526             # No use testing different io layers without PerlIO
527             # just output 'stdio' for mkovz.pl
528             my @layers = ( ($config_args =~ /-Uuseperlio\b/) || $self->{defaultenv} )
529 0 0 0     0 ? qw( stdio ) : qw( stdio perlio );
530              
531 0         0 my @locales;
532 0 0 0     0 if ( !($config_args =~ /-Uuseperlio\b/ || $self->{defaultenv}) &&
      0        
533             $self->{locale} ) {
534 0         0 @locales = split ' ', $self->{locale};
535 0         0 push @layers, ( 'locale' ) x @locales;
536             }
537              
538 0         0 delete $ENV{PERL_UNICODE};
539 0         0 foreach my $perlio ( @layers ) {
540 0         0 my $had_LC_ALL = exists $ENV{LC_ALL};
541             local( $ENV{PERLIO}, $ENV{LC_ALL} ) =
542 0 0       0 ( "", defined $ENV{LC_ALL} ? $ENV{LC_ALL} : "" );
543 0         0 my $perlio_logmsg = $perlio;
544 0 0       0 if ( $perlio ne 'locale' ) {
545 0         0 $ENV{PERLIO} = $perlio;
546 0 0       0 $self->{is_win32} and $ENV{PERLIO} .= " :crlf";
547 0 0       0 $ENV{LC_ALL} = 'C' if $self->{force_c_locale};
548 0 0       0 $ENV{LC_ALL} or delete $ENV{LC_ALL};
549             # make default 'make test' runs possible
550 0 0       0 delete $ENV{PERLIO} if $self->{defaultenv};
551             } else {
552 0         0 $ENV{LC_ALL} = $self->{locale};
553 0         0 $perlio_logmsg .= ":" . pop @locales;
554             }
555 0         0 $self->ttylog( "TSTENV = $perlio_logmsg\t" );
556              
557 0 0       0 unless ( $self->{run} ) {
558 0         0 $self->ttylog( "bailing out (--norun)...\n" );
559 0         0 next;
560             }
561              
562 0 0       0 if ( $self->{harnessonly} ) {
563 0         0 $self->log_debug("[make test] Test::Harness ONLY");
564              
565             $self->{harness3opts} and
566 0 0       0 local $ENV{HARNESS_OPTIONS} = $self->{harness3opts};
567              
568 0         0 $self->make_test_harness( $config );
569              
570             } else {
571             my $test_target = $self->{is_vms}
572 0 0       0 ? 'test' : $self->{is56x} ? 'test-notty' : '_test';
    0          
573              
574             # MSWin32 builds from its own directory
575 0 0       0 if ( $self->{is_win32} ) {
576             # $config->has_arg( '-Uuseshrplib' )
577             # and $test_target = 'static-test';
578             # $self->_run_harness_target( $test_target );
579 0         0 $self->make_test_harness( $config );
580             } else {
581 0         0 $self->_run_TEST_target( $test_target, 1 );
582             }
583 0         0 $self->tty( "\n" );
584             }
585 0 0 0     0 !$had_LC_ALL && exists $ENV{LC_ALL} and delete $ENV{LC_ALL};
586             }
587              
588 0         0 $self->unset_skip_tests;
589              
590 0         0 return 1;
591             }
592              
593             =head2 $self->extend_with_harness( @nok )
594              
595             =cut
596              
597             sub extend_with_harness {
598 0     0 1 0 my $self = shift;
599 0         0 my %inconsistent = $self->_transform_testnames( @_ );
600 0         0 my @harness = sort keys %inconsistent;
601 0         0 my $harness_re1 = HARNESS_RE1();
602 0         0 my $harness_re2 = HARNESS_RE2();
603 0 0       0 if ( @harness ) {
604              
605             # @20051016 By request of Nicholas Clark
606 0         0 local $ENV{PERL_DESTRUCT_LEVEL} = $self->{harness_destruct};
607 0         0 local $ENV{PERL_SKIP_TTY_TEST} = 1;
608              
609             # I'm not happy with this PERLSHR approach for VMS
610 0   0     0 local $ENV{PERLSHR} = $ENV{PERLSHR} || "";
611             $self->{is_vms} and
612             $ENV{PERLSHR} = catfile( $self->{ddir},
613 0 0       0 'PERLSHR' . $Config{_exe} );
614 0         0 my $harness = join " ", @harness;
615 0         0 $self->tty( "\nExtending failures with harness:\n\t$harness\n" );
616 0         0 my $changed_dir;
617 0 0       0 chdir 't' and $changed_dir = 1;
618 0         0 my $all_ok = 0;
619 0         0 my $tst_perl = catfile( curdir(), 'perl' );
620 0 0       0 my $verbose = $self->{v} > 1 ? "-v" : "";
621 0         0 my @run_harness = $self->_run( "$tst_perl harness $verbose $harness" );
622 0         0 my $harness_out = $self->_parse_harness_output( \%inconsistent, $all_ok,
623             @run_harness );
624              
625             # safeguard against empty results
626 0   0     0 $inconsistent{ $_ } ||= 'FAILED' for keys %inconsistent;
627 0         0 $harness_out =~ s/^\s*$//;
628 0 0       0 if ( $all_ok ) {
629             $harness_out .= scalar keys %inconsistent
630             ? "Inconsistent test results (between TEST and harness):\n" .
631             join "", map {
632 0 0       0 my $dots = '.' x (40 - length $_ );
  0 0       0  
633 0         0 " $_${dots}$inconsistent{ $_ }\n";
634             } keys %inconsistent
635             : $harness_out ? "" : "All tests successful.";
636             } else {
637             $harness_out .= scalar keys %inconsistent
638             ? "Inconsistent test results (between TEST and harness):\n" .
639             join "", map {
640 0 0       0 my $dots = '.' x (40 - length $_ );
  0         0  
641 0         0 " $_${dots}$inconsistent{ $_ }\n";
642             } keys %inconsistent
643             : "";
644             }
645 0         0 $self->ttylog("\n", $harness_out, "\n" );
646 0 0       0 $changed_dir and chdir updir();
647             }
648             }
649              
650             =head2 $smoker->make_test_harness
651              
652             Use Test::Harness (the test_harness target) to get the failing test
653             information and do not bother with TEST.
654              
655             =cut
656              
657             sub make_test_harness {
658 0     0 1 0 my( $self, $config ) = @_;
659              
660 0         0 my $target= "test_harness";
661 0         0 my $debugging = "";
662              
663 0 0       0 if ( $self->{is_vms} ) {
    0          
664              
665 0 0       0 $debugging = $config->has_arg( '-Dusevmsdebug' )
666             ? qq[/macro=("__DEBUG__=1")]
667             : "";
668              
669             } elsif ($self->{is_win32}) {
670 0 0       0 $target = $config->has_arg( '-Uuseshrplib' ) ? "static-test" : "test";
671             }
672              
673 0 0       0 if ( $self->{hasharness3} ) {
674 0         0 $self->log_debug("[make_test_harness] Test::Harness >= 3");
675 0         0 $self->_run_harness3_target( $target, $debugging );
676             } else {
677 0         0 $self->log_debug("[make_test_harness] Test::Harness < 3");
678 0         0 $self->_run_harness_target( $target, $debugging );
679             }
680             }
681              
682             =head2 $smoker->_run_harness_target( $target, $extra )
683              
684             The command to run C differs based on platform, so
685             the arguments have to be passed into general routine. C<$target>
686             specifies the makefile-target, C<$makeopt> specifies the extra options
687             for the make program.
688              
689             =cut
690              
691             sub _run_harness_target {
692 0     0   0 my( $self, $target, $extra ) = @_;
693              
694 0         0 my $seenheader = 0;
695 0         0 my @failed = ( );
696              
697 0         0 my $harness_re1 = HARNESS_RE1();
698 0         0 my $harness_re2 = HARNESS_RE2();
699              
700 0         0 my $tst = $self->_make_fork( $target, $extra );
701              
702 0         0 my ($line, $last);
703 0         0 while ( $line = <$tst> ) {
704             #$self->log_debug($line);
705              
706             # This line with timings only has to be logged to .out.
707 0 0       0 $line =~ / \b (?:Files | u) = .+ Tests = [0-9]+ /xi
708             and $self->log($line);
709              
710 0 0       0 $last and next;
711 0 0       0 $line =~ /All tests successful/
712             and push( @failed, $line ), $last++, next;
713              
714 0 0       0 $line =~ /Failed Test\s+Stat/
715             and $seenheader = 1, next;
716 0 0       0 $seenheader or next;
717              
718 0         0 my( $name, $fail ) = $line =~ m/$harness_re1/;
719 0 0       0 if ( $name ) {
720 0         0 my $dots = '.' x (40 - length $name );
721 0         0 $self->log_debug("[known failed test] $name");
722 0         0 push @failed, " $name${dots}FAILED $fail\n";
723             } else {
724 0         0 ( $fail ) = $line =~ m/$harness_re2/;
725 0 0       0 next unless $fail;
726 0         0 push @failed, " " x 51 . "$fail\n";
727             }
728             }
729 0         0 my @dump = <$tst>; # Read trailing output from pipe
730              
731 0 0       0 close $tst or do {
732 0   0     0 my $error = $! || ( $? >> 8);
733 0         0 require Carp;
734 0         0 Carp::carp("\nerror while running harness target '$target': $error");
735             };
736              
737 0         0 $self->ttylog( "\n", join( "", @failed ), "\n" );
738 0         0 $self->tty( "Archived results...\n" );
739             }
740              
741             =head2 $smoker->_run_harness3_target( $target, $extra )
742              
743             The command to run C differs based on platform, so
744             the arguments have to be passed into general routine. C<$target>
745             specifies the makefile-target, C<$makeopt> specifies the extra options
746             for the make program.
747              
748             =cut
749              
750             sub _run_harness3_target {
751 0     0   0 my( $self, $target, $extra ) = @_;
752              
753 0         0 my $harness3_failed = HARNESS3_RE_FAILED();
754 0         0 my $harness3_todo = HARNESS3_RE_TODO();
755 0         0 my $harness3_extra = HARNESS3_RE_EXTRA();
756 0         0 my $seenheader = 0;
757 0         0 my @failed = ( );
758              
759 0         0 my $tst = $self->_make_fork( $target, $extra );
760              
761 0         0 my $line;
762             my $file;
763 0         0 my $found = 0;
764 0         0 while ( $line = <$tst> ) {
765             #$self->log_debug($line);
766              
767             # This line with timings only has to be logged to .out.
768 0 0       0 $line =~ / \b (?:Files | u) = .+ Tests = [0-9]+ /xi
769             and $self->log($line);
770              
771 0 0       0 $line =~ /All tests successful/
772             and push( @failed, $line ), next;
773              
774 0 0       0 $line =~ /Test Summary Report/ and $seenheader = 1, next;
775 0 0       0 $seenheader or next;
776              
777 0         0 my( $tname ) = $line =~ /^\s*(.+(?:\.t)?)\s+\(Wstat/;
778 0 0       0 if ( $tname ) {
779 0 0 0     0 if ($file and not $found) {
780 0         0 $self->log_debug("[weird failed test] $file");
781 0         0 push @failed, "${file}??????\n";
782             }
783 0         0 my $ntest = $self->_normalize_testname( $tname );
784 0         0 my $dots = '.' x (60 - length $ntest);
785 0         0 $file = $ntest . $dots;
786 0         0 $found = 0;
787 0         0 next;
788             }
789              
790 0         0 my( $failed ) = $line =~ /$harness3_failed/x;
791 0 0       0 if ( $failed ) {
792 0         0 $self->log_debug("[known failed test] $file");
793 0         0 push @failed, "${file}FAILED\n";
794 0         0 push @failed, " $failed\n";
795 0         0 $found = 1;
796 0         0 next;
797             }
798              
799 0         0 my( $todo ) = $line =~ /$harness3_todo/x;
800 0 0       0 if ( $todo ) {
801 0         0 $self->log_debug("[todo test passed] $file");
802 0         0 push @failed, "${file}PASSED\n";
803 0         0 push @failed, " $todo\n";
804 0         0 $found = 1;
805 0         0 next;
806             }
807              
808 0         0 my ( $extra ) = $line =~ /$harness3_extra/x;
809 0 0       0 if ( $extra) {
810 0         0 push @failed, " $extra\n";
811 0         0 next;
812             }
813              
814 0         0 my( $parse_error ) = $line =~ /^ Parse errors: (.+)/;
815 0 0       0 if ( $parse_error ) {
816 0         0 $self->log_debug("[TAP-error test] $file");
817 0         0 push @failed, "${file}FAILED\n";
818 0         0 push @failed, " $parse_error\n";
819 0         0 $found = 1;
820 0         0 next;
821             }
822              
823 0         0 my( $exit_status ) = $line =~ /^ (Non-zero exit status: .+)/;
824 0 0       0 if ( $exit_status ) {
825 0         0 $self->log_debug("[died test] $file");
826 0         0 push @failed, "${file}FAILED\n";
827 0         0 push @failed, " $exit_status\n";
828 0         0 $found = 1;
829 0         0 next;
830             }
831             }
832 0 0 0     0 if ($file and not $found) {
833 0         0 $self->log_debug("[unknown failure] $file");
834 0         0 push @failed, "${file}??????\n";
835             }
836              
837 0         0 my @dump = <$tst>; # Read trailing output from pipe
838              
839 0 0       0 close $tst or do {
840 0   0     0 my $error = $! || ( $? >> 8);
841 0         0 require Carp;
842 0         0 Carp::carp("\nerror while running harness target '$target': $error" );
843             };
844              
845 0         0 $self->ttylog( "\n", join( "", @failed ), "\n" );
846 0         0 $self->tty( "Archived results...\n" );
847             }
848              
849             sub _run_TEST_target {
850 0     0   0 my( $self, $target, $extend ) = @_;
851 0 0       0 !$target and do {
852 0         0 require Carp;
853 0         0 Carp::confess("No target in _run_TEST_target");
854             };
855              
856 0         0 my @nok;
857 0         0 my $tst = $self->_make_fork( $target );
858 0         0 my $ok;
859              
860 0         0 while (<$tst>) {
861 0         0 $self->log_debug($_);
862 0 0       0 skip_filter( $_ ) and next;
863              
864             # make mkovz.pl's life easier
865 0         0 s/(.)(TSTENV\s+=\s+\w+)/$1\n$2/;
866              
867 0 0       0 if (m/^u=.*tests=/) {
868 0         0 s/(\d\.\d*) /sprintf "%.2f ", $1/ge;
  0         0  
869 0         0 $self->log( $_ );
870             } else {
871 0   0     0 $ok ||= m/^All tests successful/;
872 0         0 push @nok, $_;
873             }
874 0         0 $self->tty( $_ );
875             }
876 0 0       0 close $tst or do {
877 0   0     0 my $error = $! || ( $? >> 8);
878 0         0 $self->tty("\nError while reading test-results: $error");
879             };
880              
881             # $self->log( map { " $_" } @nok );
882 0 0       0 if ( grep m/^All tests successful/, @nok ) {
    0          
883 0         0 $self->log( "All tests successful.\n" );
884 0         0 $self->tty( "\nOK, archive results ..." );
885             $self->{patch} and
886 0 0       0 $nok[0] =~ s/\./ for .patch = $self->{patch}./;
887             } elsif ( !$extend ) {
888 0         0 $self->ttylog( map { " $_" } @nok );
  0         0  
889             } else {
890 0         0 $self->extend_with_harness( @nok );
891             }
892             }
893              
894             =head2 $self->make_minitest
895              
896             C was unable to build a I executable, but managed to build
897             I, so we do C<< S >>.
898              
899             =cut
900              
901             sub make_minitest {
902 0     0 1 0 my $self = shift;
903              
904 0         0 $self->ttylog( "TSTENV = minitest\t" );
905              
906 0 0       0 if ($self->{is_win32}) {
907 0         0 $self->_run_harness_target( "minitest" );
908             } else {
909 0         0 $self->_run_TEST_target( "minitest", 0 );
910             }
911              
912 0         0 $self->tty( "\n" );
913 0         0 return 1;
914             }
915              
916             =head2 $self->_parse_harness_output( $\%notok, $all_ok, @lines )
917              
918             Factor out the parsing of the Test::Harness output, as it seems subject
919             to change.
920              
921             =cut
922              
923             sub _parse_harness_output {
924 17     17   8272 my( $self, $notok, $all_ok, @lines ) = @_;
925              
926 17 100       132 grep m/^Test Summary Report/ => @lines
927             and return $self->_parse_harness3_output( $notok, $_[2], @lines );
928              
929 5         14 my $harness_re1 = HARNESS_RE1();
930 5         15 my $harness_re2 = HARNESS_RE2();
931              
932             my $output = join "", map {
933 16         137 my( $name, $fail ) = m/$harness_re1/;
934 16 100       35 if ( $name ) {
935 10         23 delete $notok->{ $name };
936 10         21 my $dots = '.' x (40 - length $name );
937 10         44 " $name${dots}FAILED $fail\n";
938             } else {
939 6         70 ( $fail ) = m/$harness_re2/;
940 6         27 " " x 51 . "$fail\n";
941             }
942             } grep m/$harness_re2/ || m/$harness_re1/ => map {
943 5 50 100     9 /All tests successful/ && $all_ok++;
  28         59  
944 28         87 $self->log_info( $_ );
945 28         384 $_;
946             } @lines;
947              
948 5         12 $_[2] = $all_ok;
949 5         19 return $output;
950             }
951              
952             =head2 $self->_parse_harness3_output( $\%notok, $all_ok, @lines )
953              
954             Fator out the parsing of the Test::Harness 3 output, as it seems subject
955             to change.
956              
957             =cut
958              
959             sub _parse_harness3_output {
960 12     12   50 my( $self, $notok, $all_ok, @lines ) = @_;
961              
962 12         24 my $harness3_failed = HARNESS3_RE_FAILED();
963 12         18 my $harness3_todo = HARNESS3_RE_TODO();
964 12         16 my $harness3_extra = HARNESS3_RE_EXTRA();
965 12         49 my $seenheader = 0;
966 12         20 my $ntest = "";
967 12         21 my $file = "";
968 12         20 my $found = 0;
969              
970             my @out = map {
971 130         178 my $line = $_;
972              
973 130         440 my( $tname ) = $line =~ /^\s*(.+(:?\.t)?)\s+\(Wstat/;
974 130         302 my( $failed ) = $line =~ /$harness3_failed/x;
975 130         261 my( $todo ) = $line =~ /$harness3_todo/x;
976 130         299 my( $extra ) = $line =~ /$harness3_extra/x;
977 130         194 my( $parse_error ) = $line =~ /^ Parse errors: (.+)/;
978 130         176 my( $exit_status ) = $line =~ /^ (Non-zero exit status: .+)/;
979              
980 130 100       308 if ( $tname ) {
    100          
    100          
    100          
    100          
    100          
981 22         39 my $r;
982 22 50 66     75 if ($file and not $found) {
983 0         0 $r = "${file}??????\n";
984             }
985              
986 22         51 $ntest = $self->_normalize_testname( $tname );
987 22         50 my $dots = '.' x (60 - length $ntest);
988 22         46 $file = " $ntest${dots}";
989 22         28 $found = 0;
990 22         62 $r;
991             } elsif ( $failed ) {
992 9         19 delete $notok->{ $ntest };
993 9         12 $found = 1;
994 9         44 ($file . "FAILED\n", " $failed\n");
995             } elsif ( $todo ) {
996 14         22 $found = 1;
997 14         43 ($file . "PASSED\n", " $todo\n");
998             } elsif ($extra) {
999 23         54 " $extra\n"
1000             } elsif ( $parse_error ) {
1001 7         12 delete $notok->{ $ntest };
1002 7         12 $found = 1;
1003 7         19 ($file . "FAILED\n", " $parse_error\n");
1004             } elsif ( $exit_status ) {
1005 6         12 delete $notok->{ $ntest };
1006 6         10 $found = 1;
1007 6         19 ($file . "FAILED\n", " $exit_status\n");
1008             } else {
1009 49         104 undef;
1010             }
1011             } grep defined $_ && length $_ => map {
1012 12 100 66     22 $seenheader or $seenheader = $_ =~ /Test Summary Report/;
  296         569  
1013 296 100       529 /All tests successful/ && $all_ok++;
1014 296         668 $self->log_info($_);
1015 296 100       934 $seenheader ? $_ : '';
1016             } @lines;
1017 12 100 66     65 if ($file and not $found) {
1018 1         4 push @out, "${file}??????\n";
1019             }
1020 12         69 my $output = join "", grep defined $_ => @out;
1021              
1022 12         22 $_[2] = $all_ok;
1023 12         79 return $output;
1024             }
1025              
1026             =head2 $self->_transform_testnames( @notok )
1027              
1028             C<_transform_testnames()> takes a list of testnames, as found by
1029             C (testname without C<.t> suffix followed by dots and a reason)
1030             and returns a hash with the filenames relative to the C directory
1031             as keys and the reason as value.
1032              
1033             =cut
1034              
1035             sub _transform_testnames {
1036 1     1   29 my( $self, @notok ) = @_;
1037 1         3 my %inconsistent;
1038 1         11 for my $nok ( @notok ) {
1039 4 50       35 $nok =~ m!^((?:\.\.[\\/])?\w+[\\/][-\w/\\]+)\.*(.*)! or next;
1040 4         24 my( $test_name, $status ) = ( $1, $2 );
1041              
1042 4         20 my $test_path = $self->_normalize_testname( $test_name );
1043              
1044 4   33     31 $inconsistent{ $test_path } ||= $status;
1045             }
1046 1         18 return %inconsistent;
1047             }
1048              
1049             =head2 $smoker->_normalize_testname( $test )
1050              
1051             Normalize a testname...
1052              
1053             =cut
1054              
1055             sub _normalize_testname {
1056 30     30   3159 my( $self, $test_name ) = @_;
1057              
1058 30         107 $test_name =~ s/\s+$//;
1059 30 100       114 $test_name =~ /\.t$/ or $test_name .= '.t';
1060 30 100       75 if ( $test_name !~ m|^\Q../| ) {
1061 28 100       195 $test_name = $test_name =~ /^(?:cpan|dist|ext|lib|t)\b/
1062             ? catfile( updir(), $test_name )
1063             : catfile( updir(), 't', $test_name );
1064             }
1065              
1066 30         137 my $test_base = catdir( $self->{ddir}, 'pod' );
1067 30         124 $test_name = rel2abs( $test_name, $test_base );
1068              
1069 30         1093 my $test_path = abs2rel( $test_name, $test_base );
1070 30 50       1986 $test_path =~ tr!\\!/! if $self->{is_win32};
1071              
1072             # sometimes ../t is optimized away
1073 30 50       132 $test_path !~ m|^\.\.[\\/]| and $test_path = "../t/$test_path";
1074              
1075 30         71 return $test_path;
1076             }
1077              
1078             =head2 set_skip_tests( [$unset] )
1079              
1080             Read from a MANIFEST like file, set in C<< $self->{skip_tests} >>, and
1081             rename the files in it with the extension F<.tskip>. If C<$unset> is
1082             set, they will be renamed back.
1083              
1084             =head2 unset_skip_tests
1085              
1086             Calls C<< $self->set_skip_tests( 1 ) >>.
1087              
1088             =cut
1089              
1090             sub set_skip_tests {
1091 2     2 1 981 my( $self, $unset ) = @_;
1092              
1093 2 50       8 $self->{skip_tests} or return;
1094 2         11 local *SKIPTESTS;
1095              
1096 2 50       74 if ( open SKIPTESTS, "< $self->{skip_tests}" ) {
1097 2 100       10 my $action = $unset ? 'Unskip' : 'Skip';
1098 2         15 $self->log_info("$action tests from '$self->{skip_tests}'");
1099 2         13 my @libext;
1100             my $raw;
1101 2         32 while ( $raw = ) {
1102 10 50       43 $raw =~ m/^\s*#/ and next;
1103 10         58 $raw =~ s/(\S+).*/$1/s;
1104 10 0 33     39 if ($raw !~ m/\.t$/ and $raw !~ m/test\.pl$/) {
1105 0         0 next;
1106             }
1107 10 100       28 if ( $raw =~ m{^(?:lib|ext|cpan|dist)/} ) {
1108 8         17 push @libext, $raw;
1109 8         45 next;
1110             }
1111 2         25 my $tsrc = File::Spec->catfile( $self->{ddir}, $raw );
1112 2 50       34 next if !-f $tsrc;
1113 2         10 my $skip = qq[print "1..0 # SKIP Disabled by Test::Smoke\\n";\nexit 0;\n__END__\n];
1114 11     11   81981 use autodie;
  11         153125  
  11         63  
1115              
1116 2         17 open my $test_fh_r, "<:raw", $tsrc;
1117 2         3109 my $body = do { local $/; <$test_fh_r> };
  2         20  
  2         86  
1118 2         15 close $test_fh_r;
1119              
1120 2         1033 open my $test_fh_w, ">:raw", $tsrc;
1121 2 100       338 print $test_fh_w !$unset ? "$skip$body" : do { $body =~ s/^\Q$skip\E//; $body; };
  1         31  
  1         6  
1122 2         7 close $test_fh_w;
1123              
1124 2         297 $self->log_info("\t%s: %sok%s\n", $raw, '', "");
1125             }
1126 2         20 close SKIPTESTS;
1127 2 50       17 @libext and $self->change_manifest( \@libext, $unset );
1128             } else {
1129 0         0 require Carp;
1130 0         0 Carp::carp("Cannot open($self->{skip_tests}): $!");
1131             }
1132             }
1133              
1134 1     1 1 1434 sub unset_skip_tests { $_[0]->set_skip_tests( 1 ) }
1135              
1136             =head2 $self->change_manifest( \@tests, $unset )
1137              
1138             =cut
1139              
1140             sub change_manifest {
1141 2     2 1 5 my( $self, $tests, $unset ) = @_;
1142              
1143 2         14 my $mani_org = catfile $self->{ddir}, 'MANIFEST';
1144 2         9 my $mani_new = catfile $self->{ddir}, 'MANIFEST.ORG';
1145 2 100       6 if ( $unset ) {
1146 1 50       19 if ( -f $mani_new ) {
1147 1         13 my $perms = (stat $mani_new)[2] & 07777;
1148 1         16 chmod 0755, $mani_new;
1149 1         61 unlink $mani_org;
1150 1         32 rename $mani_new, $mani_org;
1151 1         20 chmod $perms, $mani_org;
1152             }
1153             } else {
1154 1         18 my $perms = (stat $mani_org)[2] & 07777;
1155 1         17 chmod 0755, $mani_org;
1156 1 50       55 rename $mani_org, $mani_new or do {
1157 0         0 chmod $perms, $mani_org;
1158 0         0 require Carp;
1159 0         0 Carp::carp("No skip of lib or ext tests [rename($mani_new): $!]");
1160 0         0 return;
1161             };
1162 1         7 local( *MANIO, *MANIN );
1163 1 50       44 if ( open MANIO, "< $mani_new" ) {
1164 1         4 binmode MANIO;
1165 1 50       70 if ( open MANIN, "> $mani_org" ) {
1166 1         5 binmode MANIN;
1167 1         2 my $mline;
1168 1         19 while ( $mline = ) {
1169 17         25 chomp $mline;
1170 17         80 ( my $fn = $mline ) =~ s/^(\S+).*/$1/;
1171 17 100       190 if ( ! grep /\Q$fn\E/ => @$tests ) {
1172 13         75 print MANIN "$mline\n";
1173             } else {
1174 4         22 $self->log_info("\t$fn");
1175             }
1176             }
1177 1         50 close MANIN;
1178             }
1179 1         11 close MANIO;
1180 1         25 chmod $perms, $mani_new;
1181             }
1182             }
1183             }
1184              
1185             =head2 $self->_run( $command[, $sub[, @args]] )
1186              
1187             C<_run()> returns C<< qx( $command ) >> unless C<$sub> is specified.
1188             If C<$sub> is defined (and a coderef) C<< $sub->( $command, @args ) >> will
1189             be called.
1190              
1191             =cut
1192              
1193             sub _run {
1194 0     0     my $self = shift;
1195 0           my( $command, $sub, @args ) = @_;
1196              
1197 0           $self->log_debug("[$command]");
1198 0 0         defined $sub and return &$sub( $command, @args );
1199              
1200 0     0     my ( $out, $err, $res ) = capture { system $command };
  0            
1201 0           $self->tty($out);
1202 0 0         $self->ttylog($err) if $err;
1203 0           $self->{_run_exit} = $res >> 8;
1204 0 0         return wantarray ? split /(\r\n|\r|\n)/, $out : $out;
1205             }
1206              
1207             =head2 $self->_make( $command )
1208              
1209             C<_make()> calls C<< run( "make $command" ) >>, and does some extra
1210             stuff to help MSWin32 (the right maker, the directory).
1211              
1212             =cut
1213              
1214             sub _make {
1215 0     0     my $self = shift;
1216 0           my $cmd = shift;
1217 0 0         $self->{makeopt} and $cmd = "$self->{makeopt} $cmd";
1218 0 0         $cmd =~ m/clean/ and $cmd =~ s/-j[0-9]+\s+//;
1219              
1220             return
1221             $self->{is_vms} ? $self->_make_vms($cmd)
1222 0 0         : $self->{is_win32} ? $self->_make_win32($cmd)
    0          
1223             : $self->_run("make $cmd");
1224             }
1225              
1226             sub _make_win32 {
1227 0     0     my $self = shift;
1228 0           my $cmd = shift;
1229              
1230 0           $cmd =~ s|2\s*>\s*/dev/null\s*$|2>nul|;
1231              
1232 0           $cmd = "$self->{w32make} -f smoke.mk $cmd";
1233 0 0         chdir "win32" or die "unable to chdir () into 'win32'";
1234 0           my @output = $self->_run($cmd);
1235 0 0         chdir ".." or die "unable to chdir() out of 'win32'";
1236 0 0         return wantarray ? @output : join "", @output;
1237             }
1238              
1239             sub _make_vms {
1240 0     0     my $self = shift;
1241 0           my $cmd = shift;
1242              
1243 0           my $kill_err;
1244             # don't capture STDERR
1245             # @ But why? and what if we do it DOSish? 2>NUL:
1246              
1247 0 0         $cmd =~ s|2\s*>\s*/dev/null\s*$|| and $kill_err = 1;
1248              
1249 0           $cmd = "$self->{vmsmake} $cmd";
1250 0 0         my @output = $self->_run(
1251             $kill_err ? qq{$^X -e "close STDERR; system '$cmd'"} : $cmd
1252             );
1253 0 0         return wantarray ? @output : join "", @output;
1254             }
1255              
1256             =head2 $smoker->_make_fork( $target, $extra )
1257              
1258             C<_make_fork()> opens a read pipe to the make command with C<$target>
1259             and C<$extra> arguments for the make command.
1260              
1261             =cut
1262              
1263             sub _make_fork {
1264 0     0     my( $self, $target, $extra ) = @_;
1265              
1266 0 0         !defined $extra and $extra = "";
1267              
1268 0           my( $ok, $err, $cmd );
1269 0           local *TST;
1270              
1271             # MSWin32 builds from its own directory
1272 0 0         if ( $self->{is_win32} ) {
1273 0 0         chdir "win32" or die "unable to chdir () into 'win32'";
1274             # Same as in make ()
1275 0           $cmd = "$self->{testmake}$extra -f smoke.mk $target |";
1276 0 0         $ok = open TST, $cmd or $err = $!;
1277 0 0         chdir ".." or die "unable to chdir () out of 'win32'";
1278             } else {
1279 0           local $ENV{PERL} = "./perl";
1280 0           $cmd = "$self->{testmake}$extra $target |";
1281 0 0         $ok = open TST, $cmd or $err = $!;
1282             }
1283 0 0         $ok or do {
1284 0           require Carp;
1285 0           Carp::carp("Cannot fork '$cmd': $err");
1286 0           return 0;
1287             };
1288 0           select ((select (*TST), $| = 1)[0]);
1289 0           return *TST;
1290             }
1291              
1292             =head2 $smoker->_vms__rooted_logical
1293              
1294             This code sets up a rooted logical C and changes the {ddir}
1295             to that root.
1296              
1297             =cut
1298              
1299             sub _vms_rooted_logical {
1300 0     0     my $self = shift;
1301 0 0         return unless $^O eq 'VMS';
1302              
1303 0           Test::Smoke::Util::set_vms_rooted_logical( TSP5SRC => $self->{ddir} );
1304 0           $self->{vms_ddir} = $self->{ddir};
1305 0           $self->{ddir} = 'TSP5SRC:[000000]';
1306              
1307             }
1308              
1309             1;
1310              
1311             =head1 SEE ALSO
1312              
1313             L
1314              
1315             =head1 COPYRIGHT
1316              
1317             (c) 2002-2003, All rights reserved.
1318              
1319             * Abe Timmerman
1320              
1321             This library is free software; you can redistribute it and/or modify
1322             it under the same terms as Perl itself.
1323              
1324             See:
1325              
1326             =over 4
1327              
1328             =item * L
1329              
1330             =item * L
1331              
1332             =back
1333              
1334             This program is distributed in the hope that it will be useful,
1335             but WITHOUT ANY WARRANTY; without even the implied warranty of
1336             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1337              
1338             =cut