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