26 *{'Old::'} = *{'New::'};
30 ok (Old->isa (New::), 'Old inherits from New');
31 ok (New->isa (Old::), 'New inherits from Old');
33 object_ok (bless ({}, Old::), New::, 'Old object');
34 object_ok (bless ({}, New::), Old::, 'New object');
37 # Test that replacing a package by assigning to an existing glob
38 # invalidates the isa caches
41 name => 'assigning a glob to a glob',
42 code => '$life_raft = $::{"Left::"}; *Left:: = $::{"Right::"}',
45 name => 'assigning a string to a glob',
46 code => '$life_raft = $::{"Left::"}; *Left:: = "Right::"',
49 name => 'assigning a stashref to a glob',
50 code => '$life_raft = \%Left::; *Left:: = \%Right::',
55 @Subclass::ISA = "Left";
56 @Left::ISA = "TopLeft";
58 sub TopLeft::speak { "Woof!" }
59 sub TopRight::speak { "Bow-wow!" }
61 my $thing = bless [], "Subclass";
63 # mro_package_moved needs to know to skip non-globs
64 $Right::{"gleck::"} = 3;
66 @Right::ISA = 'TopRight';
70 print $thing->speak, "\n";
73 print $thing->speak, "\n";
74 ~ =~ s\__code__\$$_{code}\r,
75 "Bow-wow!\nBow-wow!\n",
77 "replacing packages by $$_{name} updates isa caches";
80 # Similar test, but with nested packages
82 # TopLeft (Woof) TopRight (Bow-wow)
84 # Left::Side <- Right::Side
88 # This test assigns Right:: to Left::, indirectly making Left::Side an
89 # alias to Right::Side (following the arrow in the diagram).
92 name => 'assigning a glob to a glob',
93 code => '$life_raft = $::{"Left::"}; *Left:: = $::{"Right::"}',
96 name => 'assigning a string to a glob',
97 code => '$life_raft = $::{"Left::"}; *Left:: = "Right::"',
100 name => 'assigning a stashref to a glob',
101 code => '$life_raft = \%Left::; *Left:: = \%Right::',
106 @Subclass::ISA = "Left::Side";
107 @Left::Side::ISA = "TopLeft";
109 sub TopLeft::speak { "Woof!" }
110 sub TopRight::speak { "Bow-wow!" }
112 my $thing = bless [], "Subclass";
114 @Right::Side::ISA = 'TopRight';
118 print $thing->speak, "\n";
121 print $thing->speak, "\n";
122 ~ =~ s\__code__\$$_{code}\r,
123 "Bow-wow!\nBow-wow!\n",
125 "replacing nested packages by $$_{name} updates isa caches";
128 # Another nested package test, in which the isa cache needs to be reset on
129 # the subclass of a package that does not exist.
131 # Parenthesized packages do not exist.
133 # outer::inner ( clone::inner )
139 # This test assigns outer:: to clone::, making clone::inner an alias to
142 # Then we also run the test again, but without outer::inner
145 name => 'assigning a glob to a glob',
146 code => '*clone:: = *outer::',
149 name => 'assigning a string to a glob',
150 code => '*clone:: = "outer::"',
153 name => 'assigning a stashref to a glob',
154 code => '*clone:: = \%outer::',
157 for my $tail ('inner', 'inner::', 'inner:::', 'inner::::') {
161 @left::ISA = "outer::$tail";
162 @right::ISA = "clone::$tail";
163 bless [], "outer::$tail"; # autovivify the stash
167 print "ok 1", "\n" if left->isa("clone::$tail");
168 print "ok 2", "\n" if right->isa("outer::$tail");
169 print "ok 3", "\n" if right->isa("clone::$tail");
170 print "ok 4", "\n" if left->isa("outer::$tail");
171 ~ =~ s\__code__\$$_{code}\r,
172 "ok 1\nok 2\nok 3\nok 4\n",
174 "replacing nonexistent nested packages by $$_{name} updates isa caches"
177 # Same test but with the subpackage autovivified after the assignment
181 @left::ISA = "outer::$tail";
182 @right::ISA = "clone::$tail";
186 bless [], "outer::$tail";
188 print "ok 1", "\n" if left->isa("clone::$tail");
189 print "ok 2", "\n" if right->isa("outer::$tail");
190 print "ok 3", "\n" if right->isa("clone::$tail");
191 print "ok 4", "\n" if left->isa("outer::$tail");
192 ~ =~ s\__code__\$$_{code}\r,
193 "ok 1\nok 2\nok 3\nok 4\n",
195 "Giving nonexistent packages multiple effective names by $$_{name}"
200 no warnings; # temporary; there seems to be a scoping bug, as this does not
201 # work when placed in the blocks below
203 # Test that deleting stash elements containing
204 # subpackages also invalidates the isa cache.
205 # Maybe this does not belong in package_aliases.t, but it is closely
206 # related to the tests immediately preceding.
208 @Pet::ISA = ("Cur", "Hound");
209 @Cur::ISA = "Hylactete";
211 sub Hylactete::speak { "Arff!" }
212 sub Hound::speak { "Woof!" }
214 my $pet = bless [], "Pet";
216 my $life_raft = delete $::{'Cur::'};
218 is $pet->speak, 'Woof!',
219 'deleting a stash from its parent stash invalidates the isa caches';
222 is $pet->speak, 'Woof!',
223 'the deleted stash is gone completely when freed';
225 # Same thing, but with nested packages
227 @Pett::ISA = ("Curr::Curr::Curr", "Hownd");
228 @Curr::Curr::Curr::ISA = "Latrator";
230 sub Latrator::speak { "Arff!" }
231 sub Hownd::speak { "Woof!" }
233 my $pet = bless [], "Pett";
235 my $life_raft = delete $::{'Curr::'};
237 is $pet->speak, 'Woof!',
238 'deleting a stash from its parent stash resets caches of substashes';
241 is $pet->speak, 'Woof!',
242 'the deleted substash is gone completely when freed';
249 @Tike::ISA = "Barker";
251 sub Barker::speak { print "Woof!\n" }
252 sub Latrator::speak { print "Bow-wow!\n" }
254 my $pet = bless [], "Pet";
258 sub Dog::speak { print "Hello.\n" } # strange dog!
259 @Dog::ISA = 'Latrator';
260 *Tike:: = delete $::{'Dog::'};
266 "Assigning a nameless package over one w/subclasses updates isa caches";
268 # mro_package_moved needs to make a distinction between replaced and
269 # assigned stashes when keeping track of what it has seen so far.
273 sub bar::blonk::blonk::phoo { "bbb" }
274 sub veclum::phoo { "lasrevinu" }
275 @feedlebomp::ISA = qw 'phoo::blonk::blonk veclum';
276 *phoo::baz:: = *bar::blonk::; # now bar::blonk:: is on both sides
277 *phoo:: = *bar::; # here bar::blonk:: is both deleted and added
278 *bar:: = *boo::; # now it is only known as phoo::blonk::
280 # At this point, before the bug was fixed, %phoo::blonk::blonk:: ended
281 # up with no effective name, allowing it to be deleted without updating
282 # its subclasses’ caches.
286 $accum .= 'feedlebomp'->phoo; # bbb
287 delete ${"phoo::blonk::"}{"blonk::"};
288 $accum .= 'feedlebomp'->phoo; # bbb (Oops!)
289 @feedlebomp::ISA = @feedlebomp::ISA;
290 $accum .= 'feedlebomp'->phoo; # lasrevinu
292 is $accum, 'bbblasrevinulasrevinu',
293 'nested classes deleted & added simultaneously';
297 # mro_package_moved needs to check for self-referential packages.
298 # This broke Text::Template [perl #78362].
301 *Acme::META::Acme:: = \*Acme::; # indirect self-reference
302 pass("mro_package_moved and self-referential packages");
304 # Deleting a glob whose name does not indicate its location in the symbol
305 # table but which nonetheless *is* in the symbol table.
309 @one::more::ISA = "four";
310 sub four::womp { "aoeaa" }
313 @Childclass::ISA = 'two::more';
314 my $accum = 'Childclass'->womp . '-';
315 my $life_raft = delete ${"two::"}{"more::"};
316 $accum .= eval { 'Childclass'->womp } // '<undef>';
317 is $accum, 'aoeaa-<undef>',
318 'Deleting globs whose loc in the symtab differs from gv_fullname'
321 # Pathological test for undeffing a stash that has an alias.
323 @Subclass::ISA = 'Ghelp';
325 sub Frelp::womp { "clumpren" }
328 @Neen::ISA = "Frelp";
330 is eval { 'Subclass'->womp }, 'clumpren',
331 'Changes to @ISA after undef via original name';
335 @Ghelp::ISA = "Frelp";
337 is eval { 'Subclass'->womp }, 'clumpren',
338 'Changes to @ISA after undef via alias';
341 # Packages whose containing stashes have aliases must lose all names cor-
342 # responding to that container when detached.
344 {package smare::baz} # autovivify
345 *phring:: = *smare::; # smare::baz now also named phring::baz
346 *bonk:: = delete $smare::{"baz::"};
347 # In 5.13.7, it has now lost its smare::baz name (reverting to phring::baz
348 # as the effective name), and gained bonk as an alias.
349 # In 5.13.8, both smare::baz *and* phring::baz names are deleted.
353 *{"phring::baz::frump"} = sub { "hello" };
354 sub frumper::frump { "good bye" };
356 @brumkin::ISA = qw "bonk frumper"; # now wrongly inherits from phring::baz
358 is frump brumkin, "good bye",
359 'detached stashes lose all names corresponding to the containing stash';
362 # Crazy edge cases involving packages ending with a single :
363 @Colon::ISA = 'Organ:'; # pun intended!
364 bless [], "Organ:"; # autovivify the stash
365 ok "Colon"->isa("Organ:"), 'class isa "class:"';
366 { no strict 'refs'; *{"Organ:::"} = *Organ:: }
367 ok "Colon"->isa("Organ"),
368 'isa(foo) when inheriting from "class:" which is an alias for foo';
371 # The next line of code is *not* normative. If the structure changes,
372 # this line needs to change, too.
373 my $foo = delete $Organ::{":"};
374 ok !Colon->isa("Organ"),
375 'class that isa "class:" no longer isa foo if "class:" has been deleted';
379 ok "Colon"->isa(":"), 'class isa ":"';
380 { no strict 'refs'; *{":::"} = *Punctuation:: }
381 ok "Colon"->isa("Punctuation"),
382 'isa(foo) when inheriting from ":" which is an alias for foo';
383 @Colon::ISA = 'Organ:';
387 my $life_raft = \%{"Organ:::"};
388 *{"Organ:::"} = \%Organ::;
389 ok "Colon"->isa("Organ"),
390 'isa(foo) when inheriting from "class:" after hash-to-glob assignment';
396 my $life_raft = \%{"O:::"};
397 *{"O:::"} = "Organ::";
398 ok "Colon"->isa("Organ"),
399 'isa(foo) when inheriting from "class:" after string-to-glob assignment';