The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use Forks::Super ':test';
use Test::More tests => 37;
use strict;
use warnings;

if ($^O eq 'MSWin32') {
    Forks::Super::Config::CONFIG_module("Win32::API");
    if ($Win32::API::VERSION && $Win32::API::VERSION < 0.71) {
	warn qq[

Win32::API v$Win32::API::VERSION found. v>=0.71 may be required
to pass this test and use the features exercised by this test.

];
    }
}

for my $stdfh (*STDOUT, *STDERR) {
    if ($] >= 5.007) {
        binmode $stdfh, $^O eq 'MSWin32' ? ':utf8' : ':encoding(UTF-8)';
    }
}

my @cmd = ($^X, "t/external-command.pl",
	   "-e=Hello", "-s=4", "-y=1", "-e=whirled");

my ($fh_in, $fh_out, $pid, $job) = Forks::Super::open2(@cmd);

ok(defined($fh_in) && defined($fh_out), "open2: child fh available");
ok(isValidPid($pid), "open2: valid pid $pid");
sleep 2;
ok(defined($job), "open2: received job object");
ok($job->{state} eq 'ACTIVE', "open2: job is active " . $job->{state});

my $msg = sprintf "%05x", rand() * 99999;
my $z = print {$fh_in} "$msg\n";
Forks::Super::close_fh($pid,'stdin');
ok($z > 0, "open2: print to input handle ok = $z");
for (1..10) {
    Forks::Super::Util::pause(1);
    last if $job->{state} eq 'COMPLETE';
}

my @out = Forks::Super::read_stdout($pid);
Forks::Super::close_fh($pid, 'stdout');
ok(@out == 2,                                                      ### 6 ###
   "open2: got right number of output lines 2 == " . scalar @out)
  or diag("Output was:\n@out\nExpected 2 lines");
ok($out[0] eq "Hello $msg\n", "got right output")                  ### 7 ###
  or diag("Got \"$out[0]\", expected \"Hello $msg\\n\"");
Forks::Super::pause();
ok($job->{state} eq 'COMPLETE', "job complete");
ok($pid == waitpid($pid,0), "job reaped");

######################################################

my $fh_err;
@cmd = ($^X, "t/external-command.pl",
	   "-e=Hello", "-s=4", "-y=3", "-e=whirled");
($fh_in, $fh_out, $fh_err, $pid, $job) = Forks::Super::open3(@cmd);
ok(defined($fh_in) && defined($fh_out) && defined($fh_err),
   "open3: child fh available");
ok(isValidPid($pid), "open3: valid pid $pid");
sleep 1;
ok(defined($job), "open3: received job object");
ok($job->{state} eq 'ACTIVE', "open3: job is active " . $job->{state});

$msg = sprintf "%05x", rand() * 99999;
$z = print $fh_in "$msg\n";
Forks::Super::close_fh($pid,'stdin');
ok($z > 0, "open3: print to input handle ok = $z");
for (1..10) {
    Forks::Super::Util::pause(1.0);
    last if $job->is_complete;
}

@out = Forks::Super::read_stdout($pid);
Forks::Super::close_fh($pid, 'stdout');

my @err = Forks::Super::read_stderr($pid);

if (!Forks::Super::Config::CONFIG('filehandles')) {
    @err = grep { !/set_signal_pid/ } @err;
}

Forks::Super::close_fh($pid, 'stderr');
ok(@out == 4, "open3: got right number of output lines")            ### 15 ###
  or diag("open3 output was:\n@out\nExpected 4 lines");
ok(@out>0 && $out[0] eq "Hello $msg\n", "got right output (1)")     ### 16 ###
  or diag("First output was \"$out[0]\", expected \"Hello $msg\\n\"");
ok(@out>1 && $out[1] eq "$msg\n", "got right output (2)")           ### 17 ###
  or diag("2nd output was \"$out[1]\", expected \"$msg\\n\"");
ok(@err == 1, "open3: got right error lines");                      ### 18 ###
ok(@err>0 && $err[0] eq "received message $msg\n",                  ### 19 ###
   "open3: got right error")
  or diag("Error was \"$err[0]\",\n",
	  "Expected \"received message $msg\\n\"");
Forks::Super::pause();
ok($job->{state} eq 'COMPLETE', 
   "job state " . $job->{state} . " == 'COMPLETE'");
ok($pid == waitpid($pid,0), "job reaped");

#############################################################################

sub mswin32diag { diag @_ if $^O eq 'MSWin32'; }

Forks::Super::Debug::use_Carp_Always();

@cmd = ($^X, "t/external-command.pl",
        "-e=Hello", "-s=19", "-y=3", "-e=whirled");
mswin32diag "starting FS::open3";
($fh_in, $fh_out, $fh_err, $pid, $job) 
    = Forks::Super::open3(@cmd, {timeout => 6});
mswin32diag "started FS::open3";    # timeout is Win32 failure point

ok(defined($fh_in) && defined($fh_out) && defined($fh_err),    ### 22 ###
   "open3: child fh available");
ok(defined($job), "open3: received job object");
ok($job->{state} eq 'ACTIVE', "open3: respects additional options");
mswin32diag 'checked job state';
sleep 1;
$msg = sprintf "%05x", rand() * 99999;
$z = print $fh_in "$msg\n";
mswin32diag 'wrote job input, z=', $z;
Forks::Super::close_fh($pid,'stdin');
mswin32diag 'closed job stdin';
ok($z > 0, "open3: print to input handle ok = $z"); 	       ### 25 ###

mswin32diag 'waiting for job to complete';
for (1..30) {
    Forks::Super::Util::pause(1.0);
    last if $job->is_complete;
    if ($_ == 30) {
	diag "open3 command still not complete after 30s";
    }
}
mswin32diag 'job is complete';

@out = <$fh_out>;
mswin32diag 'read stdout';
Forks::Super::close_fh($pid, 'stdout');
mswin32diag 'close stdout';
@err = <$fh_err>;
mswin32diag 'read stderr';
Forks::Super::close_fh($pid, 'stderr');
mswin32diag 'close stderr';
if (!Forks::Super::Config::CONFIG('filehandles')) {
    @err = grep { !/set_signal_pid/ } @err;
}

ok(@out == 1 && $out[0] =~ /^Hello/, 
   "open3: time out  \@out='@out'" . scalar @out);   ### 26 ###
ok(@err == 0 || $err[0] =~ /timeout/, "open3: job timed out")
    or diag("error was @err\n");
waitpid $pid,0;
ok($job->{status} != 0,
   "open3: job timed out status $job->{status}!=0")  ### 28 ###
    or diag("status was $job->{status}, expected ! 0");

#############################################################################

@cmd = ($^X, "t/external command.pl",
	   "-e=Hello", "-s=4", "-y=1", "-e=whirled");

($fh_in, $fh_out, $pid, $job) = Forks::Super::open2(@cmd);

ok(defined($fh_in) && defined($fh_out), "open2: child fh available (cmd w/meta)");
ok(isValidPid($pid), "open2: valid pid $pid (cmd w/meta)");
sleep 2;
ok(defined($job), "open2: received job object (cmd w/meta)");
ok($job->{state} eq 'ACTIVE', "open2: job is active " . $job->{state});

$msg = sprintf "%05x", rand() * 99999;
$z = print {$fh_in} "$msg\n";
Forks::Super::close_fh($pid,'stdin');
ok($z > 0, "open2: print to input handle ok = $z (cmd w/meta)");
for (1..10) {
    Forks::Super::Util::pause(1);
    last if $job->{state} eq 'COMPLETE';
}

@out = Forks::Super::read_stdout($pid);
Forks::Super::close_fh($pid, 'stdout');
ok(@out == 2,                                                      ### 34 ###
   "open2: got right number of output lines 2 == " . scalar @out)
  or diag("Output was:\n@out\nExpected 2 lines");
ok($out[0] eq "Hello $msg\n", "got right output")                  ### 35 ###
  or diag("Got \"$out[0]\", expected \"Hello $msg\\n\"");
Forks::Super::pause();
ok($job->{state} eq 'COMPLETE', "job complete (cmd w/meta)");
ok($pid == waitpid($pid,0), "job reaped (cmd w/meta)");

######################################################