Commit | Line | Data |
---|---|---|
204e6232 BF |
1 | #!./perl |
2 | ||
3 | BEGIN { | |
5b8bb896 | 4 | $ENV{PERL_UNICODE} = 0; |
204e6232 BF |
5 | unless (-d 'blib') { |
6 | chdir 't' if -d 't'; | |
7 | @INC = '../lib'; | |
8 | } | |
9 | require q(./test.pl); | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | use utf8; | |
15 | use open qw( :utf8 :std ); | |
16 | ||
17 | plan(tests => 52); | |
18 | ||
19 | { | |
20 | package Neẁ; | |
21 | use strict; | |
22 | use warnings; | |
23 | ||
24 | package ऑlㄉ; | |
25 | use strict; | |
26 | use warnings; | |
27 | ||
28 | { | |
29 | no strict 'refs'; | |
30 | *{'ऑlㄉ::'} = *{'Neẁ::'}; | |
31 | } | |
32 | } | |
33 | ||
34 | ok (ऑlㄉ->isa(Neẁ::), 'ऑlㄉ inherits from Neẁ'); | |
35 | ok (Neẁ->isa(ऑlㄉ::), 'Neẁ inherits from ऑlㄉ'); | |
36 | ||
bbce3ca6 MS |
37 | object_ok (bless ({}, ऑlㄉ::), Neẁ::, 'ऑlㄉ object'); |
38 | object_ok (bless ({}, Neẁ::), ऑlㄉ::, 'Neẁ object'); | |
204e6232 BF |
39 | |
40 | ||
41 | # Test that replacing a package by assigning to an existing glob | |
42 | # invalidates the isa caches | |
43 | for( | |
44 | { | |
45 | name => 'assigning a glob to a glob', | |
46 | code => '$life_raft = $::{"lㅔf::"}; *lㅔf:: = $::{"릭Ⱶᵀ::"}', | |
47 | }, | |
48 | { | |
49 | name => 'assigning a string to a glob', | |
50 | code => '$life_raft = $::{"lㅔf::"}; *lㅔf:: = "릭Ⱶᵀ::"', | |
51 | }, | |
52 | { | |
53 | name => 'assigning a stashref to a glob', | |
54 | code => '$life_raft = \%lㅔf::; *lㅔf:: = \%릭Ⱶᵀ::', | |
55 | }, | |
56 | ) { | |
57 | my $prog = q~ | |
58 | BEGIN { | |
59 | unless (-d 'blib') { | |
60 | chdir 't' if -d 't'; | |
61 | @INC = '../lib'; | |
62 | } | |
63 | } | |
64 | use utf8; | |
65 | use open qw( :utf8 :std ); | |
66 | ||
67 | @숩cਲꩋ::ISA = "lㅔf"; | |
68 | @lㅔf::ISA = "톺ĺФț"; | |
69 | ||
70 | sub 톺ĺФț::Sᑊeಅḱ { "Woof!" } | |
71 | sub ᴖ릭ᚽʇ::Sᑊeಅḱ { "Bow-wow!" } | |
72 | ||
73 | my $thing = bless [], "숩cਲꩋ"; | |
74 | ||
75 | # mro_package_moved needs to know to skip non-globs | |
76 | $릭Ⱶᵀ::{"ᚷꝆエcƙ::"} = 3; | |
77 | ||
78 | @릭Ⱶᵀ::ISA = 'ᴖ릭ᚽʇ'; | |
79 | my $life_raft; | |
80 | __code__; | |
81 | ||
82 | print $thing->Sᑊeಅḱ, "\n"; | |
83 | ||
84 | undef $life_raft; | |
85 | print $thing->Sᑊeಅḱ, "\n"; | |
86 | ~ =~ s\__code__\$$_{code}\r; #\ | |
87 | utf8::encode($prog); | |
88 | fresh_perl_is | |
89 | $prog, | |
90 | "Bow-wow!\nBow-wow!\n", | |
91 | {}, | |
92 | "replacing packages by $$_{name} updates isa caches"; | |
93 | } | |
94 | ||
95 | # Similar test, but with nested packages | |
96 | # | |
97 | # 톺ĺФț (Woof) ᴖ릭ᚽʇ (Bow-wow) | |
98 | # | | | |
99 | # lㅔf::Side <- 릭Ⱶᵀ::Side | |
100 | # | | |
101 | # 숩cਲꩋ | |
102 | # | |
103 | # This test assigns 릭Ⱶᵀ:: to lㅔf::, indirectly making lㅔf::Side an | |
104 | # alias to 릭Ⱶᵀ::Side (following the arrow in the diagram). | |
105 | for( | |
106 | { | |
107 | name => 'assigning a glob to a glob', | |
108 | code => '$life_raft = $::{"lㅔf::"}; *lㅔf:: = $::{"릭Ⱶᵀ::"}', | |
109 | }, | |
110 | { | |
111 | name => 'assigning a string to a glob', | |
112 | code => '$life_raft = $::{"lㅔf::"}; *lㅔf:: = "릭Ⱶᵀ::"', | |
113 | }, | |
114 | { | |
115 | name => 'assigning a stashref to a glob', | |
116 | code => '$life_raft = \%lㅔf::; *lㅔf:: = \%릭Ⱶᵀ::', | |
117 | }, | |
118 | ) { | |
119 | my $prog = q~ | |
120 | BEGIN { | |
121 | unless (-d 'blib') { | |
122 | chdir 't' if -d 't'; | |
123 | @INC = '../lib'; | |
124 | } | |
125 | } | |
126 | use utf8; | |
127 | use open qw( :utf8 :std ); | |
128 | @숩cਲꩋ::ISA = "lㅔf::Side"; | |
129 | @lㅔf::Side::ISA = "톺ĺФț"; | |
130 | ||
131 | sub 톺ĺФț::Sᑊeಅḱ { "Woof!" } | |
132 | sub ᴖ릭ᚽʇ::Sᑊeಅḱ { "Bow-wow!" } | |
133 | ||
134 | my $thing = bless [], "숩cਲꩋ"; | |
135 | ||
136 | @릭Ⱶᵀ::Side::ISA = 'ᴖ릭ᚽʇ'; | |
137 | my $life_raft; | |
138 | __code__; | |
139 | ||
140 | print $thing->Sᑊeಅḱ, "\n"; | |
141 | ||
142 | undef $life_raft; | |
143 | print $thing->Sᑊeಅḱ, "\n"; | |
144 | ~ =~ s\__code__\$$_{code}\r; | |
145 | utf8::encode($prog); | |
146 | ||
147 | fresh_perl_is | |
148 | $prog, | |
149 | "Bow-wow!\nBow-wow!\n", | |
150 | {}, | |
151 | "replacing nested packages by $$_{name} updates isa caches"; | |
152 | } | |
153 | ||
154 | # Another nested package test, in which the isa cache needs to be reset on | |
155 | # the subclass of a package that does not exist. | |
156 | # | |
157 | # Parenthesized packages do not exist. | |
158 | # | |
159 | # ɵűʇㄦ::인ንʵ ( cฬnए::인ንʵ ) | |
160 | # | | | |
161 | # Lфť R익hȚ | |
162 | # | |
163 | # ɵűʇㄦ -> cฬnए | |
164 | # | |
165 | # This test assigns ɵűʇㄦ:: to cฬnए::, making cฬnए::인ንʵ an alias to | |
166 | # ɵűʇㄦ::인ንʵ. | |
167 | # | |
168 | # Then we also run the test again, but without ɵűʇㄦ::인ንʵ | |
169 | for( | |
170 | { | |
171 | name => 'assigning a glob to a glob', | |
172 | code => '*cฬnए:: = *ɵűʇㄦ::', | |
173 | }, | |
174 | { | |
175 | name => 'assigning a string to a glob', | |
176 | code => '*cฬnए:: = "ɵűʇㄦ::"', | |
177 | }, | |
178 | { | |
179 | name => 'assigning a stashref to a glob', | |
180 | code => '*cฬnए:: = \%ɵűʇㄦ::', | |
181 | }, | |
182 | ) { | |
183 | for my $tail ('인ንʵ', '인ንʵ::', '인ንʵ:::', '인ንʵ::::') { | |
184 | my $prog = q~ | |
185 | BEGIN { | |
186 | unless (-d 'blib') { | |
187 | chdir 't' if -d 't'; | |
188 | @INC = '../lib'; | |
189 | } | |
190 | } | |
191 | use utf8; | |
192 | use open qw( :utf8 :std ); | |
193 | use Encode (); | |
194 | ||
195 | if (grep /\P{ASCII}/, @ARGV) { | |
196 | @ARGV = map { Encode::decode("UTF-8", $_) } @ARGV; | |
197 | } | |
198 | ||
199 | my $tail = shift; | |
200 | @Lфť::ISA = "ɵűʇㄦ::$tail"; | |
201 | @R익hȚ::ISA = "cฬnए::$tail"; | |
202 | bless [], "ɵűʇㄦ::$tail"; # autovivify the stash | |
203 | ||
204 | __code__; | |
205 | ||
206 | print "ok 1", "\n" if Lфť->isa("cฬnए::$tail"); | |
207 | print "ok 2", "\n" if R익hȚ->isa("ɵűʇㄦ::$tail"); | |
208 | print "ok 3", "\n" if R익hȚ->isa("cฬnए::$tail"); | |
209 | print "ok 4", "\n" if Lфť->isa("ɵűʇㄦ::$tail"); | |
210 | ~ =~ s\__code__\$$_{code}\r; | |
211 | utf8::encode($prog); | |
212 | fresh_perl_is | |
213 | $prog, | |
214 | "ok 1\nok 2\nok 3\nok 4\n", | |
215 | { args => [$tail] }, | |
216 | "replacing nonexistent nested packages by $$_{name} updates isa caches" | |
217 | ." ($tail)"; | |
218 | ||
219 | # Same test but with the subpackage autovivified after the assignment | |
220 | $prog = q~ | |
221 | BEGIN { | |
222 | unless (-d 'blib') { | |
223 | chdir 't' if -d 't'; | |
224 | @INC = '../lib'; | |
225 | } | |
226 | } | |
227 | use utf8; | |
228 | use open qw( :utf8 :std ); | |
229 | use Encode (); | |
230 | ||
231 | if (grep /\P{ASCII}/, @ARGV) { | |
232 | @ARGV = map { Encode::decode("UTF-8", $_) } @ARGV; | |
233 | } | |
234 | ||
235 | my $tail = shift; | |
236 | @Lфť::ISA = "ɵűʇㄦ::$tail"; | |
237 | @R익hȚ::ISA = "cฬnए::$tail"; | |
238 | ||
239 | __code__; | |
240 | ||
241 | bless [], "ɵűʇㄦ::$tail"; | |
242 | ||
243 | print "ok 1", "\n" if Lфť->isa("cฬnए::$tail"); | |
244 | print "ok 2", "\n" if R익hȚ->isa("ɵűʇㄦ::$tail"); | |
245 | print "ok 3", "\n" if R익hȚ->isa("cฬnए::$tail"); | |
246 | print "ok 4", "\n" if Lфť->isa("ɵűʇㄦ::$tail"); | |
247 | ~ =~ s\__code__\$$_{code}\r; | |
248 | utf8::encode($prog); | |
249 | fresh_perl_is | |
250 | $prog, | |
251 | "ok 1\nok 2\nok 3\nok 4\n", | |
252 | { args => [$tail] }, | |
253 | "Giving nonexistent packages multiple effective names by $$_{name}" | |
254 | . " ($tail)"; | |
255 | } | |
256 | } | |
257 | ||
258 | no warnings; # temporary; there seems to be a scoping bug, as this does not | |
259 | # work when placed in the blocks below | |
260 | ||
261 | # Test that deleting stash elements containing | |
262 | # subpackages also invalidates the isa cache. | |
263 | # Maybe this does not belong in package_aliases.t, but it is closely | |
264 | # related to the tests immediately preceding. | |
265 | { | |
266 | @ቹऋ::ISA = ("Cuȓ", "ฮンᛞ"); | |
267 | @Cuȓ::ISA = "Hyḹ앛Ҭテ"; | |
268 | ||
269 | sub Hyḹ앛Ҭテ::Sᑊeಅḱ { "Arff!" } | |
270 | sub ฮンᛞ::Sᑊeಅḱ { "Woof!" } | |
271 | ||
272 | my $pet = bless [], "ቹऋ"; | |
273 | ||
274 | my $life_raft = delete $::{'Cuȓ::'}; | |
275 | ||
276 | is $pet->Sᑊeಅḱ, 'Woof!', | |
277 | 'deleting a stash from its parent stash invalidates the isa caches'; | |
278 | ||
279 | undef $life_raft; | |
280 | is $pet->Sᑊeಅḱ, 'Woof!', | |
281 | 'the deleted stash is gone completely when freed'; | |
282 | } | |
283 | # Same thing, but with nested packages | |
284 | { | |
285 | @펱ᑦ::ISA = ("Cuȓȓ::Cuȓȓ::Cuȓȓ", "ɥwn"); | |
286 | @Cuȓȓ::Cuȓȓ::Cuȓȓ::ISA = "lȺt랕ᚖ"; | |
287 | ||
288 | sub lȺt랕ᚖ::Sᑊeಅḱ { "Arff!" } | |
289 | sub ɥwn::Sᑊeಅḱ { "Woof!" } | |
290 | ||
291 | my $pet = bless [], "펱ᑦ"; | |
292 | ||
293 | my $life_raft = delete $::{'Cuȓȓ::'}; | |
294 | ||
295 | is $pet->Sᑊeಅḱ, 'Woof!', | |
296 | 'deleting a stash from its parent stash resets caches of substashes'; | |
297 | ||
298 | undef $life_raft; | |
299 | is $pet->Sᑊeಅḱ, 'Woof!', | |
300 | 'the deleted substash is gone completely when freed'; | |
301 | } | |
302 | ||
303 | # [perl #77358] | |
304 | my $prog = q~#!perl -w | |
305 | BEGIN { | |
306 | unless (-d 'blib') { | |
307 | chdir 't' if -d 't'; | |
308 | @INC = '../lib'; | |
309 | } | |
310 | } | |
311 | use utf8; | |
312 | use open qw( :utf8 :std ); | |
313 | @펱ᑦ::ISA = "T잌ዕ"; | |
314 | @T잌ዕ::ISA = "Bᛆヶṝ"; | |
315 | ||
316 | sub Bᛆヶṝ::Sᑊeಅḱ { print "Woof!\n" } | |
317 | sub lȺt랕ᚖ::Sᑊeಅḱ { print "Bow-wow!\n" } | |
318 | ||
319 | my $pet = bless [], "펱ᑦ"; | |
320 | ||
321 | $pet->Sᑊeಅḱ; | |
322 | ||
323 | sub ດƓ::Sᑊeಅḱ { print "Hello.\n" } # strange ດƓ! | |
324 | @ດƓ::ISA = 'lȺt랕ᚖ'; | |
325 | *T잌ዕ:: = delete $::{'ດƓ::'}; | |
326 | ||
327 | $pet->Sᑊeಅḱ; | |
328 | ~; | |
329 | utf8::encode($prog); | |
330 | fresh_perl_is | |
331 | $prog, | |
332 | "Woof!\nHello.\n", | |
333 | { stderr => 1 }, | |
334 | "Assigning a nameless package over one w/subclasses updates isa caches"; | |
335 | ||
336 | # mro_package_moved needs to make a distinction between replaced and | |
337 | # assigned stashes when keeping track of what it has seen so far. | |
338 | no warnings; { | |
339 | no strict 'refs'; | |
340 | ||
341 | sub ʉ::bᓗnǩ::bᓗnǩ::ພo { "bbb" } | |
342 | sub ᵛeↄl움::ພo { "lasrevinu" } | |
343 | @ݏ엗Ƚeᵬૐᵖ::ISA = qw 'ພo::bᓗnǩ::bᓗnǩ ᵛeↄl움'; | |
344 | *ພo::ବㄗ:: = *ʉ::bᓗnǩ::; # now ʉ::bᓗnǩ:: is on both sides | |
345 | *ພo:: = *ʉ::; # here ʉ::bᓗnǩ:: is both deleted and added | |
346 | *ʉ:: = *ቦᵕ::; # now it is only known as ພo::bᓗnǩ:: | |
347 | ||
348 | # At this point, before the bug was fixed, %ພo::bᓗnǩ::bᓗnǩ:: ended | |
349 | # up with no effective name, allowing it to be deleted without updating | |
350 | # its subclassesâ\80\99 caches. | |
351 | ||
352 | my $accum = ''; | |
353 | ||
354 | $accum .= 'ݏ엗Ƚeᵬૐᵖ'->ພo; # bbb | |
355 | delete ${"ພo::bᓗnǩ::"}{"bᓗnǩ::"}; | |
356 | $accum .= 'ݏ엗Ƚeᵬૐᵖ'->ພo; # bbb (Oops!) | |
357 | @ݏ엗Ƚeᵬૐᵖ::ISA = @ݏ엗Ƚeᵬૐᵖ::ISA; | |
358 | $accum .= 'ݏ엗Ƚeᵬૐᵖ'->ພo; # lasrevinu | |
359 | ||
360 | is $accum, 'bbblasrevinulasrevinu', | |
361 | 'nested classes deleted & added simultaneously'; | |
362 | } | |
363 | use warnings; | |
364 | ||
365 | # mro_package_moved needs to check for self-referential packages. | |
366 | # This broke Text::Template [perl #78362]. | |
367 | watchdog 3; | |
368 | *ᕘ:: = \%::; | |
369 | *Aᶜme::Mῌ::Aᶜme:: = \*Aᶜme::; # indirect self-reference | |
370 | pass("mro_package_moved and self-referential packages"); | |
371 | ||
372 | # Deleting a glob whose name does not indicate its location in the symbol | |
373 | # table but which nonetheless *is* in the symbol table. | |
374 | { | |
375 | no strict refs=>; | |
376 | no warnings; | |
377 | @ოƐ::mഒrェ::ISA = "foᚒ"; | |
378 | sub foᚒ::ວmᑊ { "aoeaa" } | |
379 | *ťວ:: = *ოƐ::; | |
380 | delete $::{"ოƐ::"}; | |
381 | @C힐dᒡl았::ISA = 'ťວ::mഒrェ'; | |
382 | my $accum = 'C힐dᒡl았'->ວmᑊ . '-'; | |
383 | my $life_raft = delete ${"ťວ::"}{"mഒrェ::"}; | |
384 | $accum .= eval { 'C힐dᒡl았'->ວmᑊ } // '<undef>'; | |
385 | is $accum, 'aoeaa-<undef>', | |
386 | 'Deleting globs whose loc in the symtab differs from gv_fullname' | |
387 | } | |
388 | ||
389 | # Pathological test for undeffing a stash that has an alias. | |
390 | *ᵍh엞:: = *ኔƞ::; | |
391 | @숩cਲꩋ::ISA = 'ᵍh엞'; | |
392 | undef %ᵍh엞::; | |
393 | sub F렐ᛔ::ວmᑊ { "clumpren" } | |
394 | eval ' | |
395 | $ኔƞ::whatever++; | |
396 | @ኔƞ::ISA = "F렐ᛔ"; | |
397 | '; | |
398 | is eval { '숩cਲꩋ'->ວmᑊ }, 'clumpren', | |
399 | 'Changes to @ISA after undef via original name'; | |
400 | undef %ᵍh엞::; | |
401 | eval ' | |
402 | $ᵍh엞::whatever++; | |
403 | @ᵍh엞::ISA = "F렐ᛔ"; | |
404 | '; | |
405 | is eval { '숩cਲꩋ'->ວmᑊ }, 'clumpren', | |
406 | 'Changes to @ISA after undef via alias'; | |
407 | ||
408 | ||
409 | # Packages whose containing stashes have aliases must lose all names cor- | |
410 | # responding to that container when detached. | |
411 | { | |
412 | {package śmᛅḙ::በɀ} # autovivify | |
413 | *pḢ린ᚷ:: = *śmᛅḙ::; # śmᛅḙ::በɀ now also named pḢ린ᚷ::በɀ | |
414 | *본:: = delete $śmᛅḙ::{"በɀ::"}; | |
415 | # In 5.13.7, it has now lost its śmᛅḙ::በɀ name (reverting to pḢ린ᚷ::በɀ | |
416 | # as the effective name), and gained 본 as an alias. | |
417 | # In 5.13.8, both śmᛅḙ::በɀ *and* pḢ린ᚷ::በɀ names are deleted. | |
418 | ||
419 | # Make some methods | |
420 | no strict 'refs'; | |
421 | *{"pḢ린ᚷ::በɀ::fฤmᛈ"} = sub { "hello" }; | |
422 | sub Fルmፕṟ::fฤmᛈ { "good bye" }; | |
423 | ||
424 | @ᵇるᣘ킨::ISA = qw "본 Fルmፕṟ"; # now wrongly inherits from pḢ린ᚷ::በɀ | |
425 | ||
426 | is fฤmᛈ ᵇるᣘ킨, "good bye", | |
427 | 'detached stashes lose all names corresponding to the containing stash'; | |
428 | } | |
429 | ||
430 | # Crazy edge cases involving packages ending with a single : | |
431 | @촐oン::ISA = 'ᚖგ:'; # pun intended! | |
432 | bless [], "ᚖგ:"; # autovivify the stash | |
433 | ok "촐oン"->isa("ᚖგ:"), 'class isa "class:"'; | |
434 | { no strict 'refs'; *{"ᚖგ:::"} = *ᚖგ:: } | |
435 | ok "촐oン"->isa("ᚖგ"), | |
436 | 'isa(ᕘ) when inheriting from "class:" which is an alias for ᕘ'; | |
437 | { | |
438 | no warnings; | |
439 | # The next line of code is *not* normative. If the structure changes, | |
440 | # this line needs to change, too. | |
441 | my $ᕘ = delete $ᚖგ::{":"}; | |
442 | ok !촐oン->isa("ᚖგ"), | |
443 | 'class that isa "class:" no longer isa ᕘ if "class:" has been deleted'; | |
444 | } | |
445 | @촐oン::ISA = ':'; | |
446 | bless [], ":"; | |
447 | ok "촐oン"->isa(":"), 'class isa ":"'; | |
448 | { no strict 'refs'; *{":::"} = *ፑňṪu앝ȋ온:: } | |
449 | ok "촐oン"->isa("ፑňṪu앝ȋ온"), | |
450 | 'isa(ᕘ) when inheriting from ":" which is an alias for ᕘ'; | |
451 | @촐oン::ISA = 'ᚖგ:'; | |
452 | bless [], "ᚖგ:"; | |
453 | { | |
454 | no strict 'refs'; | |
455 | my $life_raft = \%{"ᚖგ:::"}; | |
456 | *{"ᚖგ:::"} = \%ᚖგ::; | |
457 | ok "촐oン"->isa("ᚖგ"), | |
458 | 'isa(ᕘ) when inheriting from "class:" after hash-to-glob assignment'; | |
459 | } | |
460 | @촐oン::ISA = 'ŏ:'; | |
461 | bless [], "ŏ:"; | |
462 | { | |
463 | no strict 'refs'; | |
464 | my $life_raft = \%{"ŏ:::"}; | |
465 | *{"ŏ:::"} = "ᚖგ::"; | |
466 | ok "촐oン"->isa("ᚖგ"), | |
467 | 'isa(ᕘ) when inheriting from "class:" after string-to-glob assignment'; | |
468 | } | |
469 | =cut |