Commit | Line | Data |
a687059c |
1 | #!./perl |
2 | |
d441d3db |
3 | BEGIN { |
4 | chdir 't' if -d 't'; |
28e491ba |
5 | @INC = qw(. ../lib); |
d441d3db |
6 | require './test.pl'; |
7 | } |
658aef79 |
8 | plan tests => 114; |
a687059c |
9 | |
13414bd5 |
10 | my $list_assignment_supported = 1; |
11 | |
12 | #mg.c says list assignment not supported on VMS, EPOC, and SYMBIAN. |
13 | $list_assignment_supported = 0 if ($^O eq 'VMS'); |
14 | |
15 | |
a687059c |
16 | sub foo { |
17 | local($a, $b) = @_; |
18 | local($c, $d); |
d441d3db |
19 | $c = "c 3"; |
20 | $d = "d 4"; |
21 | { local($a,$c) = ("a 9", "c 10"); ($x, $y) = ($a, $c); } |
22 | is($a, "a 1"); |
23 | is($b, "b 2"); |
24 | $c, $d; |
a687059c |
25 | } |
26 | |
d441d3db |
27 | $a = "a 5"; |
28 | $b = "b 6"; |
29 | $c = "c 7"; |
30 | $d = "d 8"; |
a687059c |
31 | |
d441d3db |
32 | my @res; |
33 | @res = &foo("a 1","b 2"); |
34 | is($res[0], "c 3"); |
35 | is($res[1], "d 4"); |
a687059c |
36 | |
d441d3db |
37 | is($a, "a 5"); |
38 | is($b, "b 6"); |
39 | is($c, "c 7"); |
40 | is($d, "d 8"); |
41 | is($x, "a 9"); |
42 | is($y, "c 10"); |
a687059c |
43 | |
44 | # same thing, only with arrays and associative arrays |
45 | |
46 | sub foo2 { |
47 | local($a, @b) = @_; |
48 | local(@c, %d); |
d441d3db |
49 | @c = "c 3"; |
50 | $d{''} = "d 4"; |
51 | { local($a,@c) = ("a 19", "c 20"); ($x, $y) = ($a, @c); } |
52 | is($a, "a 1"); |
53 | is("@b", "b 2"); |
54 | $c[0], $d{''}; |
a687059c |
55 | } |
56 | |
d441d3db |
57 | $a = "a 5"; |
58 | @b = "b 6"; |
59 | @c = "c 7"; |
60 | $d{''} = "d 8"; |
61 | |
62 | @res = &foo2("a 1","b 2"); |
63 | is($res[0], "c 3"); |
64 | is($res[1], "d 4"); |
a687059c |
65 | |
d441d3db |
66 | is($a, "a 5"); |
67 | is("@b", "b 6"); |
68 | is($c[0], "c 7"); |
69 | is($d{''}, "d 8"); |
70 | is($x, "a 19"); |
71 | is($y, "c 20"); |
a687059c |
72 | |
706a304b |
73 | |
74 | eval 'local($$e)'; |
d441d3db |
75 | like($@, qr/Can't localize through a reference/); |
706a304b |
76 | |
82d03984 |
77 | eval '$e = []; local(@$e)'; |
d441d3db |
78 | like($@, qr/Can't localize through a reference/); |
706a304b |
79 | |
82d03984 |
80 | eval '$e = {}; local(%$e)'; |
d441d3db |
81 | like($@, qr/Can't localize through a reference/); |
85aff577 |
82 | |
161b7d16 |
83 | # Array and hash elements |
84 | |
85 | @a = ('a', 'b', 'c'); |
86 | { |
87 | local($a[1]) = 'foo'; |
88 | local($a[2]) = $a[2]; |
d441d3db |
89 | is($a[1], 'foo'); |
90 | is($a[2], 'c'); |
161b7d16 |
91 | undef @a; |
92 | } |
d441d3db |
93 | is($a[1], 'b'); |
94 | is($a[2], 'c'); |
95 | ok(!defined $a[0]); |
161b7d16 |
96 | |
97 | @a = ('a', 'b', 'c'); |
98 | { |
99 | local($a[1]) = "X"; |
100 | shift @a; |
101 | } |
d441d3db |
102 | is($a[0].$a[1], "Xb"); |
d60c5a05 |
103 | { |
104 | my $d = "@a"; |
105 | local @a = @a; |
106 | is("@a", $d); |
107 | } |
161b7d16 |
108 | |
109 | %h = ('a' => 1, 'b' => 2, 'c' => 3); |
110 | { |
111 | local($h{'a'}) = 'foo'; |
112 | local($h{'b'}) = $h{'b'}; |
d441d3db |
113 | is($h{'a'}, 'foo'); |
114 | is($h{'b'}, 2); |
161b7d16 |
115 | local($h{'c'}); |
116 | delete $h{'c'}; |
117 | } |
d441d3db |
118 | is($h{'a'}, 1); |
119 | is($h{'b'}, 2); |
d60c5a05 |
120 | { |
121 | my $d = join("\n", map { "$_=>$h{$_}" } sort keys %h); |
122 | local %h = %h; |
123 | is(join("\n", map { "$_=>$h{$_}" } sort keys %h), $d); |
124 | } |
d441d3db |
125 | is($h{'c'}, 3); |
2bb40b7f |
126 | |
127 | # check for scope leakage |
128 | $a = 'outer'; |
129 | if (1) { local $a = 'inner' } |
d441d3db |
130 | is($a, 'outer'); |
2bb40b7f |
131 | |
132 | # see if localization works when scope unwinds |
133 | local $m = 5; |
134 | eval { |
135 | for $m (6) { |
136 | local $m = 7; |
137 | die "bye"; |
138 | } |
139 | }; |
d441d3db |
140 | is($m, 5); |
4e4c362e |
141 | |
142 | # see if localization works on tied arrays |
143 | { |
144 | package TA; |
145 | sub TIEARRAY { bless [], $_[0] } |
146 | sub STORE { print "# STORE [@_]\n"; $_[0]->[$_[1]] = $_[2] } |
147 | sub FETCH { my $v = $_[0]->[$_[1]]; print "# FETCH [@_=$v]\n"; $v } |
148 | sub CLEAR { print "# CLEAR [@_]\n"; @{$_[0]} = (); } |
149 | sub FETCHSIZE { scalar(@{$_[0]}) } |
150 | sub SHIFT { shift (@{$_[0]}) } |
151 | sub EXTEND {} |
152 | } |
153 | |
154 | tie @a, 'TA'; |
155 | @a = ('a', 'b', 'c'); |
156 | { |
157 | local($a[1]) = 'foo'; |
be6c24e0 |
158 | local($a[2]) = $a[2]; |
d441d3db |
159 | is($a[1], 'foo'); |
160 | is($a[2], 'c'); |
4e4c362e |
161 | @a = (); |
162 | } |
d441d3db |
163 | is($a[1], 'b'); |
164 | is($a[2], 'c'); |
165 | ok(!defined $a[0]); |
d60c5a05 |
166 | { |
167 | my $d = "@a"; |
168 | local @a = @a; |
169 | is("@a", $d); |
170 | } |
4e4c362e |
171 | |
172 | { |
173 | package TH; |
174 | sub TIEHASH { bless {}, $_[0] } |
175 | sub STORE { print "# STORE [@_]\n"; $_[0]->{$_[1]} = $_[2] } |
176 | sub FETCH { my $v = $_[0]->{$_[1]}; print "# FETCH [@_=$v]\n"; $v } |
c39e6ab0 |
177 | sub EXISTS { print "# EXISTS [@_]\n"; exists $_[0]->{$_[1]}; } |
4e4c362e |
178 | sub DELETE { print "# DELETE [@_]\n"; delete $_[0]->{$_[1]}; } |
179 | sub CLEAR { print "# CLEAR [@_]\n"; %{$_[0]} = (); } |
d60c5a05 |
180 | sub FIRSTKEY { print "# FIRSTKEY [@_]\n"; keys %{$_[0]}; each %{$_[0]} } |
181 | sub NEXTKEY { print "# NEXTKEY [@_]\n"; each %{$_[0]} } |
4e4c362e |
182 | } |
183 | |
184 | # see if localization works on tied hashes |
185 | tie %h, 'TH'; |
186 | %h = ('a' => 1, 'b' => 2, 'c' => 3); |
187 | |
188 | { |
189 | local($h{'a'}) = 'foo'; |
be6c24e0 |
190 | local($h{'b'}) = $h{'b'}; |
159ad915 |
191 | local($h{'y'}); |
192 | local($h{'z'}) = 33; |
d441d3db |
193 | is($h{'a'}, 'foo'); |
194 | is($h{'b'}, 2); |
4e4c362e |
195 | local($h{'c'}); |
196 | delete $h{'c'}; |
197 | } |
d441d3db |
198 | is($h{'a'}, 1); |
199 | is($h{'b'}, 2); |
200 | is($h{'c'}, 3); |
201 | # local() should preserve the existenceness of tied hash elements |
202 | ok(! exists $h{'y'}); |
203 | ok(! exists $h{'z'}); |
d60c5a05 |
204 | TODO: { |
205 | todo_skip("Localize entire tied hash"); |
206 | my $d = join("\n", map { "$_=>$h{$_}" } sort keys %h); |
207 | local %h = %h; |
208 | is(join("\n", map { "$_=>$h{$_}" } sort keys %h), $d); |
209 | } |
4e4c362e |
210 | |
211 | @a = ('a', 'b', 'c'); |
212 | { |
213 | local($a[1]) = "X"; |
214 | shift @a; |
215 | } |
d441d3db |
216 | is($a[0].$a[1], "Xb"); |
4e4c362e |
217 | |
be6c24e0 |
218 | # now try the same for %SIG |
219 | |
220 | $SIG{TERM} = 'foo'; |
221 | $SIG{INT} = \&foo; |
222 | $SIG{__WARN__} = $SIG{INT}; |
223 | { |
224 | local($SIG{TERM}) = $SIG{TERM}; |
225 | local($SIG{INT}) = $SIG{INT}; |
226 | local($SIG{__WARN__}) = $SIG{__WARN__}; |
d441d3db |
227 | is($SIG{TERM}, 'main::foo'); |
228 | is($SIG{INT}, \&foo); |
229 | is($SIG{__WARN__}, \&foo); |
be6c24e0 |
230 | local($SIG{INT}); |
231 | delete $SIG{__WARN__}; |
232 | } |
d441d3db |
233 | is($SIG{TERM}, 'main::foo'); |
234 | is($SIG{INT}, \&foo); |
235 | is($SIG{__WARN__}, \&foo); |
d60c5a05 |
236 | { |
237 | my $d = join("\n", map { "$_=>$SIG{$_}" } sort keys %SIG); |
238 | local %SIG = %SIG; |
239 | is(join("\n", map { "$_=>$SIG{$_}" } sort keys %SIG), $d); |
240 | } |
be6c24e0 |
241 | |
242 | # and for %ENV |
243 | |
244 | $ENV{_X_} = 'a'; |
245 | $ENV{_Y_} = 'b'; |
246 | $ENV{_Z_} = 'c'; |
247 | { |
159ad915 |
248 | local($ENV{_A_}); |
249 | local($ENV{_B_}) = 'foo'; |
be6c24e0 |
250 | local($ENV{_X_}) = 'foo'; |
251 | local($ENV{_Y_}) = $ENV{_Y_}; |
d441d3db |
252 | is($ENV{_X_}, 'foo'); |
253 | is($ENV{_Y_}, 'b'); |
be6c24e0 |
254 | local($ENV{_Z_}); |
255 | delete $ENV{_Z_}; |
256 | } |
d441d3db |
257 | is($ENV{_X_}, 'a'); |
258 | is($ENV{_Y_}, 'b'); |
259 | is($ENV{_Z_}, 'c'); |
260 | # local() should preserve the existenceness of %ENV elements |
261 | ok(! exists $ENV{_A_}); |
262 | ok(! exists $ENV{_B_}); |
13414bd5 |
263 | |
264 | SKIP: { |
265 | skip("Can't make list assignment to \%ENV on this system") |
266 | unless $list_assignment_supported; |
d60c5a05 |
267 | my $d = join("\n", map { "$_=>$ENV{$_}" } sort keys %ENV); |
268 | local %ENV = %ENV; |
269 | is(join("\n", map { "$_=>$ENV{$_}" } sort keys %ENV), $d); |
270 | } |
be6c24e0 |
271 | |
0214ae40 |
272 | # does implicit localization in foreach skip magic? |
273 | |
d441d3db |
274 | $_ = "o 0,o 1,"; |
0214ae40 |
275 | my $iter = 0; |
276 | while (/(o.+?),/gc) { |
d441d3db |
277 | is($1, "o $iter"); |
0214ae40 |
278 | foreach (1..1) { $iter++ } |
d441d3db |
279 | if ($iter > 2) { fail("endless loop"); last; } |
0214ae40 |
280 | } |
281 | |
282 | { |
283 | package UnderScore; |
284 | sub TIESCALAR { bless \my $self, shift } |
285 | sub FETCH { die "read \$_ forbidden" } |
286 | sub STORE { die "write \$_ forbidden" } |
287 | tie $_, __PACKAGE__; |
0214ae40 |
288 | my @tests = ( |
289 | "Nesting" => sub { print '#'; for (1..3) { print } |
290 | print "\n" }, 1, |
291 | "Reading" => sub { print }, 0, |
292 | "Matching" => sub { $x = /badness/ }, 0, |
293 | "Concat" => sub { $_ .= "a" }, 0, |
294 | "Chop" => sub { chop }, 0, |
295 | "Filetest" => sub { -x }, 0, |
296 | "Assignment" => sub { $_ = "Bad" }, 0, |
297 | # XXX whether next one should fail is debatable |
298 | "Local \$_" => sub { local $_ = 'ok?'; print }, 0, |
299 | "for local" => sub { for("#ok?\n"){ print } }, 1, |
300 | ); |
301 | while ( ($name, $code, $ok) = splice(@tests, 0, 3) ) { |
0214ae40 |
302 | eval { &$code }; |
d441d3db |
303 | main::ok(($ok xor $@), "Underscore '$name'"); |
0214ae40 |
304 | } |
305 | untie $_; |
306 | } |
307 | |
1f5346dc |
308 | { |
309 | # BUG 20001205.22 |
310 | my %x; |
311 | $x{a} = 1; |
312 | { local $x{b} = 1; } |
d441d3db |
313 | ok(! exists $x{b}); |
1f5346dc |
314 | { local @x{c,d,e}; } |
d441d3db |
315 | ok(! exists $x{c}); |
1f5346dc |
316 | } |
159ad915 |
317 | |
33f3c7b8 |
318 | # local() and readonly magic variables |
319 | |
320 | eval { local $1 = 1 }; |
d441d3db |
321 | like($@, qr/Modification of a read-only value attempted/); |
33f3c7b8 |
322 | |
323 | eval { for ($1) { local $_ = 1 } }; |
d441d3db |
324 | like($@, qr/Modification of a read-only value attempted/); |
33f3c7b8 |
325 | |
0cbee0a4 |
326 | # make sure $1 is still read-only |
33f3c7b8 |
327 | eval { for ($1) { local $_ = 1 } }; |
d441d3db |
328 | like($@, qr/Modification of a read-only value attempted/); |
ac117f44 |
329 | |
330 | # The s/// adds 'g' magic to $_, but it should remain non-readonly |
331 | eval { for("a") { for $x (1,2) { local $_="b"; s/(.*)/+$1/ } } }; |
d441d3db |
332 | is($@, ""); |
4cb09e0a |
333 | |
334 | # Special local() behavior for $[ |
335 | # (see RT #38207 - Useless localization of constant ($[) in getopts.pl} |
336 | { |
337 | local $[ = 1; |
338 | local $TODO = "local() not currently working correctly with \$["; |
339 | ok(1 == $[); |
340 | undef $TODO; |
341 | f(); |
342 | } |
343 | |
344 | sub f { ok(0 == $[); } |
345 | |
985d6f61 |
346 | # sub localisation |
347 | { |
348 | package Other; |
349 | |
350 | sub f1 { "f1" } |
351 | sub f2 { "f2" } |
352 | |
353 | no warnings "redefine"; |
354 | { |
355 | local *f1 = sub { "g1" }; |
356 | ::ok(f1() eq "g1", "localised sub via glob"); |
357 | } |
358 | ::ok(f1() eq "f1", "localised sub restored"); |
359 | { |
360 | local $Other::{"f1"} = sub { "h1" }; |
361 | ::ok(f1() eq "h1", "localised sub via stash"); |
362 | } |
363 | ::ok(f1() eq "f1", "localised sub restored"); |
364 | { |
365 | local @Other::{qw/ f1 f2 /} = (sub { "j1" }, sub { "j2" }); |
985d6f61 |
366 | ::ok(f1() eq "j1", "localised sub via stash slice"); |
367 | ::ok(f2() eq "j2", "localised sub via stash slice"); |
985d6f61 |
368 | } |
369 | ::ok(f1() eq "f1", "localised sub restored"); |
370 | ::ok(f2() eq "f2", "localised sub restored"); |
371 | } |
7d654f43 |
372 | |
373 | # Localising unicode keys (bug #38815) |
374 | { |
375 | my %h; |
376 | $h{"\243"} = "pound"; |
377 | $h{"\302\240"} = "octects"; |
378 | is(scalar keys %h, 2); |
379 | { |
380 | my $unicode = chr 256; |
381 | my $ambigous = "\240" . $unicode; |
382 | chop $ambigous; |
383 | local $h{$unicode} = 256; |
384 | local $h{$ambigous} = 160; |
385 | |
386 | is(scalar keys %h, 4); |
387 | is($h{"\243"}, "pound"); |
388 | is($h{$unicode}, 256); |
389 | is($h{$ambigous}, 160); |
390 | is($h{"\302\240"}, "octects"); |
391 | } |
392 | is(scalar keys %h, 2); |
393 | is($h{"\243"}, "pound"); |
394 | is($h{"\302\240"}, "octects"); |
395 | } |
919acde0 |
396 | |
397 | # And with slices |
398 | { |
399 | my %h; |
400 | $h{"\243"} = "pound"; |
401 | $h{"\302\240"} = "octects"; |
402 | is(scalar keys %h, 2); |
403 | { |
404 | my $unicode = chr 256; |
405 | my $ambigous = "\240" . $unicode; |
406 | chop $ambigous; |
407 | local @h{$unicode, $ambigous} = (256, 160); |
408 | |
409 | is(scalar keys %h, 4); |
410 | is($h{"\243"}, "pound"); |
411 | is($h{$unicode}, 256); |
412 | is($h{$ambigous}, 160); |
413 | is($h{"\302\240"}, "octects"); |
414 | } |
415 | is(scalar keys %h, 2); |
416 | is($h{"\243"}, "pound"); |
417 | is($h{"\302\240"}, "octects"); |
418 | } |
658aef79 |
419 | |
420 | # [perl #39012] localizing @_ element then shifting frees element too # soon |
421 | |
422 | { |
423 | my $x; |
424 | my $y = bless [], 'X39012'; |
425 | sub X39012::DESTROY { $x++ } |
426 | sub { local $_[0]; shift }->($y); |
427 | ok(!$x, '[perl #39012]'); |
428 | |
429 | } |
430 | |