xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/t/op/tie.t (revision 0:68f95e015346)
1*0Sstevel@tonic-gate#!./perl
2*0Sstevel@tonic-gate
3*0Sstevel@tonic-gate# Add new tests to the end with format:
4*0Sstevel@tonic-gate# ########
5*0Sstevel@tonic-gate#
6*0Sstevel@tonic-gate# # test description
7*0Sstevel@tonic-gate# Test code
8*0Sstevel@tonic-gate# EXPECT
9*0Sstevel@tonic-gate# Warn or die msgs (if any) at - line 1234
10*0Sstevel@tonic-gate#
11*0Sstevel@tonic-gate
12*0Sstevel@tonic-gatechdir 't' if -d 't';
13*0Sstevel@tonic-gate@INC = '../lib';
14*0Sstevel@tonic-gate$ENV{PERL5LIB} = "../lib";
15*0Sstevel@tonic-gate
16*0Sstevel@tonic-gate$|=1;
17*0Sstevel@tonic-gate
18*0Sstevel@tonic-gateundef $/;
19*0Sstevel@tonic-gate@prgs = split /^########\n/m, <DATA>;
20*0Sstevel@tonic-gate
21*0Sstevel@tonic-gaterequire './test.pl';
22*0Sstevel@tonic-gateplan(tests => scalar @prgs);
23*0Sstevel@tonic-gatefor (@prgs){
24*0Sstevel@tonic-gate    ++$i;
25*0Sstevel@tonic-gate    my($prog,$expected) = split(/\nEXPECT\n/, $_, 2);
26*0Sstevel@tonic-gate    print("not ok $i # bad test format\n"), next
27*0Sstevel@tonic-gate        unless defined $expected;
28*0Sstevel@tonic-gate    my ($testname) = $prog =~ /^# (.*)\n/m;
29*0Sstevel@tonic-gate    $testname ||= '';
30*0Sstevel@tonic-gate    $TODO = $testname =~ s/^TODO //;
31*0Sstevel@tonic-gate    $results =~ s/\n+$//;
32*0Sstevel@tonic-gate    $expected =~ s/\n+$//;
33*0Sstevel@tonic-gate
34*0Sstevel@tonic-gate    fresh_perl_is($prog, $expected, {}, $testname);
35*0Sstevel@tonic-gate}
36*0Sstevel@tonic-gate
37*0Sstevel@tonic-gate__END__
38*0Sstevel@tonic-gate
39*0Sstevel@tonic-gate# standard behaviour, without any extra references
40*0Sstevel@tonic-gateuse Tie::Hash ;
41*0Sstevel@tonic-gatetie %h, Tie::StdHash;
42*0Sstevel@tonic-gateuntie %h;
43*0Sstevel@tonic-gateEXPECT
44*0Sstevel@tonic-gate########
45*0Sstevel@tonic-gate
46*0Sstevel@tonic-gate# standard behaviour, without any extra references
47*0Sstevel@tonic-gateuse Tie::Hash ;
48*0Sstevel@tonic-gate{package Tie::HashUntie;
49*0Sstevel@tonic-gate use base 'Tie::StdHash';
50*0Sstevel@tonic-gate sub UNTIE
51*0Sstevel@tonic-gate  {
52*0Sstevel@tonic-gate   warn "Untied\n";
53*0Sstevel@tonic-gate  }
54*0Sstevel@tonic-gate}
55*0Sstevel@tonic-gatetie %h, Tie::HashUntie;
56*0Sstevel@tonic-gateuntie %h;
57*0Sstevel@tonic-gateEXPECT
58*0Sstevel@tonic-gateUntied
59*0Sstevel@tonic-gate########
60*0Sstevel@tonic-gate
61*0Sstevel@tonic-gate# standard behaviour, with 1 extra reference
62*0Sstevel@tonic-gateuse Tie::Hash ;
63*0Sstevel@tonic-gate$a = tie %h, Tie::StdHash;
64*0Sstevel@tonic-gateuntie %h;
65*0Sstevel@tonic-gateEXPECT
66*0Sstevel@tonic-gate########
67*0Sstevel@tonic-gate
68*0Sstevel@tonic-gate# standard behaviour, with 1 extra reference via tied
69*0Sstevel@tonic-gateuse Tie::Hash ;
70*0Sstevel@tonic-gatetie %h, Tie::StdHash;
71*0Sstevel@tonic-gate$a = tied %h;
72*0Sstevel@tonic-gateuntie %h;
73*0Sstevel@tonic-gateEXPECT
74*0Sstevel@tonic-gate########
75*0Sstevel@tonic-gate
76*0Sstevel@tonic-gate# standard behaviour, with 1 extra reference which is destroyed
77*0Sstevel@tonic-gateuse Tie::Hash ;
78*0Sstevel@tonic-gate$a = tie %h, Tie::StdHash;
79*0Sstevel@tonic-gate$a = 0 ;
80*0Sstevel@tonic-gateuntie %h;
81*0Sstevel@tonic-gateEXPECT
82*0Sstevel@tonic-gate########
83*0Sstevel@tonic-gate
84*0Sstevel@tonic-gate# standard behaviour, with 1 extra reference via tied which is destroyed
85*0Sstevel@tonic-gateuse Tie::Hash ;
86*0Sstevel@tonic-gatetie %h, Tie::StdHash;
87*0Sstevel@tonic-gate$a = tied %h;
88*0Sstevel@tonic-gate$a = 0 ;
89*0Sstevel@tonic-gateuntie %h;
90*0Sstevel@tonic-gateEXPECT
91*0Sstevel@tonic-gate########
92*0Sstevel@tonic-gate
93*0Sstevel@tonic-gate# strict behaviour, without any extra references
94*0Sstevel@tonic-gateuse warnings 'untie';
95*0Sstevel@tonic-gateuse Tie::Hash ;
96*0Sstevel@tonic-gatetie %h, Tie::StdHash;
97*0Sstevel@tonic-gateuntie %h;
98*0Sstevel@tonic-gateEXPECT
99*0Sstevel@tonic-gate########
100*0Sstevel@tonic-gate
101*0Sstevel@tonic-gate# strict behaviour, with 1 extra references generating an error
102*0Sstevel@tonic-gateuse warnings 'untie';
103*0Sstevel@tonic-gateuse Tie::Hash ;
104*0Sstevel@tonic-gate$a = tie %h, Tie::StdHash;
105*0Sstevel@tonic-gateuntie %h;
106*0Sstevel@tonic-gateEXPECT
107*0Sstevel@tonic-gateuntie attempted while 1 inner references still exist at - line 6.
108*0Sstevel@tonic-gate########
109*0Sstevel@tonic-gate
110*0Sstevel@tonic-gate# strict behaviour, with 1 extra references via tied generating an error
111*0Sstevel@tonic-gateuse warnings 'untie';
112*0Sstevel@tonic-gateuse Tie::Hash ;
113*0Sstevel@tonic-gatetie %h, Tie::StdHash;
114*0Sstevel@tonic-gate$a = tied %h;
115*0Sstevel@tonic-gateuntie %h;
116*0Sstevel@tonic-gateEXPECT
117*0Sstevel@tonic-gateuntie attempted while 1 inner references still exist at - line 7.
118*0Sstevel@tonic-gate########
119*0Sstevel@tonic-gate
120*0Sstevel@tonic-gate# strict behaviour, with 1 extra references which are destroyed
121*0Sstevel@tonic-gateuse warnings 'untie';
122*0Sstevel@tonic-gateuse Tie::Hash ;
123*0Sstevel@tonic-gate$a = tie %h, Tie::StdHash;
124*0Sstevel@tonic-gate$a = 0 ;
125*0Sstevel@tonic-gateuntie %h;
126*0Sstevel@tonic-gateEXPECT
127*0Sstevel@tonic-gate########
128*0Sstevel@tonic-gate
129*0Sstevel@tonic-gate# strict behaviour, with extra 1 references via tied which are destroyed
130*0Sstevel@tonic-gateuse warnings 'untie';
131*0Sstevel@tonic-gateuse Tie::Hash ;
132*0Sstevel@tonic-gatetie %h, Tie::StdHash;
133*0Sstevel@tonic-gate$a = tied %h;
134*0Sstevel@tonic-gate$a = 0 ;
135*0Sstevel@tonic-gateuntie %h;
136*0Sstevel@tonic-gateEXPECT
137*0Sstevel@tonic-gate########
138*0Sstevel@tonic-gate
139*0Sstevel@tonic-gate# strict error behaviour, with 2 extra references
140*0Sstevel@tonic-gateuse warnings 'untie';
141*0Sstevel@tonic-gateuse Tie::Hash ;
142*0Sstevel@tonic-gate$a = tie %h, Tie::StdHash;
143*0Sstevel@tonic-gate$b = tied %h ;
144*0Sstevel@tonic-gateuntie %h;
145*0Sstevel@tonic-gateEXPECT
146*0Sstevel@tonic-gateuntie attempted while 2 inner references still exist at - line 7.
147*0Sstevel@tonic-gate########
148*0Sstevel@tonic-gate
149*0Sstevel@tonic-gate# strict behaviour, check scope of strictness.
150*0Sstevel@tonic-gateno warnings 'untie';
151*0Sstevel@tonic-gateuse Tie::Hash ;
152*0Sstevel@tonic-gate$A = tie %H, Tie::StdHash;
153*0Sstevel@tonic-gate$C = $B = tied %H ;
154*0Sstevel@tonic-gate{
155*0Sstevel@tonic-gate    use warnings 'untie';
156*0Sstevel@tonic-gate    use Tie::Hash ;
157*0Sstevel@tonic-gate    tie %h, Tie::StdHash;
158*0Sstevel@tonic-gate    untie %h;
159*0Sstevel@tonic-gate}
160*0Sstevel@tonic-gateuntie %H;
161*0Sstevel@tonic-gateEXPECT
162*0Sstevel@tonic-gate########
163*0Sstevel@tonic-gate
164*0Sstevel@tonic-gate# Forbidden aggregate self-ties
165*0Sstevel@tonic-gatesub Self::TIEHASH { bless $_[1], $_[0] }
166*0Sstevel@tonic-gate{
167*0Sstevel@tonic-gate    my %c;
168*0Sstevel@tonic-gate    tie %c, 'Self', \%c;
169*0Sstevel@tonic-gate}
170*0Sstevel@tonic-gateEXPECT
171*0Sstevel@tonic-gateSelf-ties of arrays and hashes are not supported at - line 6.
172*0Sstevel@tonic-gate########
173*0Sstevel@tonic-gate
174*0Sstevel@tonic-gate# Allowed scalar self-ties
175*0Sstevel@tonic-gatemy $destroyed = 0;
176*0Sstevel@tonic-gatesub Self::TIESCALAR { bless $_[1], $_[0] }
177*0Sstevel@tonic-gatesub Self::DESTROY   { $destroyed = 1; }
178*0Sstevel@tonic-gate{
179*0Sstevel@tonic-gate    my $c = 42;
180*0Sstevel@tonic-gate    tie $c, 'Self', \$c;
181*0Sstevel@tonic-gate}
182*0Sstevel@tonic-gatedie "self-tied scalar not DESTROYed" unless $destroyed == 1;
183*0Sstevel@tonic-gateEXPECT
184*0Sstevel@tonic-gate########
185*0Sstevel@tonic-gate
186*0Sstevel@tonic-gate# Allowed glob self-ties
187*0Sstevel@tonic-gatemy $destroyed = 0;
188*0Sstevel@tonic-gatemy $printed   = 0;
189*0Sstevel@tonic-gatesub Self2::TIEHANDLE { bless $_[1], $_[0] }
190*0Sstevel@tonic-gatesub Self2::DESTROY   { $destroyed = 1; }
191*0Sstevel@tonic-gatesub Self2::PRINT     { $printed = 1; }
192*0Sstevel@tonic-gate{
193*0Sstevel@tonic-gate    use Symbol;
194*0Sstevel@tonic-gate    my $c = gensym;
195*0Sstevel@tonic-gate    tie *$c, 'Self2', $c;
196*0Sstevel@tonic-gate    print $c 'Hello';
197*0Sstevel@tonic-gate}
198*0Sstevel@tonic-gatedie "self-tied glob not PRINTed" unless $printed == 1;
199*0Sstevel@tonic-gatedie "self-tied glob not DESTROYed" unless $destroyed == 1;
200*0Sstevel@tonic-gateEXPECT
201*0Sstevel@tonic-gate########
202*0Sstevel@tonic-gate
203*0Sstevel@tonic-gate# Allowed IO self-ties
204*0Sstevel@tonic-gatemy $destroyed = 0;
205*0Sstevel@tonic-gatesub Self3::TIEHANDLE { bless $_[1], $_[0] }
206*0Sstevel@tonic-gatesub Self3::DESTROY   { $destroyed = 1; }
207*0Sstevel@tonic-gatesub Self3::PRINT     { $printed = 1; }
208*0Sstevel@tonic-gate{
209*0Sstevel@tonic-gate    use Symbol 'geniosym';
210*0Sstevel@tonic-gate    my $c = geniosym;
211*0Sstevel@tonic-gate    tie *$c, 'Self3', $c;
212*0Sstevel@tonic-gate    print $c 'Hello';
213*0Sstevel@tonic-gate}
214*0Sstevel@tonic-gatedie "self-tied IO not PRINTed" unless $printed == 1;
215*0Sstevel@tonic-gatedie "self-tied IO not DESTROYed" unless $destroyed == 1;
216*0Sstevel@tonic-gateEXPECT
217*0Sstevel@tonic-gate########
218*0Sstevel@tonic-gate
219*0Sstevel@tonic-gate# TODO IO "self-tie" via TEMP glob
220*0Sstevel@tonic-gatemy $destroyed = 0;
221*0Sstevel@tonic-gatesub Self3::TIEHANDLE { bless $_[1], $_[0] }
222*0Sstevel@tonic-gatesub Self3::DESTROY   { $destroyed = 1; }
223*0Sstevel@tonic-gatesub Self3::PRINT     { $printed = 1; }
224*0Sstevel@tonic-gate{
225*0Sstevel@tonic-gate    use Symbol 'geniosym';
226*0Sstevel@tonic-gate    my $c = geniosym;
227*0Sstevel@tonic-gate    tie *$c, 'Self3', \*$c;
228*0Sstevel@tonic-gate    print $c 'Hello';
229*0Sstevel@tonic-gate}
230*0Sstevel@tonic-gatedie "IO tied to TEMP glob not PRINTed" unless $printed == 1;
231*0Sstevel@tonic-gatedie "IO tied to TEMP glob not DESTROYed" unless $destroyed == 1;
232*0Sstevel@tonic-gateEXPECT
233*0Sstevel@tonic-gate########
234*0Sstevel@tonic-gate
235*0Sstevel@tonic-gate# Interaction of tie and vec
236*0Sstevel@tonic-gate
237*0Sstevel@tonic-gatemy ($a, $b);
238*0Sstevel@tonic-gateuse Tie::Scalar;
239*0Sstevel@tonic-gatetie $a,Tie::StdScalar or die;
240*0Sstevel@tonic-gatevec($b,1,1)=1;
241*0Sstevel@tonic-gate$a = $b;
242*0Sstevel@tonic-gatevec($a,1,1)=0;
243*0Sstevel@tonic-gatevec($b,1,1)=0;
244*0Sstevel@tonic-gatedie unless $a eq $b;
245*0Sstevel@tonic-gateEXPECT
246*0Sstevel@tonic-gate########
247*0Sstevel@tonic-gate
248*0Sstevel@tonic-gate# correct unlocalisation of tied hashes (patch #16431)
249*0Sstevel@tonic-gateuse Tie::Hash ;
250*0Sstevel@tonic-gatetie %tied, Tie::StdHash;
251*0Sstevel@tonic-gate{ local $hash{'foo'} } warn "plain hash bad unlocalize" if exists $hash{'foo'};
252*0Sstevel@tonic-gate{ local $tied{'foo'} } warn "tied hash bad unlocalize" if exists $tied{'foo'};
253*0Sstevel@tonic-gate{ local $ENV{'foo'}  } warn "%ENV bad unlocalize" if exists $ENV{'foo'};
254*0Sstevel@tonic-gateEXPECT
255*0Sstevel@tonic-gate########
256*0Sstevel@tonic-gate
257*0Sstevel@tonic-gate# An attempt at lvalueable barewords broke this
258*0Sstevel@tonic-gatetie FH, 'main';
259*0Sstevel@tonic-gateEXPECT
260*0Sstevel@tonic-gateCan't modify constant item in tie at - line 3, near "'main';"
261*0Sstevel@tonic-gateExecution of - aborted due to compilation errors.
262*0Sstevel@tonic-gate########
263*0Sstevel@tonic-gate
264*0Sstevel@tonic-gate# localizing tied hash slices
265*0Sstevel@tonic-gate$ENV{FooA} = 1;
266*0Sstevel@tonic-gate$ENV{FooB} = 2;
267*0Sstevel@tonic-gateprint exists $ENV{FooA} ? 1 : 0, "\n";
268*0Sstevel@tonic-gateprint exists $ENV{FooB} ? 2 : 0, "\n";
269*0Sstevel@tonic-gateprint exists $ENV{FooC} ? 3 : 0, "\n";
270*0Sstevel@tonic-gate{
271*0Sstevel@tonic-gate    local @ENV{qw(FooA FooC)};
272*0Sstevel@tonic-gate    print exists $ENV{FooA} ? 4 : 0, "\n";
273*0Sstevel@tonic-gate    print exists $ENV{FooB} ? 5 : 0, "\n";
274*0Sstevel@tonic-gate    print exists $ENV{FooC} ? 6 : 0, "\n";
275*0Sstevel@tonic-gate}
276*0Sstevel@tonic-gateprint exists $ENV{FooA} ? 7 : 0, "\n";
277*0Sstevel@tonic-gateprint exists $ENV{FooB} ? 8 : 0, "\n";
278*0Sstevel@tonic-gateprint exists $ENV{FooC} ? 9 : 0, "\n"; # this should not exist
279*0Sstevel@tonic-gateEXPECT
280*0Sstevel@tonic-gate1
281*0Sstevel@tonic-gate2
282*0Sstevel@tonic-gate0
283*0Sstevel@tonic-gate4
284*0Sstevel@tonic-gate5
285*0Sstevel@tonic-gate6
286*0Sstevel@tonic-gate7
287*0Sstevel@tonic-gate8
288*0Sstevel@tonic-gate0
289*0Sstevel@tonic-gate########
290*0Sstevel@tonic-gate#
291*0Sstevel@tonic-gate# FETCH freeing tie'd SV
292*0Sstevel@tonic-gatesub TIESCALAR { bless [] }
293*0Sstevel@tonic-gatesub FETCH { *a = \1; 1 }
294*0Sstevel@tonic-gatetie $a, 'main';
295*0Sstevel@tonic-gateprint $a;
296*0Sstevel@tonic-gateEXPECT
297*0Sstevel@tonic-gateTied variable freed while still in use at - line 6.
298*0Sstevel@tonic-gate########
299*0Sstevel@tonic-gate
300*0Sstevel@tonic-gate#  [20020716.007] - nested FETCHES
301*0Sstevel@tonic-gate
302*0Sstevel@tonic-gatesub F1::TIEARRAY { bless [], 'F1' }
303*0Sstevel@tonic-gatesub F1::FETCH { 1 }
304*0Sstevel@tonic-gatemy @f1;
305*0Sstevel@tonic-gatetie @f1, 'F1';
306*0Sstevel@tonic-gate
307*0Sstevel@tonic-gatesub F2::TIEARRAY { bless [2], 'F2' }
308*0Sstevel@tonic-gatesub F2::FETCH { my $self = shift; my $x = $f1[3]; $self }
309*0Sstevel@tonic-gatemy @f2;
310*0Sstevel@tonic-gatetie @f2, 'F2';
311*0Sstevel@tonic-gate
312*0Sstevel@tonic-gateprint $f2[4][0],"\n";
313*0Sstevel@tonic-gate
314*0Sstevel@tonic-gatesub F3::TIEHASH { bless [], 'F3' }
315*0Sstevel@tonic-gatesub F3::FETCH { 1 }
316*0Sstevel@tonic-gatemy %f3;
317*0Sstevel@tonic-gatetie %f3, 'F3';
318*0Sstevel@tonic-gate
319*0Sstevel@tonic-gatesub F4::TIEHASH { bless [3], 'F4' }
320*0Sstevel@tonic-gatesub F4::FETCH { my $self = shift; my $x = $f3{3}; $self }
321*0Sstevel@tonic-gatemy %f4;
322*0Sstevel@tonic-gatetie %f4, 'F4';
323*0Sstevel@tonic-gate
324*0Sstevel@tonic-gateprint $f4{'foo'}[0],"\n";
325*0Sstevel@tonic-gate
326*0Sstevel@tonic-gateEXPECT
327*0Sstevel@tonic-gate2
328*0Sstevel@tonic-gate3
329*0Sstevel@tonic-gate########
330*0Sstevel@tonic-gate# test untie() from within FETCH
331*0Sstevel@tonic-gatepackage Foo;
332*0Sstevel@tonic-gatesub TIESCALAR { my $pkg = shift; return bless [@_], $pkg; }
333*0Sstevel@tonic-gatesub FETCH {
334*0Sstevel@tonic-gate  my $self = shift;
335*0Sstevel@tonic-gate  my ($obj, $field) = @$self;
336*0Sstevel@tonic-gate  untie $obj->{$field};
337*0Sstevel@tonic-gate  $obj->{$field} = "Bar";
338*0Sstevel@tonic-gate}
339*0Sstevel@tonic-gatepackage main;
340*0Sstevel@tonic-gatetie $a->{foo}, "Foo", $a, "foo";
341*0Sstevel@tonic-gate$a->{foo}; # access once
342*0Sstevel@tonic-gate# the hash element should not be tied anymore
343*0Sstevel@tonic-gateprint defined tied $a->{foo} ? "not ok" : "ok";
344*0Sstevel@tonic-gateEXPECT
345*0Sstevel@tonic-gateok
346*0Sstevel@tonic-gate########
347*0Sstevel@tonic-gate# the tmps returned by FETCH should appear to be SCALAR
348*0Sstevel@tonic-gate# (even though they are now implemented using PVLVs.)
349*0Sstevel@tonic-gatepackage X;
350*0Sstevel@tonic-gatesub TIEHASH { bless {} }
351*0Sstevel@tonic-gatesub TIEARRAY { bless {} }
352*0Sstevel@tonic-gatesub FETCH {1}
353*0Sstevel@tonic-gatemy (%h, @a);
354*0Sstevel@tonic-gatetie %h, 'X';
355*0Sstevel@tonic-gatetie @a, 'X';
356*0Sstevel@tonic-gatemy $r1 = \$h{1};
357*0Sstevel@tonic-gatemy $r2 = \$a[0];
358*0Sstevel@tonic-gatemy $s = "$r1 ". ref($r1) . " $r2 " . ref($r2);
359*0Sstevel@tonic-gate$s=~ s/\(0x\w+\)//g;
360*0Sstevel@tonic-gateprint $s, "\n";
361*0Sstevel@tonic-gateEXPECT
362*0Sstevel@tonic-gateSCALAR SCALAR SCALAR SCALAR
363*0Sstevel@tonic-gate########
364*0Sstevel@tonic-gate# [perl #23287] segfault in untie
365*0Sstevel@tonic-gatesub TIESCALAR { bless $_[1], $_[0] }
366*0Sstevel@tonic-gatemy $var;
367*0Sstevel@tonic-gatetie $var, 'main', \$var;
368*0Sstevel@tonic-gateuntie $var;
369*0Sstevel@tonic-gateEXPECT
370*0Sstevel@tonic-gate########
371*0Sstevel@tonic-gate# Test case from perlmonks by runrig
372*0Sstevel@tonic-gate# http://www.perlmonks.org/index.pl?node_id=273490
373*0Sstevel@tonic-gate# "Here is what I tried. I think its similar to what you've tried
374*0Sstevel@tonic-gate#  above. Its odd but convienient that after untie'ing you are left with
375*0Sstevel@tonic-gate#  a variable that has the same value as was last returned from
376*0Sstevel@tonic-gate#  FETCH. (At least on my perl v5.6.1). So you don't need to pass a
377*0Sstevel@tonic-gate#  reference to the variable in order to set it after the untie (here it
378*0Sstevel@tonic-gate#  is accessed through a closure)."
379*0Sstevel@tonic-gateuse strict;
380*0Sstevel@tonic-gateuse warnings;
381*0Sstevel@tonic-gatepackage MyTied;
382*0Sstevel@tonic-gatesub TIESCALAR {
383*0Sstevel@tonic-gate    my ($class,$code) = @_;
384*0Sstevel@tonic-gate    bless $code, $class;
385*0Sstevel@tonic-gate}
386*0Sstevel@tonic-gatesub FETCH {
387*0Sstevel@tonic-gate    my $self = shift;
388*0Sstevel@tonic-gate    print "Untie\n";
389*0Sstevel@tonic-gate    $self->();
390*0Sstevel@tonic-gate}
391*0Sstevel@tonic-gatepackage main;
392*0Sstevel@tonic-gatemy $var;
393*0Sstevel@tonic-gatetie $var, 'MyTied', sub { untie $var; 4 };
394*0Sstevel@tonic-gateprint "One\n";
395*0Sstevel@tonic-gateprint "$var\n";
396*0Sstevel@tonic-gateprint "Two\n";
397*0Sstevel@tonic-gateprint "$var\n";
398*0Sstevel@tonic-gateprint "Three\n";
399*0Sstevel@tonic-gateprint "$var\n";
400*0Sstevel@tonic-gateEXPECT
401*0Sstevel@tonic-gateOne
402*0Sstevel@tonic-gateUntie
403*0Sstevel@tonic-gate4
404*0Sstevel@tonic-gateTwo
405*0Sstevel@tonic-gate4
406*0Sstevel@tonic-gateThree
407*0Sstevel@tonic-gate4
408*0Sstevel@tonic-gate########
409*0Sstevel@tonic-gate# [perl #22297] cannot untie scalar from within tied FETCH
410*0Sstevel@tonic-gatemy $counter = 0;
411*0Sstevel@tonic-gatemy $x = 7;
412*0Sstevel@tonic-gatemy $ref = \$x;
413*0Sstevel@tonic-gatetie $x, 'Overlay', $ref, $x;
414*0Sstevel@tonic-gatemy $y;
415*0Sstevel@tonic-gate$y = $x;
416*0Sstevel@tonic-gate$y = $x;
417*0Sstevel@tonic-gate$y = $x;
418*0Sstevel@tonic-gate$y = $x;
419*0Sstevel@tonic-gate#print "WILL EXTERNAL UNTIE $ref\n";
420*0Sstevel@tonic-gateuntie $$ref;
421*0Sstevel@tonic-gate$y = $x;
422*0Sstevel@tonic-gate$y = $x;
423*0Sstevel@tonic-gate$y = $x;
424*0Sstevel@tonic-gate$y = $x;
425*0Sstevel@tonic-gate#print "counter = $counter\n";
426*0Sstevel@tonic-gate
427*0Sstevel@tonic-gateprint (($counter == 1) ? "ok\n" : "not ok\n");
428*0Sstevel@tonic-gate
429*0Sstevel@tonic-gatepackage Overlay;
430*0Sstevel@tonic-gate
431*0Sstevel@tonic-gatesub TIESCALAR
432*0Sstevel@tonic-gate{
433*0Sstevel@tonic-gate        my $pkg = shift;
434*0Sstevel@tonic-gate        my ($ref, $val) = @_;
435*0Sstevel@tonic-gate        return bless [ $ref, $val ], $pkg;
436*0Sstevel@tonic-gate}
437*0Sstevel@tonic-gate
438*0Sstevel@tonic-gatesub FETCH
439*0Sstevel@tonic-gate{
440*0Sstevel@tonic-gate        my $self = shift;
441*0Sstevel@tonic-gate        my ($ref, $val) = @$self;
442*0Sstevel@tonic-gate        #print "WILL INTERNAL UNITE $ref\n";
443*0Sstevel@tonic-gate        $counter++;
444*0Sstevel@tonic-gate        untie $$ref;
445*0Sstevel@tonic-gate        return $val;
446*0Sstevel@tonic-gate}
447*0Sstevel@tonic-gateEXPECT
448*0Sstevel@tonic-gateok
449*0Sstevel@tonic-gate########
450*0Sstevel@tonic-gate
451*0Sstevel@tonic-gate# test SCALAR method
452*0Sstevel@tonic-gatepackage TieScalar;
453*0Sstevel@tonic-gate
454*0Sstevel@tonic-gatesub TIEHASH {
455*0Sstevel@tonic-gate    my $pkg = shift;
456*0Sstevel@tonic-gate    bless { } => $pkg;
457*0Sstevel@tonic-gate}
458*0Sstevel@tonic-gate
459*0Sstevel@tonic-gatesub STORE {
460*0Sstevel@tonic-gate    $_[0]->{$_[1]} = $_[2];
461*0Sstevel@tonic-gate}
462*0Sstevel@tonic-gate
463*0Sstevel@tonic-gatesub FETCH {
464*0Sstevel@tonic-gate    $_[0]->{$_[1]}
465*0Sstevel@tonic-gate}
466*0Sstevel@tonic-gate
467*0Sstevel@tonic-gatesub CLEAR {
468*0Sstevel@tonic-gate    %{ $_[0] } = ();
469*0Sstevel@tonic-gate}
470*0Sstevel@tonic-gate
471*0Sstevel@tonic-gatesub SCALAR {
472*0Sstevel@tonic-gate    print "SCALAR\n";
473*0Sstevel@tonic-gate    return 0 if ! keys %{$_[0]};
474*0Sstevel@tonic-gate    sprintf "%i/%i", scalar keys %{$_[0]}, scalar keys %{$_[0]};
475*0Sstevel@tonic-gate}
476*0Sstevel@tonic-gate
477*0Sstevel@tonic-gatepackage main;
478*0Sstevel@tonic-gatetie my %h => "TieScalar";
479*0Sstevel@tonic-gate$h{key1} = "val1";
480*0Sstevel@tonic-gate$h{key2} = "val2";
481*0Sstevel@tonic-gateprint scalar %h, "\n";
482*0Sstevel@tonic-gate%h = ();
483*0Sstevel@tonic-gateprint scalar %h, "\n";
484*0Sstevel@tonic-gateEXPECT
485*0Sstevel@tonic-gateSCALAR
486*0Sstevel@tonic-gate2/2
487*0Sstevel@tonic-gateSCALAR
488*0Sstevel@tonic-gate0
489*0Sstevel@tonic-gate########
490*0Sstevel@tonic-gate
491*0Sstevel@tonic-gate# test scalar on tied hash when no SCALAR method has been given
492*0Sstevel@tonic-gatepackage TieScalar;
493*0Sstevel@tonic-gate
494*0Sstevel@tonic-gatesub TIEHASH {
495*0Sstevel@tonic-gate    my $pkg = shift;
496*0Sstevel@tonic-gate    bless { } => $pkg;
497*0Sstevel@tonic-gate}
498*0Sstevel@tonic-gatesub STORE {
499*0Sstevel@tonic-gate    $_[0]->{$_[1]} = $_[2];
500*0Sstevel@tonic-gate}
501*0Sstevel@tonic-gatesub FETCH {
502*0Sstevel@tonic-gate    $_[0]->{$_[1]}
503*0Sstevel@tonic-gate}
504*0Sstevel@tonic-gatesub CLEAR {
505*0Sstevel@tonic-gate    %{ $_[0] } = ();
506*0Sstevel@tonic-gate}
507*0Sstevel@tonic-gatesub FIRSTKEY {
508*0Sstevel@tonic-gate    my $a = keys %{ $_[0] };
509*0Sstevel@tonic-gate    print "FIRSTKEY\n";
510*0Sstevel@tonic-gate    each %{ $_[0] };
511*0Sstevel@tonic-gate}
512*0Sstevel@tonic-gate
513*0Sstevel@tonic-gatepackage main;
514*0Sstevel@tonic-gatetie my %h => "TieScalar";
515*0Sstevel@tonic-gate
516*0Sstevel@tonic-gateif (!%h) {
517*0Sstevel@tonic-gate    print "empty\n";
518*0Sstevel@tonic-gate} else {
519*0Sstevel@tonic-gate    print "not empty\n";
520*0Sstevel@tonic-gate}
521*0Sstevel@tonic-gate
522*0Sstevel@tonic-gate$h{key1} = "val1";
523*0Sstevel@tonic-gateprint "not empty\n" if %h;
524*0Sstevel@tonic-gateprint "not empty\n" if %h;
525*0Sstevel@tonic-gateprint "-->\n";
526*0Sstevel@tonic-gatemy ($k,$v) = each %h;
527*0Sstevel@tonic-gateprint "<--\n";
528*0Sstevel@tonic-gateprint "not empty\n" if %h;
529*0Sstevel@tonic-gate%h = ();
530*0Sstevel@tonic-gateprint "empty\n" if ! %h;
531*0Sstevel@tonic-gateEXPECT
532*0Sstevel@tonic-gateFIRSTKEY
533*0Sstevel@tonic-gateempty
534*0Sstevel@tonic-gateFIRSTKEY
535*0Sstevel@tonic-gatenot empty
536*0Sstevel@tonic-gateFIRSTKEY
537*0Sstevel@tonic-gatenot empty
538*0Sstevel@tonic-gate-->
539*0Sstevel@tonic-gateFIRSTKEY
540*0Sstevel@tonic-gate<--
541*0Sstevel@tonic-gatenot empty
542*0Sstevel@tonic-gateFIRSTKEY
543*0Sstevel@tonic-gateempty
544