blob: 85835d0f89a31b2519a4fae5d6253c672149faac [file] [log] [blame]
## IPC::Cmd test suite ###
BEGIN { chdir 't' if -d 't' };
use strict;
use lib qw[../lib];
use File::Spec;
use Test::More 'no_plan';
my $Class = 'IPC::Cmd';
my $AClass = $Class . '::TimeOut';
my @Funcs = qw[run can_run QUOTE run_forked];
my @Meths = qw[can_use_ipc_run can_use_ipc_open3 can_capture_buffer can_use_run_forked];
my $IsWin32 = $^O eq 'MSWin32';
my $Verbose = @ARGV ? 1 : 0;
use_ok( $Class, $_ ) for @Funcs;
can_ok( $Class, $_ ) for @Funcs, @Meths;
can_ok( __PACKAGE__, $_ ) for @Funcs;
my $Have_IPC_Run = $Class->can_use_ipc_run || 0;
my $Have_IPC_Open3 = $Class->can_use_ipc_open3 || 0;
diag("IPC::Run: $Have_IPC_Run IPC::Open3: $Have_IPC_Open3")
unless exists $ENV{'PERL_CORE'};
local $IPC::Cmd::VERBOSE = $Verbose;
local $IPC::Cmd::VERBOSE = $Verbose;
local $IPC::Cmd::DEBUG = $Verbose;
local $IPC::Cmd::DEBUG = $Verbose;
### run tests in various configurations, based on what modules we have
my @Prefs = ( );
push @Prefs, [ $Have_IPC_Run, $Have_IPC_Open3 ] if $Have_IPC_Run;
### run this config twice to ensure FD restores work properly
push @Prefs, [ 0, $Have_IPC_Open3 ],
[ 0, $Have_IPC_Open3 ] if $Have_IPC_Open3;
### run this config twice to ensure FD restores work properly
### these are the system() tests;
push @Prefs, [ 0, 0 ], [ 0, 0 ];
### can_run tests
{
ok( can_run("$^X"), q[Found 'perl' in your path] );
ok( !can_run('10283lkjfdalskfjaf'), q[Not found non-existent binary] );
}
{ ### list of commands and regexes matching output
### XXX use " everywhere when using literal strings as commands for
### portability, especially on win32
my $map = [
# command # output regex # buffer
### run tests that print only to stdout
[ "$^X -v", qr/larry\s+wall/i, 3, ],
[ [$^X, '-v'], qr/larry\s+wall/i, 3, ],
### pipes
[ "$^X -eprint+424 | $^X -neprint+split+2", qr/44/, 3, ],
[ [$^X,qw[-eprint+424 |], $^X, qw|-neprint+split+2|],
qr/44/, 3, ],
### whitespace
[ [$^X, '-eprint+shift', q|a b a|], qr/a b a/, 3, ],
[ qq[$^X -eprint+shift "a b a"], qr/a b a/, 3, ],
### whitespace + pipe
[ [$^X, '-eprint+shift', q|a b a|, q[|], $^X, qw[-neprint+split+b] ],
qr/a a/, 3, ],
[ qq[$^X -eprint+shift "a b a" | $^X -neprint+split+b],
qr/a a/, 3, ],
### run tests that print only to stderr
[ "$^X -ewarn+42", qr/^42 /, 4, ],
[ [$^X, '-ewarn+42'], qr/^42 /, 4, ],
];
### extended test in developer mode
### test if gzip | tar works
if( $Verbose ) {
my $gzip = can_run('gzip');
my $tar = can_run('tar');
if( $gzip and $tar ) {
push @$map,
[ [$gzip, qw[-cdf src/x.tgz |], $tar, qw[-tf -]],
qr/a/, 3, ];
}
}
### for each configuration
for my $pref ( @Prefs ) {
local $IPC::Cmd::USE_IPC_RUN = !!$pref->[0];
local $IPC::Cmd::USE_IPC_RUN = !!$pref->[0];
local $IPC::Cmd::USE_IPC_OPEN3 = !!$pref->[1];
local $IPC::Cmd::USE_IPC_OPEN3 = !!$pref->[1];
### for each command
for my $aref ( @$map ) {
my $cmd = $aref->[0];
my $regex = $aref->[1];
my $index = $aref->[2];
my $pp_cmd = ref $cmd ? "Array: @$cmd" : "Scalar: $cmd";
$pp_cmd .= " (IPC::Run: $pref->[0] IPC::Open3: $pref->[1])";
diag( "Running '$pp_cmd'") if $Verbose;
### in scalar mode
{ my $buffer;
my $ok = run( command => $cmd, buffer => \$buffer );
ok( $ok, "Ran '$pp_cmd' command successfully" );
SKIP: {
skip "No buffers available", 1
unless $Class->can_capture_buffer;
like( $buffer, $regex,
" Buffer matches $regex -- ($pp_cmd)" );
}
}
### in list mode
{ diag( "Running list mode" ) if $Verbose;
my @list = run( command => $cmd );
ok( $list[0], "Ran '$pp_cmd' successfully" );
ok( !$list[1], " No error code set -- ($pp_cmd)" );
my $list_length = $Class->can_capture_buffer ? 5 : 2;
is( scalar(@list), $list_length,
" Output list has $list_length entries -- ($pp_cmd)" );
SKIP: {
skip "No buffers available", 6
unless $Class->can_capture_buffer;
### the last 3 entries from the RV, are they array refs?
isa_ok( $list[$_], 'ARRAY' ) for 2..4;
like( "@{$list[2]}", $regex,
" Combined buffer matches $regex -- ($pp_cmd)" );
like( "@{$list[$index]}", qr/$regex/,
" Proper buffer($index) matches $regex -- ($pp_cmd)" );
is( scalar( @{$list[ $index==3 ? 4 : 3 ]} ), 0,
" Other buffer empty -- ($pp_cmd)" );
}
}
}
}
}
unless ( IPC::Cmd->can_use_run_forked ) {
ok(1, "run_forked not available on this platform");
exit;
}
{
my $cmd = "echo out ; echo err >&2 ; sleep 4";
my $r = run_forked($cmd, {'timeout' => 1});
ok(ref($r) eq 'HASH', "executed: $cmd");
ok($r->{'timeout'} eq 1, "timed out");
ok($r->{'stdout'}, "stdout: " . $r->{'stdout'});
ok($r->{'stderr'}, "stderr: " . $r->{'stderr'});
}
# try discarding the out+err
{
my $out;
my $cmd = "echo out ; echo err >&2";
my $r = run_forked(
$cmd,
{ discard_output => 1,
stderr_handler => sub { $out .= shift },
stdout_handler => sub { $out .= shift }
});
ok(ref($r) eq 'HASH', "executed: $cmd");
ok(!$r->{'stdout'}, "stdout discarded");
ok(!$r->{'stderr'}, "stderr discarded");
ok($out =~ m/out/, "stdout handled");
ok($out =~ m/err/, "stderr handled");
}
__END__
### special call to check that output is interleaved properly
{ my $cmd = [$^X, File::Spec->catfile( qw[src output.pl] ) ];
### for each configuration
for my $pref ( @Prefs ) {
diag( "Running config: IPC::Run: $pref->[0] IPC::Open3: $pref->[1]" )
if $Verbose;
local $IPC::Cmd::USE_IPC_RUN = $pref->[0];
local $IPC::Cmd::USE_IPC_OPEN3 = $pref->[1];
my @list = run( command => $cmd, buffer => \my $buffer );
ok( $list[0], "Ran @{$cmd} successfully" );
ok( !$list[1], " No errorcode set" );
SKIP: {
skip "No buffers available", 3 unless $Class->can_capture_buffer;
TODO: {
local $TODO = qq[Can't interleave input/output buffers yet];
is( "@{$list[2]}",'1 2 3 4'," Combined output as expected" );
is( "@{$list[3]}", '1 3', " STDOUT as expected" );
is( "@{$list[4]}", '2 4', " STDERR as expected" );
}
}
}
}
### test failures
{ ### for each configuration
for my $pref ( @Prefs ) {
diag( "Running config: IPC::Run: $pref->[0] IPC::Open3: $pref->[1]" )
if $Verbose;
local $IPC::Cmd::USE_IPC_RUN = $pref->[0];
local $IPC::Cmd::USE_IPC_OPEN3 = $pref->[1];
my ($ok,$err) = run( command => "$^X -edie" );
ok( !$ok, "Non-zero exit caught" );
ok( $err, " Error '$err'" );
}
}
### timeout tests
{ my $timeout = 1;
for my $pref ( @Prefs ) {
diag( "Running config: IPC::Run: $pref->[0] IPC::Open3: $pref->[1]" )
if $Verbose;
local $IPC::Cmd::USE_IPC_RUN = $pref->[0];
local $IPC::Cmd::USE_IPC_OPEN3 = $pref->[1];
### -X to quiet the 'sleep without parens is ambiguous' warning
my ($ok,$err) = run( command => "$^X -Xesleep+4", timeout => $timeout );
ok( !$ok, "Timeout caught" );
ok( $err, " Error stored" );
ok( not(ref($err)), " Error string is not a reference" );
like( $err,qr/^$AClass/," Error '$err' mentions $AClass" );
}
}