#!./perl use strict; use Config; BEGIN { unless (-d 'blib') { chdir 't' if -d 't'; @INC = '../lib'; keys %Config; # Silence warning if ($Config{extensions} !~ /\bList\/Util\b/) { print "1..0 # Skip: List::Util was not built\n"; exit 0; } } } use Scalar::Util (); use Test::More ((grep { /weaken/ } @Scalar::Util::EXPORT_FAIL) and !$ENV{PERL_CORE}) ? (skip_all => 'weaken requires XS version') : (tests => 22); if (0) { require Devel::Peek; Devel::Peek->import('Dump'); } else { *Dump = sub {}; } Scalar::Util->import(qw(weaken isweak)); if(1) { my ($y,$z); # # Case 1: two references, one is weakened, the other is then undef'ed. # { my $x = "foo"; $y = \$x; $z = \$x; } print "# START\n"; Dump($y); Dump($z); ok( ref($y) and ref($z)); print "# WEAK:\n"; weaken($y); Dump($y); Dump($z); ok( ref($y) and ref($z)); print "# UNDZ:\n"; undef($z); Dump($y); Dump($z); ok( not (defined($y) and defined($z)) ); print "# UNDY:\n"; undef($y); Dump($y); Dump($z); ok( not (defined($y) and defined($z)) ); print "# FIN:\n"; Dump($y); Dump($z); # # Case 2: one reference, which is weakened # print "# CASE 2:\n"; { my $x = "foo"; $y = \$x; } ok( ref($y) ); print "# BW: \n"; Dump($y); weaken($y); print "# AW: \n"; Dump($y); ok( not defined $y ); print "# EXITBLOCK\n"; } # # Case 3: a circular structure # my $flag = 0; { my $y = bless {}, 'Dest'; Dump($y); print "# 1: $y\n"; $y->{Self} = $y; Dump($y); print "# 2: $y\n"; $y->{Flag} = \$flag; print "# 3: $y\n"; weaken($y->{Self}); print "# WKED\n"; ok( ref($y) ); print "# VALS: HASH ",$y," SELF ",\$y->{Self}," Y ",\$y, " FLAG: ",\$y->{Flag},"\n"; print "# VPRINT\n"; } print "# OUT $flag\n"; ok( $flag == 1 ); print "# AFTER\n"; undef $flag; print "# FLAGU\n"; # # Case 4: a more complicated circular structure # $flag = 0; { my $y = bless {}, 'Dest'; my $x = bless {}, 'Dest'; $x->{Ref} = $y; $y->{Ref} = $x; $x->{Flag} = \$flag; $y->{Flag} = \$flag; weaken($x->{Ref}); } ok( $flag == 2 ); # # Case 5: deleting a weakref before the other one # my ($y,$z); { my $x = "foo"; $y = \$x; $z = \$x; } print "# CASE5\n"; Dump($y); weaken($y); Dump($y); undef($y); ok( not defined $y); ok( ref($z) ); # # Case 6: test isweakref # $a = 5; ok(!isweak($a)); $b = \$a; ok(!isweak($b)); weaken($b); ok(isweak($b)); $b = \$a; ok(!isweak($b)); my $x = {}; weaken($x->{Y} = \$a); ok(isweak($x->{Y})); ok(!isweak($x->{Z})); # # Case 7: test weaken on a read only ref # SKIP: { # Doesn't work for older perls, see bug [perl #24506] skip("Test does not work with perl < 5.8.3", 5) if $] < 5.008003; # in a MAD build, constants have refcnt 2, not 1 skip("Test does not work with MAD", 5) if exists $Config{mad}; $a = eval '\"hello"'; ok(ref($a)) or print "# didn't get a ref from eval\n"; $b = $a; eval{weaken($b)}; # we didn't die ok($@ eq "") or print "# died with $@\n"; ok(isweak($b)); ok($$b eq "hello") or print "# b is '$$b'\n"; $a=""; ok(not $b) or print "# b didn't go away\n"; } package Dest; sub DESTROY { print "# INCFLAG\n"; ${$_[0]{Flag}} ++; }