#!/usr/bin/perl -w

=head1 DESCRIPTION

This test is modified of the iterators.t of the Test-Harness distribution to test the L<TAP::Parser::Iterator::Worker>.

=cut

use strict;

use Test::More tests => 23;

use File::Spec;
use TAP::Parser;
use TAP::Parser::Iterator::Array;
use TAP::Parser::Iterator::Stream;
use TAP::Parser::Iterator::Process;
use TAP::Parser::Iterator::Worker;
use TAP::Parser::Iterator::Stream::Selectable;
use Config;
use Sys::Hostname;
use IO::Socket::INET;

my $listener = IO::Socket::INET->new(
    Listen => 5,
    Proto  => 'tcp'
);
ok($listener, 'got a socket');
my $spec =
  ( $listener->sockhost eq '0.0.0.0' ? hostname : $listener->sockhost ) . ':'
  . $listener->sockport;

my @schedule = (
    {
        name       => 'Worker',
        class      => 'TAP::Parser::Iterator::Worker',
        subclass   => 'TAP::Parser::Iterator::Worker',
        source     => { spec => $spec, },
        file       => File::Spec->catfile( 't', 'sample-tests', 'out_err_mix' ),
        need_open3 => 15,
    },
);

sub _can_open3 {
    return $Config{d_fork};
}

for my $test (@schedule) {
  SKIP: {
        my $name       = $test->{name};
        my $need_open3 = $test->{need_open3};
        skip "No open3", $need_open3 if $need_open3 && !_can_open3();
        my $subclass = $test->{subclass};
        my $source   = $test->{source};
        my $class    = $test->{class};
        my $worker_iterator =
            $class
          ? $class->new($source)
          : make_iterator($source);

        my $worker = $listener->accept();

        #LSF: Must have end of line.
        $worker->print( $test->{file} . "\n" );
        my $iterator = TAP::Parser::Iterator::Stream::Selectable->new(
            { handle => $worker } );
        ok $iterator, "$name: We should be able to create a new iterator";
        isa_ok $worker_iterator, 'TAP::Parser::Iterator',
          '... and the object it returns';
        isa_ok $iterator, 'TAP::Parser::Iterator',
          '... and the object it returns';
        isa_ok $worker_iterator, $subclass, '... and the object it returns';
        isa_ok $iterator, 'TAP::Parser::Iterator::Stream::Selectable',
          '... and the object it returns';

        can_ok $iterator, 'exit';
        is $iterator->next, 'one',
          "$name: next() should return the first result";

        is $iterator->next, 'two',
          "$name: next() should return the second result";

        is $iterator->next, '', "$name: next() should return the third result";

        is $iterator->next, 'three',
          "$name: next() should return the fourth result";

        ok !defined $iterator->next,
          "$name: next() should return undef after it is empty";

        is $iterator->exit, 0,
          "$name: ... and exit should now return 0 ($subclass)";

        is $iterator->wait, 0,
          "$name: wait should also now return 0 ($subclass)";

        if ( my $after = $test->{after} ) {
            $after->();
        }
    }
}

{

    # coverage tests for the ctor

    my $iterator = make_iterator( IO::Handle->new );

    isa_ok $iterator, 'TAP::Parser::Iterator::Stream';

    my @die;

    eval {
        local $SIG{__DIE__} = sub { push @die, @_ };
        make_iterator( \1 );    # a ref to a scalar
    };

    is @die, 1, 'coverage of error case';

    like pop @die, qr/Can't iterate with a SCALAR/,
      '...and we died as expected';
}

{

    # coverage test for VMS case

    my $iterator = make_iterator( [ 'not ', 'ok 1 - I hate VMS', ] );

    is $iterator->next, 'not ok 1 - I hate VMS',
      'coverage of VMS line-splitting case';

    # coverage test for VMS case - nothing after 'not'

    $iterator = make_iterator( [ 'not ', ] );

    is $iterator->next, 'not ', '...and we find "not" by itself';
}

SKIP: {
    skip "No open3", 4 unless _can_open3();

    # coverage testing for TAP::Parser::Iterator::Process ctor

    my @die;

    eval {
        local $SIG{__DIE__} = sub { push @die, @_ };
        make_iterator( {} );
    };

    is @die, 1, 'coverage testing for TPI::Process';

    like pop @die, qr/Must supply a command to execute/,
      '...and we died as expected';

    my $parser = make_iterator(
        {
            command => [
                $^X, File::Spec->catfile( 't', 'sample-tests', 'out_err_mix' )
            ],
            merge => 1,
        }
    );

    is $parser->{err}, '',    'confirm we set err to empty string';
    is $parser->{sel}, undef, '...and selector to undef';

    # And then we read from the parser to sidestep the Mac OS / open3
    # bug which frequently throws an error here otherwise.
    $parser->next;
}

sub make_iterator {
    my $thing = shift;
    my $ref   = ref $thing;
    if ( $ref eq 'GLOB' || UNIVERSAL::isa( $ref, 'IO::Handle' ) ) {
        return TAP::Parser::Iterator::Stream->new($thing);
    }
    elsif ( $ref eq 'ARRAY' ) {
        return TAP::Parser::Iterator::Array->new($thing);
    }
    elsif ( $ref eq 'HASH' ) {
        return TAP::Parser::Iterator::Process->new($thing);
    }
    else {
        die "Can't iterate with a $ref";
    }
}

1;
