The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use warnings;
use strict;
use Test::More;
use Test::Exception;

use Async::Defer;


plan tests => 9;


my ($d);
my (@result);


# continue
# - correctly restart nearest while, with incremented iter()
# - correctly work inside if/try/catch/finally (inside while)
# - restart current Defer (with empty params) if used outside while
# - finally can replace current continue with throw/continue/break

$d = Async::Defer->new();
$d->while(sub{ $_[0]->iter() <= 3 });
    $d->do(sub{ push @result, 'i='.$_[0]->iter(); $_[0]->done() });
    $d->if(sub{ $_[0]->iter() == 2 });
        $d->try();
            $d->do(  sub{ push @result, 'do';
                          $_[0]->{op} eq 'do'      ? $_[0]->continue() : $_[0]->throw(); });
        $d->catch(
            qr//   =>sub{ push @result, 'ca';
                          $_[0]->{op} eq 'catch'   ? $_[0]->continue() : $_[0]->done(); },
            FINALLY=>sub{ push @result, 'fi';
                          $_[0]->{op} eq 'finally' ? $_[0]->continue() : $_[0]->done(); },
        );
    $d->end_if();
    $d->do(sub{ push @result, 'x'; $_[0]->done() });
$d->end_while();
($d->{op}, @result) = (q{}); $d->run();
is_deeply \@result, [qw(i=1 x i=2 do ca fi x i=3 x)], 'without continue';
($d->{op}, @result) = ('do'); $d->run();
is_deeply \@result, [qw(i=1 x i=2 do    fi   i=3 x)], 'continue inside if/try';
($d->{op}, @result) = ('catch'); $d->run();
is_deeply \@result, [qw(i=1 x i=2 do ca fi   i=3 x)], 'continue inside catch';
($d->{op}, @result) = ('finally'); $d->run();
is_deeply \@result, [qw(i=1 x i=2 do ca fi   i=3 x)], 'continue inside finally';

$d = Async::Defer->new();
$d->do(sub{ push @result, 'p='.($_[1]||q{}); $_[0]->done() });
$d->do(sub{ push @result, 'n='.++$_[0]->{n}; $_[0]->done() });
$d->do(sub{ $_[0]->{n} == 3 ? $_[0]->done() : $_[0]->continue() });
$d->do(sub{ push @result, 'x'; $_[0]->done() });
($d->{n}, @result) = (0); $d->run(undef, 10);
is_deeply \@result, [qw(p=10 n=1 p= n=2 p= n=3 x)],
    'restart current Defer (with empty params) if used outside while';

$d = Async::Defer->new();
$d->while(sub{ $_[0]->iter() <= 3 });
    $d->do(sub{ push @result, 'i='.$_[0]->iter(); $_[0]->done() });
    $d->try();
        $d->try();
            $d->do(sub{ push @result, 'a'; $_[0]->done() });
            $d->do(sub{ $_[0]->continue(); });
            $d->do(sub{ push @result, 'b'; $_[0]->done() });
        $d->catch(
            qr//   =>sub{ push @result, 'c1'; $_[0]->done(); },
            FINALLY=>sub{ push @result, 'f1';
                          $_[0]->{op} eq 'throw' ? $_[0]->throw()
                        : $_[0]->{op} eq 'continue'  ? $_[0]->continue()
                        : $_[0]->{op} eq 'break'  ? $_[0]->break()
                        :                          $_[0]->done(); },
        );
    $d->catch(
        qr//   =>sub{ push @result, 'c2'; $_[0]->done(); },
        FINALLY=>sub{ push @result, 'f2'; $_[0]->done(); },
    );
    $d->do(sub{ push @result, 'x'; $_[0]->done() });
$d->end_while();
($d->{op}, @result) = (q{}); $d->run();
is_deeply \@result, [qw(i=1 a f1 f2 i=2 a f1 f2 i=3 a f1 f2)],
    'finally do not replace current continue';
($d->{op}, @result) = ('throw'); $d->run();
is_deeply \@result, [qw(i=1 a f1 c2 f2 x i=2 a f1 c2 f2 x i=3 a f1 c2 f2 x)],
    'finally can replace current continue with throw';
($d->{op}, @result) = ('continue'); $d->run();
is_deeply \@result, [qw(i=1 a f1 f2 i=2 a f1 f2 i=3 a f1 f2)],
    'finally can replace current continue with continue';
($d->{op}, @result) = ('break'); $d->run();
is_deeply \@result, [qw(i=1 a f1 f2)],
    'finally can replace current continue with break';