1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
|
#!./perl
#
# test method calls and autoloading.
#
BEGIN {
chdir 't' if -d 't';
@INC = qw(. ../lib);
require "test.pl";
}
print "1..78\n";
@A::ISA = 'B';
@B::ISA = 'C';
sub C::d {"C::d"}
sub D::d {"D::d"}
# First, some basic checks of method-calling syntax:
$obj = bless [], "Pack";
sub Pack::method { shift; join(",", "method", @_) }
$mname = "method";
is(Pack->method("a","b","c"), "method,a,b,c");
is(Pack->$mname("a","b","c"), "method,a,b,c");
is(method Pack ("a","b","c"), "method,a,b,c");
is((method Pack "a","b","c"), "method,a,b,c");
is(Pack->method(), "method");
is(Pack->$mname(), "method");
is(method Pack (), "method");
is(Pack->method, "method");
is(Pack->$mname, "method");
is(method Pack, "method");
is($obj->method("a","b","c"), "method,a,b,c");
is($obj->$mname("a","b","c"), "method,a,b,c");
is((method $obj ("a","b","c")), "method,a,b,c");
is((method $obj "a","b","c"), "method,a,b,c");
is($obj->method(0), "method,0");
is($obj->method(1), "method,1");
is($obj->method(), "method");
is($obj->$mname(), "method");
is((method $obj ()), "method");
is($obj->method, "method");
is($obj->$mname, "method");
is(method $obj, "method");
is( A->d, "C::d"); # Update hash table;
*B::d = \&D::d; # Import now.
is(A->d, "D::d"); # Update hash table;
{
local @A::ISA = qw(C); # Update hash table with split() assignment
is(A->d, "C::d");
$#A::ISA = -1;
is(eval { A->d } || "fail", "fail");
}
is(A->d, "D::d");
{
local *B::d;
eval 'sub B::d {"B::d1"}'; # Import now.
is(A->d, "B::d1"); # Update hash table;
undef &B::d;
is((eval { A->d }, ($@ =~ /Undefined subroutine/)), 1);
}
is(A->d, "D::d"); # Back to previous state
eval 'sub B::d {"B::d2"}'; # Import now.
is(A->d, "B::d2"); # Update hash table;
# What follows is hardly guarantied to work, since the names in scripts
# are already linked to "pruned" globs. Say, `undef &B::d' if it were
# after `delete $B::{d}; sub B::d {}' would reach an old subroutine.
undef &B::d;
delete $B::{d};
is(A->d, "C::d"); # Update hash table;
eval 'sub B::d {"B::d3"}'; # Import now.
is(A->d, "B::d3"); # Update hash table;
delete $B::{d};
*dummy::dummy = sub {}; # Mark as updated
is(A->d, "C::d");
eval 'sub B::d {"B::d4"}'; # Import now.
is(A->d, "B::d4"); # Update hash table;
delete $B::{d}; # Should work without any help too
is(A->d, "C::d");
{
local *C::d;
is(eval { A->d } || "nope", "nope");
}
is(A->d, "C::d");
*A::x = *A::d; # See if cache incorrectly follows synonyms
A->d;
is(eval { A->x } || "nope", "nope");
eval <<'EOF';
sub C::e;
BEGIN { *B::e = \&C::e } # Shouldn't prevent AUTOLOAD in original pkg
sub Y::f;
$counter = 0;
@X::ISA = 'Y';
@Y::ISA = 'B';
sub B::AUTOLOAD {
my $c = ++$counter;
my $method = $B::AUTOLOAD;
my $msg = "B: In $method, $c";
eval "sub $method { \$msg }";
goto &$method;
}
sub C::AUTOLOAD {
my $c = ++$counter;
my $method = $C::AUTOLOAD;
my $msg = "C: In $method, $c";
eval "sub $method { \$msg }";
goto &$method;
}
EOF
is(A->e(), "C: In C::e, 1"); # We get a correct autoload
is(A->e(), "C: In C::e, 1"); # Which sticks
is(A->ee(), "B: In A::ee, 2"); # We get a generic autoload, method in top
is(A->ee(), "B: In A::ee, 2"); # Which sticks
is(Y->f(), "B: In Y::f, 3"); # We vivify a correct method
is(Y->f(), "B: In Y::f, 3"); # Which sticks
# This test is not intended to be reasonable. It is here just to let you
# know that you broke some old construction. Feel free to rewrite the test
# if your patch breaks it.
*B::AUTOLOAD = sub {
my $c = ++$counter;
my $method = $AUTOLOAD;
*$AUTOLOAD = sub { "new B: In $method, $c" };
goto &$AUTOLOAD;
};
is(A->eee(), "new B: In A::eee, 4"); # We get a correct $autoload
is(A->eee(), "new B: In A::eee, 4"); # Which sticks
# this test added due to bug discovery
is(defined(@{"unknown_package::ISA"}) ? "defined" : "undefined", "undefined");
# test that failed subroutine calls don't affect method calls
{
package A1;
sub foo { "foo" }
package A2;
@ISA = 'A1';
package main;
is(A2->foo(), "foo");
is(do { eval 'A2::foo()'; $@ ? 1 : 0}, 1);
is(A2->foo(), "foo");
}
## This test was totally misguided. It passed before only because the
## code to determine if a package was loaded used to look for the hash
## %Foo::Bar instead of the package Foo::Bar:: -- and Config.pm just
## happens to export %Config.
# {
# is(do { use Config; eval 'Config->foo()';
# $@ =~ /^\QCan't locate object method "foo" via package "Config" at/ ? 1 : $@}, 1);
# is(do { use Config; eval '$d = bless {}, "Config"; $d->foo()';
# $@ =~ /^\QCan't locate object method "foo" via package "Config" at/ ? 1 : $@}, 1);
# }
# test error messages if method loading fails
is(do { eval '$e = bless {}, "E::A"; E::A->foo()';
$@ =~ /^\QCan't locate object method "foo" via package "E::A" at/ ? 1 : $@}, 1);
is(do { eval '$e = bless {}, "E::B"; $e->foo()';
$@ =~ /^\QCan't locate object method "foo" via package "E::B" at/ ? 1 : $@}, 1);
is(do { eval 'E::C->foo()';
$@ =~ /^\QCan't locate object method "foo" via package "E::C" (perhaps / ? 1 : $@}, 1);
is(do { eval 'UNIVERSAL->E::D::foo()';
$@ =~ /^\QCan't locate object method "foo" via package "E::D" (perhaps / ? 1 : $@}, 1);
is(do { eval '$e = bless {}, "UNIVERSAL"; $e->E::E::foo()';
$@ =~ /^\QCan't locate object method "foo" via package "E::E" (perhaps / ? 1 : $@}, 1);
$e = bless {}, "E::F"; # force package to exist
is(do { eval 'UNIVERSAL->E::F::foo()';
$@ =~ /^\QCan't locate object method "foo" via package "E::F" at/ ? 1 : $@}, 1);
is(do { eval '$e = bless {}, "UNIVERSAL"; $e->E::F::foo()';
$@ =~ /^\QCan't locate object method "foo" via package "E::F" at/ ? 1 : $@}, 1);
# TODO: we need some tests for the SUPER:: pseudoclass
# failed method call or UNIVERSAL::can() should not autovivify packages
is( $::{"Foo::"} || "none", "none"); # sanity check 1
is( $::{"Foo::"} || "none", "none"); # sanity check 2
is( UNIVERSAL::can("Foo", "boogie") ? "yes":"no", "no" );
is( $::{"Foo::"} || "none", "none"); # still missing?
is( Foo->UNIVERSAL::can("boogie") ? "yes":"no", "no" );
is( $::{"Foo::"} || "none", "none"); # still missing?
is( Foo->can("boogie") ? "yes":"no", "no" );
is( $::{"Foo::"} || "none", "none"); # still missing?
is( eval 'Foo->boogie(); 1' ? "yes":"no", "no" );
is( $::{"Foo::"} || "none", "none"); # still missing?
is(do { eval 'Foo->boogie()';
$@ =~ /^\QCan't locate object method "boogie" via package "Foo" (perhaps / ? 1 : $@}, 1);
eval 'sub Foo::boogie { "yes, sir!" }';
is( $::{"Foo::"} ? "ok" : "none", "ok"); # should exist now
is( Foo->boogie(), "yes, sir!");
# TODO: universal.t should test NoSuchPackage->isa()/can()
# This is actually testing parsing of indirect objects and undefined subs
# print foo("bar") where foo does not exist is not an indirect object.
# print foo "bar" where foo does not exist is an indirect object.
eval 'sub AUTOLOAD { "ok ", shift, "\n"; }';
ok(1);
# Bug ID 20010902.002
is(
eval q[
$x = 'x';
sub Foo::x : lvalue { $x }
Foo->$x = 'ok';
] || $@, 'ok'
);
# An autoloaded, inherited DESTROY may be invoked differently than normal
# methods, and has been known to give rise to spurious warnings
# eg <200203121600.QAA11064@gizmo.fdgroup.co.uk>
{
use warnings;
my $w = '';
local $SIG{__WARN__} = sub { $w = $_[0] };
sub AutoDest::Base::AUTOLOAD {}
@AutoDest::ISA = qw(AutoDest::Base);
{ my $x = bless {}, 'AutoDest'; }
$w =~ s/\n//g;
is($w, '');
}
# [ID 20020305.025] PACKAGE::SUPER doesn't work anymore
package main;
our @X;
package Amajor;
sub test {
push @main::X, 'Amajor', @_;
}
package Bminor;
use base qw(Amajor);
package main;
sub Bminor::test {
$_[0]->Bminor::SUPER::test('x', 'y');
push @main::X, 'Bminor', @_;
}
Bminor->test('y', 'z');
is("@X", "Amajor Bminor x y Bminor Bminor y z");
package main;
for my $meth (['Bar', 'Foo::Bar'],
['SUPER::Bar', 'main::SUPER::Bar'],
['Xyz::SUPER::Bar', 'Xyz::SUPER::Bar'])
{
fresh_perl_is(<<EOT,
package UNIVERSAL; sub AUTOLOAD { my \$c = shift; print "\$c \$AUTOLOAD\\n" }
sub DESTROY {} # IO object destructor called in MacOS, because of Mac::err
package Xyz;
package main; Foo->$meth->[0]();
EOT
"Foo $meth->[1]",
{ switches => [ '-w' ] },
"check if UNIVERSAL::AUTOLOAD works",
);
}
|