#!perl
use strict;
use warnings;

use Test qw( plan );
use IPC::Run3;

my ( $in, $out, $err ) = @_;

my %e = (
    map( { chr $_ => sprintf( "\\0x%02d", $_ ) } (0..255) ),
    "\n" => "\\n",
    "\r" => "\\r",
);

sub ok {
    @_ = map { ( my $s = $_ ) =~ s/([\000-\037])/$e{$1}/ge; $s } @_;
    goto &Test::ok;
}

my @tests = (
sub {
    eval { run3 };
    ok $@;
},

sub {
    ( $in, $out, $err ) = ();
    run3 [$^X, '-e', 'print "OUT"' ], \undef, \$out, \$err;
    ok $out, "OUT";
},

sub {
    ok $err, "";
},

sub {
    ( $in, $out, $err ) = ();
    $out = "STUFF";
    run3 [$^X, '-e', 'print "OUT"' ], \undef, \$out, \$err, { append_stdout => 1 };
    ok $out, "STUFFOUT";
},

sub {
    ( $in, $out, $err ) = ();
    $err = "STUFF";
    run3 [$^X, '-e', 'print STDERR "OUT"' ], \undef, \$out, \$err, { append_stderr => 1 };
    ok $out, "";
},

sub {
    ok $err, "STUFFOUT";
},

sub {
    ( $in, $out, $err ) = ();
    run3 [$^X, '-e', 'print map uc, <>' ], \"in", \$out, \$err;
    ok $out, "IN";
},

sub {
    ok $err, "";
},

sub {
    ( $in, $out, $err ) = ();
    run3 [$^X, '-e', 'print STDERR map uc, <>' ], \"in", \$out, \$err;
    ok $out, "";
},

sub {
    ok $err, "IN";
},

sub {
    ( $in, $out, $err ) = ();
    run3 [$^X, '-e', 'print map uc, <>' ], [qw( in1 in2 )], \$out;
    ok $out, "IN1IN2";
},

sub {
    ( $in, $out, $err ) = ();
    my @ary;
    run3 [$^X, '-e', 'print map uc, <>' ], [qw( in1 in2 )], \$out;
    ok $out, "IN1IN2";
},

sub {
    ( $in, $out, $err ) = ();
    my @out;
    run3 [$^X, '-e', 'print "OUT1\nOUT2"' ], \undef, \@out, \$err;
    ok scalar(@out), 2;
    $out = join('', @out);
},
sub {
    ok $out, "OUT1\nOUT2";
},

sub {
    ( $in, $out, $err ) = ();
    my @out = ("STUFF\n");
    run3 [$^X, '-e', 'print "OUT1\nOUT2"' ], \undef, \@out, \$err, { append_stdout => 1 };
    ok scalar(@out), 3;
    $out = join('', @out);
},
sub {
    ok $out, "STUFF\nOUT1\nOUT2";
},

sub {
    ( $in, $out, $err ) = ();
    run3 [$^X, '-e', 'print map { length($_)."[$_]" } <>' ], \"in1\nin2", \$out;
    ok $out, "4[in1\n]3[in2]";
},

sub {
    ( $in, $out, $err ) = ();
    run3 [$^X, '-e', 'binmode STDIN; binmode STDOUT; print map { length($_)."[$_]" } <>' ],
        \"in1\nin2", \$out,
        { binmode_stdin => 1 };
    ok $out, "4[in1\n]3[in2]";
},

sub {
    ( $in, $out, $err ) = ();
    run3 [$^X, '-e', 'binmode STDIN; binmode STDOUT; print map { length($_)."[$_]" } <>' ],
        \"in1\r\nin2", \$out,
        { binmode_stdin => 1, binmode_stdout => 1 };
    ok $out, "5[in1\r\n]3[in2]";
},

sub {
    ( $in, $out, $err ) = ();
    my @in = qw( in1 in2 );
    run3 [$^X, '-e', 'print map uc, <>' ], sub { shift @in }, \$out;
    ok $out, "IN1IN2";
},

sub {
    ( $in, $out, $err ) = ();
    my @out;
    run3 [$^X, '-e', 'print map uc, <>' ], \"in1\nin2", sub { push @out, shift };
    ok scalar(@out), 2;
    $out = join('', @out);
},
sub {
    ok $out, "IN1\nIN2";
},

sub {
    ( $in, $out, $err ) = ();
    run3 [$^X, '-e',
        '$|=1; select STDERR; $| = 1; for (<>){print STDOUT uc;print STDERR lc}'
    ], \"in1\nin2\n", \$out,\$out;
    ok $out, "IN1\nin1\nIN2\nin2\n";
},

sub {
    my $fn = "t/test.txt";
    unlink $fn or warn "$! unlinking $fn" if -e $fn;

    ( $in, $out, $err ) = ();
    run3 [$^X, '-e', 'print "OUT"' ], \undef, $fn;
    ok -s $fn, 3;
},

sub {
    my $fn = "t/test.txt";
    unlink $fn or warn "$! unlinking $fn" if -e $fn;
    open FH, ">", $fn  or warn "$! opening $fn";
    print FH "STUFF";
    close FH;

    ( $in, $out, $err ) = ();
    run3 [$^X, '-e', 'print "OUT"' ], \undef, $fn, { append_stdout => 1 };
    ok -s $fn, 8;
},

sub {
    my $fn = "t/test.txt";
    open FH, ">", $fn or warn "$! opening $fn";

    ( $in, $out, $err ) = ();
    run3 [$^X, '-e', 'print "OUT"' ], \undef, \*FH;

    close FH;
    ok -s $fn, 3;
},

sub {
    my $fn = "t/test.txt";
    unlink $fn or warn "$! unlinking $fn" if -e $fn;
    open FH, ">", $fn or warn "$! opening $fn";
    print FH "IN1\nIN2\n";
    close FH;

    open FH, "<", $fn or warn "$! opening $fn";

    ( $in, $out, $err ) = ();
    run3 [$^X, '-e', 'print <>' ], \*FH, \$out;

    close FH;
    ok $out, "IN1\nIN2\n";
},

# check that run3 doesn't die on platforms where system()
# returns -1 when SIGCHLD is ignored (RT #14272)
sub {
  use Config;

  if ( $^O eq 'openbsd' and $Config{'useithreads'} ) {
    ok(1); # Bug in OpenBSD threaded perls causes a hang
  }
  else {

      my $system_child_error = eval
      {
        local $SIG{CHLD} = "IGNORE";
        system $^X, '-e', 0;
        $?;
      };
      my $run3_child_error = eval
      {
        local $SIG{CHLD} = "IGNORE";
        run3 [ $^X, '-e', 0 ], \undef, \undef, \undef, { return_if_system_error => 1 };
        $?;
      };
      ok $run3_child_error, $system_child_error;

  }
},


sub {
  ($in, $out, $err) = ();
  eval { run3 [ $^X, '-e', 'BEGIN { die }' ], \$in, \$out, \$err };
  ok $@, '';
},

sub {
  ($in, $out, $err) = ();
  eval { run3 [ $^X, '-e', 'print STDOUT "stdout"; print STDERR "stderr"; exit 255;' ], \$in, \$out, \$err };
  ok $@, '';
},

sub {
  ok $out, "stdout";
},

sub {
  ok $err, "stderr";
},

sub {
  ok $? >> 8, 255;
},

);

plan tests => 0+@tests;

$_->() for @tests;
