File Coverage

blib/lib/Test2/Tools/Command.pm
Criterion Covered Total %
statement 79 79 100.0
branch 29 30 96.6
condition 14 28 50.0
subroutine 13 13 100.0
pod 1 1 100.0
total 136 151 90.0


line stmt bran cond sub pod time code
1             # -*- Perl -*-
2             #
3             # run unix commands for expected results given particular inputs
4              
5             package Test2::Tools::Command;
6             our $VERSION = '0.10';
7              
8 2     2   232358 use 5.10.0;
  2         12  
9 2     2   10 use strict;
  2         5  
  2         55  
10 2     2   10 use warnings;
  2         4  
  2         74  
11 2     2   12 use Cwd ();
  2         3  
  2         42  
12 2     2   979 use File::chdir; # $CWD
  2         5236  
  2         261  
13 2     2   1006 use IPC::Open3 'open3';
  2         8389  
  2         124  
14 2     2   15 use Symbol 'gensym';
  2         4  
  2         76  
15 2     2   13 use Test2::API 'context';
  2         4  
  2         79  
16 2     2   12 use Test2::Tools::Compare;
  2         4  
  2         95  
17              
18 2     2   11 use base 'Exporter';
  2         5  
  2         1637  
19             our @EXPORT = qw(command);
20              
21             our @command; # prefixed on each run, followed by any ->{args}
22             our $timeout = 30; # seconds, for alarm()
23              
24             sub command ($) {
25 7 100   7 1 7136 local $CWD = $_[0]->{chdir} if defined $_[0]->{chdir};
26 6         118 local @ENV{ keys %{ $_[0]->{env} } } = values %{ $_[0]->{env} };
  6         35  
  6         34  
27              
28 6 100       45 my @cmd = ( @command, exists $_[0]->{args} ? @{ $_[0]->{args} } : () );
  5         24  
29              
30 6         16 my ( $stdout, $stderr );
31 6 100       11 eval {
32 6     1   173 local $SIG{ALRM} = sub { die "timeout\n" };
  1         354  
33 6   66     94 alarm( $_[0]->{timeout} || $timeout );
34              
35 6         63 my $pid = open3( my $in, my $out, my $err = gensym, @cmd );
36 6 100       29565 if ( defined $_[0]->{binmode} ) {
37 1     1   40 for my $fh ( $in, $out, $err ) { binmode $fh, $_[0]->{binmode} }
  3         2374  
  1         29  
  1         6  
  1         27  
38             }
39 6 100       77 if ( exists $_[0]->{stdin} ) {
40 1         45 print $in $_[0]->{stdin};
41 1         20 close $in;
42             }
43 6         41 $stdout = do { local $/; readline $out };
  6         133  
  6         1026310  
44 5         428 $stderr = do { local $/; readline $err };
  5         37  
  5         230  
45 5         182 waitpid $pid, 0;
46 5         45 alarm 0;
47 5         512 1;
48             } or die $@;
49 5         77 my $orig_status = $?;
50             # the exit status is broken out into a hashref for exact tests on
51             # the various components of the 16-bit word (an alternative might be
52             # to mangle the value like the shell does)
53 5 50       105 my $status = {
54             code => $? >> 8,
55             signal => $? & 127,
56             iscore => $? & 128 ? 1 : 0
57             };
58             # the munge are for when the code or signal vary and you only want
59             # to know if the value was 0 or not
60 5 100       76 $status->{code} = $status->{code} ? 1 : 0 if $_[0]->{munge_status};
    100          
61 5 100       59 $status->{signal} = $status->{signal} ? 1 : 0 if $_[0]->{munge_signal};
    100          
62              
63             # default exit status word is 0, but need it in hashref form
64 5 100       26 if ( exists $_[0]->{status} ) {
65 3 100       38 if ( !defined $_[0]->{status} ) {
    100          
66 1         26 $_[0]->{status} = { code => 0, signal => 0, iscore => 0 };
67             } elsif ( ref $_[0]->{status} eq '' ) {
68 1         11 $_[0]->{status} = { code => $_[0]->{status}, signal => 0, iscore => 0 };
69             }
70             # assume that ->{status} is a hashref
71             } else {
72 2         33 $_[0]->{status} = { code => 0, signal => 0, iscore => 0 };
73             }
74              
75 5         105 my $ctx = context();
76 5   66     8998 my $name = $_[0]->{name} // "@cmd";
77 5         106 my $result = is $status, $_[0]->{status}, "exit - $name";
78             # qr// or assume it's a string
79 5 100 100     8353 if (defined $_[0]->{stdout} and ref $_[0]->{stdout} eq 'Regexp') {
80 1   33     29 $result ||= like $stdout, $_[0]->{stdout}, "stdout - $name";
81             } else {
82 4   0     12 $result ||= is $stdout, $_[0]->{stdout} // '', "stdout - $name";
      33        
83             }
84 5 100 100     57 if (defined $_[0]->{stderr} and ref $_[0]->{stderr} eq 'Regexp') {
85 1   33     9 $result ||= like $stderr, $_[0]->{stderr}, "stderr - $name";
86             } else {
87 4   0     13 $result ||= is $stderr, $_[0]->{stderr} // '', "stderr - $name";
      33        
88             }
89 5         22 $ctx->release;
90 5         243 return $result, $orig_status, \$stdout, \$stderr;
91             }
92              
93             1;
94             __END__