1#!/usr/bin/perl
2
3use v5.10;
4use strict;
5use warnings;
6
7use Test::More;
8use Test::Refcount;
9
10use Future;
11
12# catch success
13{
14   my $f1 = Future->new;
15
16   my $fseq = $f1->catch(
17      test => sub { die "catch of successful Future should not be invoked" },
18   );
19
20   ok( defined $fseq, '$fseq defined' );
21   isa_ok( $fseq, "Future", '$fseq' );
22
23   is_oneref( $fseq, '$fseq has refcount 1 initially' );
24
25   $f1->done( results => "here" );
26
27   is_deeply( [ $fseq->result ], [ results => "here" ], '$fseq succeeds when $f1 succeeds' );
28
29   undef $f1;
30   is_oneref( $fseq, '$fseq has refcount 1 before EOF' );
31}
32
33# catch matching failure
34{
35   my $f1 = Future->new;
36
37   my $f2;
38   my $fseq = $f1->catch(
39      test => sub {
40         is( $_[0], "f1 failure\n", 'catch block passed result of $f1' );
41         return $f2 = Future->done;
42      },
43   );
44
45   ok( defined $fseq, '$fseq defined' );
46   isa_ok( $fseq, "Future", '$fseq' );
47
48   is_oneref( $fseq, '$fseq has refcount 1 initially' );
49
50   $f1->fail( "f1 failure\n", test => );
51
52   undef $f1;
53   is_oneref( $fseq, '$fseq has refcount 1 after $f1 fail and dropped' );
54
55   ok( defined $f2, '$f2 now defined after $f1 fails' );
56
57   ok( $fseq->is_ready, '$fseq is done after $f2 done' );
58}
59
60# catch non-matching failure
61{
62   my $f1 = Future->new;
63
64   my $fseq = $f1->catch(
65      test => sub { die "catch of non-matching Failure should not be invoked" },
66   );
67
68   $f1->fail( "f1 failure\n", different => );
69
70   ok( $fseq->is_ready, '$fseq is done after $f1 fail' );
71   is( scalar $fseq->failure, "f1 failure\n", '$fseq failure' );
72}
73
74# catch default handler
75{
76   my $fseq = Future->fail( "failure", other => )
77      ->catch(
78         test => sub { die "'test' catch should not match" },
79         sub { Future->done( default => "handler" ) },
80      );
81
82   is_deeply( [ $fseq->result ], [ default => "handler" ],
83      '->catch accepts a default handler' );
84}
85
86# catch_with_f
87{
88   my $f1 = Future->new;
89
90   my $fseq = $f1->catch_with_f(
91      test => sub {
92         identical( $_[0], $f1, '$f1 passed to catch code' );
93         is( $_[1], "f1 failure\n", '$f1 failure message passed to catch code' );
94         Future->done;
95      },
96   );
97
98   ok( defined $fseq, 'defined $fseq' );
99   isa_ok( $fseq, "Future", '$fseq' );
100
101   $f1->fail( "f1 failure\n", test => );
102
103   ok( $fseq->is_ready, '$fseq is done after $f1 fail' );
104}
105
106# catch via 'then'
107{
108   is( scalar ( Future->fail( "message", test => )
109            ->then( sub { die "then &done should not be invoked" },
110               test => sub { Future->done( 1234 ) },
111               sub { die "then &fail should not be invoked" } )->result ),
112      1234, 'catch semantics via ->then' );
113}
114
115# catch via 'then_with_f'
116{
117   my $f1 = Future->new;
118
119   my $fseq = $f1->then_with_f(
120      sub { die "then &done should not be invoked" },
121      test => sub {
122         identical( $_[0], $f1, '$f1 passed to catch code' );
123         is( $_[1], "f1 failure\n", '$f1 failure message passed to catch code' );
124         Future->done;
125      }
126   );
127
128   $f1->fail( "f1 failure\n", test => );
129
130   ok( $fseq->is_ready, '$fseq is done after $f1 fail' );
131}
132
133done_testing;
134