1#!./perl -w 2 3BEGIN { 4 if ($ENV{PERL_CORE}) { 5 chdir 't' if -d 't'; 6 #@INC = '../lib'; 7 } 8} 9 10use strict; 11use File::Spec; 12use File::Path; 13 14my $dir; 15BEGIN 16{ 17 $dir = File::Spec->catdir( "auto-$$" ); 18 unshift @INC, $dir; 19} 20 21use Test::More tests => 21; 22 23sub write_file { 24 my ($file, $text) = @_; 25 open my $fh, '>', $file 26 or die "Could not open file '$file' for writing: $!"; 27 print $fh $text; 28 close $fh; 29} 30 31# First we must set up some autoloader files 32my $fulldir = File::Spec->catdir( $dir, 'auto', 'Foo' ); 33mkpath( $fulldir ) or die "Can't mkdir '$fulldir': $!"; 34 35write_file( File::Spec->catfile( $fulldir, 'foo.al' ), <<'EOT' ); 36package Foo; 37sub foo { shift; shift || "foo" } 381; 39EOT 40 41write_file( File::Spec->catfile( $fulldir, 'bazmarkhian.al' ), <<'EOT' ); 42package Foo; 43sub bazmarkhianish { shift; shift || "baz" } 441; 45EOT 46 47my $blechanawilla_text = <<'EOT'; 48package Foo; 49sub blechanawilla { compilation error ( 50EOT 51write_file( File::Spec->catfile( $fulldir, 'blechanawilla.al' ), $blechanawilla_text ); 52# This is just to keep the old SVR3 systems happy; they may fail 53# to find the above file so we duplicate it where they should find it. 54write_file( File::Spec->catfile( $fulldir, 'blechanawil.al' ), $blechanawilla_text ); 55 56write_file( File::Spec->catfile( $fulldir, 'notreached.al' ), <<'EOT' ); 57package Foo; 58sub notreached { die "Should not be reached!" } 591; 60EOT 61 62# Let's define the package 63package Foo; 64require AutoLoader; 65AutoLoader->import( 'AUTOLOAD' ); 66 67sub new { bless {}, shift }; 68sub foo; 69sub bazmarkhianish; 70sub notreached; 71 72package main; 73 74my $foo = Foo->new(); 75 76my $result = $foo->can( 'foo' ); 77ok( $result, 'can() first time' ); 78is( $foo->foo, 'foo', 'autoloaded first time' ); 79is( $foo->foo, 'foo', 'regular call' ); 80is( $result, \&Foo::foo, 'can() returns ref to regular installed sub' ); 81 82eval { 83 $foo->will_fail; 84}; 85like( $@, qr/^Can't locate/, 'undefined method' ); 86 87$result = $foo->can( 'will_fail' ); 88ok( ! $result, 'can() should fail on undefined methods' ); 89 90# Used to be trouble with this 91eval { 92 my $foo = Foo->new(); 93 die "oops"; 94}; 95like( $@, qr/oops/, 'indirect method call' ); 96 97# Pass regular expression variable to autoloaded function. This used 98# to go wrong because AutoLoader used regular expressions to generate 99# autoloaded filename. 100'foo' =~ /(\w+)/; 101 102is( $foo->bazmarkhianish($1), 'foo', 'autoloaded method should not stomp match vars' ); 103is( $foo->bazmarkhianish($1), 'foo', '(again)' ); 104 105# Used to retry long subnames with shorter filenames on any old 106# exception, including compilation error. Now AutoLoader only 107# tries shorter filenames if it can't find the long one. 108eval { 109 $foo->blechanawilla; 110}; 111like( $@, qr/syntax error/i, 'require error propagates' ); 112 113# test recursive autoloads 114write_file( File::Spec->catfile( $fulldir, 'a.al' ), <<'EOT' ); 115package Foo; 116BEGIN { b() } 117sub a { ::ok( 1, 'adding a new autoloaded method' ); } 1181; 119EOT 120write_file( File::Spec->catfile( $fulldir, 'b.al' ), <<'EOT' ); 121package Foo; 122sub b { ::ok( 1, 'adding a new autoloaded method' ) } 1231; 124EOT 125 126Foo::a(); 127 128# Test whether autoload_sub works without actually executing the function 129ok(!defined(&Foo::notreached), "Foo::notreached unknown to boot"); 130AutoLoader::autoload_sub("Foo::notreached"); 131ok(defined(&Foo::notreached), "Foo::notreached loaded by autoload_sub"); 132 133# Make sure that repeatedly calling autoload_sub is not a problem: 134AutoLoader::autoload_sub("Foo::notreached"); 135eval {Foo::notreached;}; 136ok($@ && $@ =~ /Should not/, "Foo::notreached works as expected"); 137 138package Bar; 139AutoLoader->import(); 140::ok( ! defined &AUTOLOAD, 'AutoLoader should not export AUTOLOAD by default' ); 141::ok( ! defined &can, '... nor can()' ); 142 143package Foo; 144AutoLoader->unimport(); 145eval { Foo->baz() }; 146::like( $@, qr/locate object method "baz"/, 147 'unimport() should remove imported AUTOLOAD()' ); 148 149package Baz; 150 151sub AUTOLOAD { 'i am here' } 152 153AutoLoader->import(); 154AutoLoader->unimport(); 155 156::is( Baz->AUTOLOAD(), 'i am here', '... but not non-imported AUTOLOAD()' ); 157 158 159package SomeClass; 160use AutoLoader 'AUTOLOAD'; 161sub new { 162 bless {} => shift; 163} 164 165package main; 166 167$INC{"SomeClass.pm"} = $0; # Prepare possible recursion 168{ 169 my $p = SomeClass->new(); 170} # <-- deep recursion in AUTOLOAD looking for SomeClass::DESTROY? 171::ok(1, "AutoLoader shouldn't loop forever if \%INC is modified"); 172 173# Now test the bug that lead to AutoLoader 0.67: 174# If the module is loaded from a file name different than normal, 175# we could formerly have trouble finding autosplit.ix 176# Contributed by Christoph Lamprecht. 177# Recreate the following file structure: 178# auto/MyAddon/autosplit.ix 179# auto/MyAddon/testsub.al 180# MyModule.pm 181SCOPE: { 182 my $autopath = File::Spec->catdir( $dir, 'auto', 'MyAddon' ); 183 mkpath( $autopath ) or die "Can't mkdir '$autopath': $!"; 184 my $autosplit_text = <<'EOT'; 185# Index created by AutoSplit for MyModule.pm 186# (file acts as timestamp) 187package MyAddon; 188sub testsub ; 1891; 190EOT 191 write_file( File::Spec->catfile( $autopath, 'autosplit.ix' ), $autosplit_text ); 192 193 my $testsub_text = <<'EOT'; 194# NOTE: Derived from MyModule.pm. 195# Changes made here will be lost when autosplit is run again. 196# See AutoSplit.pm. 197package MyAddon; 198 199#line 13 "MyModule.pm (autosplit into auto/MyAddon/testsub.al)" 200sub testsub{ 201 return "MyAddon"; 202} 203 2041; 205# end of MyAddon::testsub 206EOT 207 write_file( File::Spec->catfile( $autopath, 'testsub.al' ), $testsub_text); 208 209 my $mymodule_text = <<'EOT'; 210use strict; 211use warnings; 212package MyModule; 213sub testsub{return 'MyModule';} 214 215package MyAddon; 216our @ISA = ('MyModule'); 217BEGIN{$INC{'MyAddon.pm'} = __FILE__} 218use AutoLoader 'AUTOLOAD'; 2191; 220__END__ 221 222sub testsub{ 223 return "MyAddon"; 224} 225EOT 226 write_file( File::Spec->catfile( $dir, 'MyModule.pm' ), $mymodule_text); 227 228 require MyModule; 229 230 my $res = MyAddon->testsub(); 231 ::is ($res , 'MyAddon', 'invoke MyAddon::testsub'); 232} 233 234# cleanup 235END { 236 return unless $dir && -d $dir; 237 rmtree $dir; 238} 239 240