#!/usr/bin/perl

use v5.14;
use warnings;

use Test2::V0;

use Future;

use Future::AsyncAwait;

my $orig_cxstack_ix = Future::AsyncAwait::__cxstack_ix;

my $f;
my $failure;

async sub inner
{
   my $ret = await $f;
   die $failure if defined $failure;
   return $ret;
}

async sub outer
{
   await inner();
}

# await through two nested async sub calls
# See also RT123062
{
   $f = Future->new;

   my $fret = outer();
   $f->done( "value" );

   is( scalar $fret->get, "value", '$fret->get through two nested async subs' );
}

# die after double await
# See also RT126037
{
   $f = Future->new;

   my $fret = outer();
   $failure = "Oopsie\n";

   $f->done( "result" );

   is( scalar $fret->failure, "Oopsie\n", '$fret->failure through two nested async subs' );
}

# await through two nested async method calls
{
   my $f = Future->new;

   package TestObj {
      async sub inner {
         await $f;
      }

      async sub outer {
         my $mth = "inner";
         await shift->$mth;
      }
   }

   my $fret = TestObj->outer();
   $f->done( "value" );

   is( scalar $fret->get, "value", '$fret->get through two nested async methods' );
}

# await twice nested
{
   my @f;

   async sub f2
   {
      await $f[0];
   }

   async sub f1
   {
      await f2();
      await f2();
   }

   @f = map { Future->new } 1 .. 2;
   my $fret = f1();
   ( shift @f )->done( "result" ) while @f;

   is( scalar $fret->get, "result", '$fret->get through nested double wait' );
}

# nested failure
{
    my $f = Future->new;

    async sub func_fail {
        await $f;
    }
    async sub func_fail_wrap {
        await func_fail();
    }

    my $fret = func_fail_wrap();
    $f->fail("aiee\n");

    is( $fret->failure, "aiee\n", "nested fail" );
}

is( Future::AsyncAwait::__cxstack_ix, $orig_cxstack_ix,
   'cxstack_ix did not grow during the test' );

done_testing;
