#!/usr/bin/perl

use strict;
use warnings;

use Test::More;

use Future::Buffer;

use Future;

my @next_fill_f;

my $buf = Future::Buffer->new(
   fill => sub { push @next_fill_f, my $f = Future->new; return $f },
);

# A quiescent buffer does not yet invoke fill
ok( !@next_fill_f, 'fill not yet invoked before any ->read_atmost' );

# A ->read_atmost call invokes fill to provide data
{
   my $read_f = $buf->read_atmost( 128 );

   ok( @next_fill_f, 'fill invoked after ->read_atmost' );
   ok( !$read_f->is_ready, '->read_atmost not yet ready' );

   ( shift @next_fill_f )->done( "abcd" );

   is( $read_f->get, "abcd", '->read_atmost yields data after fill' );
   ok( !@next_fill_f, 'fill not yet invoked again' );
}

# Two queued ->reads can see one round of fill
{
   my $read1 = $buf->read_atmost( 2 );
   my $read2 = $buf->read_atmost( 2 );

   ok( @next_fill_f, 'fill invoked after two reads' );

   ( shift @next_fill_f )->done( "efgh" );

   is( $read1->get, 'ef', 'first of two ->reads yields data after fill' );
   is( $read2->get, 'gh', 'second of two ->reads yields data after fill' );
}

# One long read will invoke multiple fills
{
   my $read_f = $buf->read_exactly( 4 );

   ( shift @next_fill_f )->done( "i" );
   ( shift @next_fill_f )->done( "j" );
   ( shift @next_fill_f )->done( "kl" );

   is( $read_f->get, "ijkl", '->read_atmost yields combined results of multiple fills' );
}

# fill future is used as prototype for read futures
{
   my $buf = Future::Buffer->new(
      fill => sub { return Some::Future::Subclass->new },
   );

   my $f = $buf->read_atmost( 1 );
   isa_ok( $f, "Some::Future::Subclass", '$f' );
}

done_testing;

package Some::Future::Subclass;
use base qw( Future );