#!perl
use warnings;
use strict;
use Test::More tests => 41;
use lib 't'; use Utils;
use File::Temp qw/tempfile/;
use Encode qw/decode_utf8/;

BEGIN { use_ok('Feersum') };

my ($socket,$port) = get_listen_socket();
ok $socket, "made listen socket";

my $evh = Feersum->new();
{
    no warnings 'redefine';
    *Feersum::DIED = sub {
        my $err = shift;
        fail "Died during request handler: $err";
    };
}
$evh->use_socket($socket);

{
    package FakeIOHandle;
    sub new { return bless {lines => $_[1]}, __PACKAGE__ }
    sub getline {
        my $self = shift;
        Test::More::ok(ref($/) && ${$/} == 4096, '$/ is \4096');
        return @{$self->{lines}} ? shift @{$self->{lines}} : undef;
    }
    sub close {
        Test::More::pass("called close");
    }
}

my $APP = <<'EOAPP';
    my $app = sub {
        my $env = shift;
        Test::More::pass "called app";
        my $io = FakeIOHandle->new([
            "line one\n",
            "line two\n"
        ]);
        return [200,['Content-Type'=>'text/plain'],$io];
    };
EOAPP

my $app = eval $APP;
ok $app, 'got an app' || diag $@;
$evh->psgi_request_handler($app);

returning_mock: {
    my $cv = AE::cv;

    $cv->begin;
    my $h; $h = simple_client GET => '/', sub {
        my ($body, $headers) = @_;
        is $headers->{'Status'}, 200, "Response OK";
        is $headers->{'content-type'}, 'text/plain';
        is $body, qq(line one\nline two\n);
        $cv->end;
        undef $h;
    };

    $cv->recv;
    pass "all done app 1";
}

my ($tempfh, $tempname) = tempfile(UNLINK=>1);
print $tempfh "temp line one\n";
print $tempfh "temp line two\n";
close $tempfh;

my $APP2 = <<'EOAPP';
    my $app2 = sub {
        my $env = shift;
        Test::More::pass "called app2";
        open my $io, '<', $tempname;
        return [200,['Content-Type'=>'text/plain'],$io];
    };
EOAPP

my $app2 = eval $APP2;
ok $app2, 'got app 2' || diag $@;
$evh->psgi_request_handler($app2);

returning_glob: {
    my $cv = AE::cv;
    $cv->begin;
    my $h; $h = simple_client GET => '/', sub {
        my ($body, $headers) = @_;
        is $headers->{'Status'}, 200, "Response OK";
        is $headers->{'content-type'}, 'text/plain';
        is $body, qq(temp line one\ntemp line two\n);
        $cv->end;
        undef $h;
    };
    $cv->recv;
}

pass "all done app 2";

my $APP3 = <<'EOAPP';
    my $app3 = sub {
        my $env = shift;
        Test::More::pass "called app3";
        require IO::File;
        my $io = IO::File->new($tempname,"r");
        return [200,['Content-Type'=>'text/plain'],$io];
    };
EOAPP

my $app3 = eval $APP3;
ok $app3, 'got app 3' || diag $@;
$evh->psgi_request_handler($app3);

returning_io_file: {
    my $cv = AE::cv;
    $cv->begin;
    my $h; $h = simple_client GET => '/', sub {
        my ($body, $headers) = @_;
        is $headers->{'Status'}, 200, "Response OK";
        is $headers->{'content-type'}, 'text/plain', "C-T";
        is $body, qq(temp line one\ntemp line two\n), "body";
        $cv->end;
        undef $h;
    };
    $cv->recv;
}

pass "all done app 3";

{
    open my $fh, '>:encoding(UTF-16LE)',$tempname;
    print $fh "\x{2603}\n"; # U+2603 SNOWMAN, UTF-8: E2 98 83
    close $fh;
}

my $APP4 = <<'EOAPP';
    my $app4 = sub {
        my $env = shift;
        Test::More::pass "called app4";
        open my $io, '<:encoding(UTF-16LE)',$tempname;
        return [200,['Content-Type'=>'text/plain; charset=UTF-8'],$io];
    };
EOAPP

my $app4 = eval $APP4;
ok $app4, 'got app 4' || diag $@;
$evh->psgi_request_handler($app4);

returning_perlio_layer: {
    my $cv = AE::cv;
    $cv->begin;
    my $h; $h = simple_client GET => '/', sub {
        my ($body, $headers) = @_;
        is $headers->{'Status'}, 200, "Response OK";
        is $headers->{'content-type'}, 'text/plain; charset=UTF-8', "C-T";
        is decode_utf8($body), qq(\x{2603}\n), "utf8 body";
        $cv->end;
        undef $h;
    };
    $cv->recv;
}

pass "all done app 4";

my $APP5 = <<'EOAPP';
    my $app5 = sub {
        my $env = shift;
        Test::More::pass "called app5";
        return sub {
            my $responder = shift;
            open my $io, '<:encoding(UTF-16LE)',$tempname;
            $responder->([
                200,['Content-Type'=>'text/plain; charset=UTF-8'],$io
            ]);
        };
    };
EOAPP

my $app5 = eval $APP5;
ok $app5, 'got app 5' || diag $@;
$evh->psgi_request_handler($app5);

returning_perlio_layer_from_stream: {
    my $cv = AE::cv;
    $cv->begin;
    my $h; $h = simple_client GET => '/', sub {
        my ($body, $headers) = @_;
        is $headers->{'Status'}, 200, "Response OK";
        is $headers->{'content-type'}, 'text/plain; charset=UTF-8', "C-T";
        is decode_utf8($body), qq(\x{2603}\n), "utf8 body from streamer";
        $cv->end;
        undef $h;
    };
    $cv->recv;
}

pass "all done app 5";
