On Thu Dec 25 09:10:15 2014, TEAM wrote:
Show quoted text> Since the test is only looking for Futures that were still pending
> after the block returns, how about removing futures from the list once
> they're no longer pending? Something like ->on_ready(extract_by { ...
> } @futures) in the local *Future::new wrapper, perhaps.
Yes.
Turns out the implementation is a little more complex due to the shortcut that ->done and ->fail as class constructors take; those need special handling.
Patch attached; will be in next release.
--
Paul Evans
=== modified file 'lib/Test/Future.pm'
--- lib/Test/Future.pm 2014-11-26 14:34:46 +0000
+++ lib/Test/Future.pm 2015-03-08 18:19:00 +0000
@@ -72,11 +72,35 @@
my @futures;
+ no warnings 'redefine';
+
my $new = Future->can( "new" );
- no warnings 'redefine';
local *Future::new = sub {
my $f = $new->(@_);
push @futures, $f;
+ $f->on_ready( sub {
+ my $f = shift;
+ for ( 0 .. $#futures ) {
+ refaddr( $futures[$_] ) == refaddr( $f ) or next;
+
+ splice @futures, $_, 1, ();
+ return;
+ }
+ });
+ return $f;
+ };
+
+ my $done = Future->can( "done" );
+ local *Future::done = sub {
+ my $f = $done->(@_);
+ pop @futures if !ref $_[0]; # class method
+ return $f;
+ };
+
+ my $fail = Future->can( "fail" );
+ local *Future::fail = sub {
+ my $f = $fail->(@_);
+ pop @futures if !ref $_[0]; # class method
return $f;
};
=== modified file 't/50test-future.t'
--- t/50test-future.t 2014-11-15 00:17:09 +0000
+++ t/50test-future.t 2015-03-08 18:17:12 +0000
@@ -4,6 +4,7 @@
use warnings;
use Test::More;
+use Test::Refcount;
use Test::Builder::Tester;
use Future;
@@ -41,6 +42,41 @@
$f->cancel;
}
+# does not retain Futures
+{
+ test_out( "ok 1 - refcount 2 before drop" );
+ test_out( "ok 2 - refcount 1 after drop" );
+ test_out( "ok 3 - retain" );
+
+ no_pending_futures {
+ my $arr = [1,2,3];
+ my $f = Future->new;
+ $f->done( $arr );
+ is_refcount( $arr, 2, 'refcount 2 before drop' );
+ undef $f;
+ is_refcount( $arr, 1, 'refcount 1 after drop' );
+ } 'retain';
+
+ test_test( "no_pending_futures does not retain completed Futures" );
+}
+
+# does not retain immedate Futures
+{
+ test_out( "ok 1 - refcount 2 before drop" );
+ test_out( "ok 2 - refcount 1 after drop" );
+ test_out( "ok 3 - retain" );
+
+ no_pending_futures {
+ my $arr = [1,2,3];
+ my $f = Future->done( $arr );
+ is_refcount( $arr, 2, 'refcount 2 before drop' );
+ undef $f;
+ is_refcount( $arr, 1, 'refcount 1 after drop' );
+ } 'retain';
+
+ test_test( "no_pending_futures does not retain immediate Futures" );
+}
+
END {
# Clean up Devel::MAT dumpfile
my $pmat = $0;