diff --git a/lib/Test/MockFile.pm b/lib/Test/MockFile.pm index 6c5d4cf..03eef33 100644 --- a/lib/Test/MockFile.pm +++ b/lib/Test/MockFile.pm @@ -4101,6 +4101,7 @@ sub __rename ($$) { delete $files_being_mocked{$key}; $files_being_mocked{$new_key} = $child; + Scalar::Util::weaken( $files_being_mocked{$new_key} ); $child->{'path'} = $new_key; # Update autovivify tracking for child directories diff --git a/t/rename.t b/t/rename.t index 439da47..bd07bc4 100644 --- a/t/rename.t +++ b/t/rename.t @@ -8,6 +8,7 @@ use Test2::Tools::Explain; use Test2::Plugin::NoWarnings; use Errno qw/ENOENT EISDIR ENOTDIR ENOTEMPTY/; +use Scalar::Util qw/isweak/; use Test::MockFile qw< nostrict >; @@ -227,6 +228,23 @@ note "-------------- rename: directory DESTROY cleanup works after rename ------ ok( -e '/mock/dtor2/f.txt', 'child accessible before DESTROY' ); } +note "-------------- rename: re-keyed children keep weak refs in files_being_mocked --------------"; +{ + my $dir = Test::MockFile->new_dir('/mock/weaktest'); + my $child = Test::MockFile->file( '/mock/weaktest/w.txt', 'data' ); + my $dest = Test::MockFile->dir('/mock/weaktest2'); + + ok( rename( '/mock/weaktest', '/mock/weaktest2' ), 'rename for weakref test' ); + + ok( isweak( $Test::MockFile::files_being_mocked{'/mock/weaktest2/w.txt'} ), + 'child entry in files_being_mocked is weakened after directory rename' ); + + # When user drops the reference, mock should be garbage collected + undef $child; + ok( !defined $Test::MockFile::files_being_mocked{'/mock/weaktest2/w.txt'}, + 'child mock is garbage collected after user drops reference' ); +} + note "-------------- rename: preserves inode and nlink --------------"; { my $old = Test::MockFile->file( '/mock/ino_old', 'data', { inode => 42, nlink => 3 } );