fix occasional op/time.t failure
[p5sagit/p5-mst-13.2.git] / t / op / inccode.t
CommitLineData
69026470 1#!./perl -w
e5d18500 2
3# Tests for the coderef-in-@INC feature
4
6b75eab3 5my $can_fork = 0;
ab742322 6my $minitest = $ENV{PERL_CORE_MINITEST};
7
e5d18500 8BEGIN {
f8973f08 9 chdir 't' if -d 't';
69026470 10 @INC = qw(. ../lib);
e5d18500 11}
ab742322 12
13if (!$minitest) {
6b75eab3 14 use Config;
15 if (PerlIO::Layer->find('perlio') && $Config{d_fork} &&
16 eval 'require POSIX; 1') {
17 $can_fork = 1;
18 }
19}
f8973f08 20
6b75eab3 21use strict;
47de4e93 22use File::Spec;
69026470 23
24require "test.pl";
ab742322 25plan(tests => 45 + !$minitest * (3 + 14 * $can_fork));
47de4e93 26
22e2837f 27my @tempfiles = ();
28
47de4e93 29sub get_temp_fh {
22e2837f 30 my $f = "DummyModule0000";
31 1 while -e ++$f;
32 push @tempfiles, $f;
33 open my $fh, ">$f" or die "Can't create $f: $!";
3a5db825 34 print $fh "package ".substr($_[0],0,-3).";\n1;\n";
35 print $fh $_[1] if @_ > 1;
d1e4d418 36 close $fh or die "Couldn't close: $!";
47de4e93 37 open $fh, $f or die "Can't open $f: $!";
38 return $fh;
39}
f8973f08 40
22e2837f 41END { 1 while unlink @tempfiles }
42
e5d18500 43sub fooinc {
44 my ($self, $filename) = @_;
45 if (substr($filename,0,3) eq 'Foo') {
47de4e93 46 return get_temp_fh($filename);
e5d18500 47 }
48 else {
f8973f08 49 return undef;
e5d18500 50 }
51}
52
53push @INC, \&fooinc;
54
d1e4d418 55my $evalret = eval { require Bar; 1 };
56ok( !$evalret, 'Trying non-magic package' );
57
58$evalret = eval { require Foo; 1 };
59die $@ if $@;
60ok( $evalret, 'require Foo; magic via code ref' );
61ok( exists $INC{'Foo.pm'}, ' %INC sees Foo.pm' );
62is( ref $INC{'Foo.pm'}, 'CODE', ' val Foo.pm is a coderef in %INC' );
63is( $INC{'Foo.pm'}, \&fooinc, ' val Foo.pm is correct in %INC' );
64
65$evalret = eval "use Foo1; 1;";
66die $@ if $@;
67ok( $evalret, 'use Foo1' );
68ok( exists $INC{'Foo1.pm'}, ' %INC sees Foo1.pm' );
69is( ref $INC{'Foo1.pm'}, 'CODE', ' val Foo1.pm is a coderef in %INC' );
70is( $INC{'Foo1.pm'}, \&fooinc, ' val Foo1.pm is correct in %INC' );
71
72$evalret = eval { do 'Foo2.pl'; 1 };
73die $@ if $@;
74ok( $evalret, 'do "Foo2.pl"' );
75ok( exists $INC{'Foo2.pl'}, ' %INC sees Foo2.pl' );
76is( ref $INC{'Foo2.pl'}, 'CODE', ' val Foo2.pl is a coderef in %INC' );
77is( $INC{'Foo2.pl'}, \&fooinc, ' val Foo2.pl is correct in %INC' );
e5d18500 78
79pop @INC;
80
f8973f08 81
e5d18500 82sub fooinc2 {
83 my ($self, $filename) = @_;
84 if (substr($filename, 0, length($self->[1])) eq $self->[1]) {
47de4e93 85 return get_temp_fh($filename);
e5d18500 86 }
87 else {
f8973f08 88 return undef;
e5d18500 89 }
90}
91
47de4e93 92my $arrayref = [ \&fooinc2, 'Bar' ];
93push @INC, $arrayref;
e5d18500 94
d1e4d418 95$evalret = eval { require Foo; 1; };
96die $@ if $@;
97ok( $evalret, 'Originally loaded packages preserved' );
98$evalret = eval { require Foo3; 1; };
99ok( !$evalret, 'Original magic INC purged' );
100
101$evalret = eval { require Bar; 1 };
102die $@ if $@;
103ok( $evalret, 'require Bar; magic via array ref' );
104ok( exists $INC{'Bar.pm'}, ' %INC sees Bar.pm' );
105is( ref $INC{'Bar.pm'}, 'ARRAY', ' val Bar.pm is an arrayref in %INC' );
106is( $INC{'Bar.pm'}, $arrayref, ' val Bar.pm is correct in %INC' );
107
108ok( eval "use Bar1; 1;", 'use Bar1' );
109ok( exists $INC{'Bar1.pm'}, ' %INC sees Bar1.pm' );
110is( ref $INC{'Bar1.pm'}, 'ARRAY', ' val Bar1.pm is an arrayref in %INC' );
111is( $INC{'Bar1.pm'}, $arrayref, ' val Bar1.pm is correct in %INC' );
112
113ok( eval { do 'Bar2.pl'; 1 }, 'do "Bar2.pl"' );
114ok( exists $INC{'Bar2.pl'}, ' %INC sees Bar2.pl' );
115is( ref $INC{'Bar2.pl'}, 'ARRAY', ' val Bar2.pl is an arrayref in %INC' );
116is( $INC{'Bar2.pl'}, $arrayref, ' val Bar2.pl is correct in %INC' );
e5d18500 117
118pop @INC;
119
120sub FooLoader::INC {
121 my ($self, $filename) = @_;
122 if (substr($filename,0,4) eq 'Quux') {
47de4e93 123 return get_temp_fh($filename);
e5d18500 124 }
125 else {
f8973f08 126 return undef;
e5d18500 127 }
128}
129
47de4e93 130my $href = bless( {}, 'FooLoader' );
131push @INC, $href;
e5d18500 132
d1e4d418 133$evalret = eval { require Quux; 1 };
134die $@ if $@;
135ok( $evalret, 'require Quux; magic via hash object' );
136ok( exists $INC{'Quux.pm'}, ' %INC sees Quux.pm' );
6ece0f6b 137is( ref $INC{'Quux.pm'}, 'FooLoader',
d1e4d418 138 ' val Quux.pm is an object in %INC' );
139is( $INC{'Quux.pm'}, $href, ' val Quux.pm is correct in %INC' );
e5d18500 140
141pop @INC;
142
47de4e93 143my $aref = bless( [], 'FooLoader' );
144push @INC, $aref;
e5d18500 145
d1e4d418 146$evalret = eval { require Quux1; 1 };
147die $@ if $@;
148ok( $evalret, 'require Quux1; magic via array object' );
149ok( exists $INC{'Quux1.pm'}, ' %INC sees Quux1.pm' );
6ece0f6b 150is( ref $INC{'Quux1.pm'}, 'FooLoader',
d1e4d418 151 ' val Quux1.pm is an object in %INC' );
152is( $INC{'Quux1.pm'}, $aref, ' val Quux1.pm is correct in %INC' );
e5d18500 153
154pop @INC;
155
47de4e93 156my $sref = bless( \(my $x = 1), 'FooLoader' );
157push @INC, $sref;
e5d18500 158
d1e4d418 159$evalret = eval { require Quux2; 1 };
160die $@ if $@;
161ok( $evalret, 'require Quux2; magic via scalar object' );
162ok( exists $INC{'Quux2.pm'}, ' %INC sees Quux2.pm' );
6ece0f6b 163is( ref $INC{'Quux2.pm'}, 'FooLoader',
d1e4d418 164 ' val Quux2.pm is an object in %INC' );
165is( $INC{'Quux2.pm'}, $sref, ' val Quux2.pm is correct in %INC' );
f8973f08 166
167pop @INC;
9ae8cd5b 168
169push @INC, sub {
170 my ($self, $filename) = @_;
171 if (substr($filename,0,4) eq 'Toto') {
172 $INC{$filename} = 'xyz';
173 return get_temp_fh($filename);
174 }
175 else {
176 return undef;
177 }
178};
179
d1e4d418 180$evalret = eval { require Toto; 1 };
181die $@ if $@;
182ok( $evalret, 'require Toto; magic via anonymous code ref' );
183ok( exists $INC{'Toto.pm'}, ' %INC sees Toto.pm' );
184ok( ! ref $INC{'Toto.pm'}, q/ val Toto.pm isn't a ref in %INC/ );
185is( $INC{'Toto.pm'}, 'xyz', ' val Toto.pm is correct in %INC' );
9ae8cd5b 186
187pop @INC;
d820be44 188
3a5db825 189push @INC, sub {
190 my ($self, $filename) = @_;
191 if ($filename eq 'abc.pl') {
192 return get_temp_fh($filename, qq(return "abc";\n));
193 }
194 else {
195 return undef;
196 }
197};
198
6b75eab3 199my $ret = "";
3a5db825 200$ret ||= do 'abc.pl';
201is( $ret, 'abc', 'do "abc.pl" sees return value' );
202
ab742322 203{
204 my $filename = $^O eq 'MacOS' ? ':Foo:Foo.pm' : './Foo.pm';
c38a6530 205 #local @INC; # local fails on tied @INC
206 my @old_INC = @INC; # because local doesn't work on tied arrays
ab742322 207 @INC = sub { $filename = 'seen'; return undef; };
208 eval { require $filename; };
209 is( $filename, 'seen', 'the coderef sees fully-qualified pathnames' );
c38a6530 210 @INC = @old_INC;
ab742322 211}
212
213exit if $minitest;
214
3a5db825 215pop @INC;
216
a3b58a99 217push @INC, sub {
218 my ($cr, $filename) = @_;
219 my $module = $filename; $module =~ s,/,::,g; $module =~ s/\.pm$//;
220 open my $fh, '<', \"package $module; sub complain { warn q() }; \$::file = __FILE__;"
221 or die $!;
222 $INC{$filename} = "/custom/path/to/$filename";
223 return $fh;
224};
225
226require Publius::Vergilius::Maro;
227is( $INC{'Publius/Vergilius/Maro.pm'}, '/custom/path/to/Publius/Vergilius/Maro.pm', '%INC set correctly');
228is( our $file, '/custom/path/to/Publius/Vergilius/Maro.pm', '__FILE__ set correctly' );
229{
230 my $warning;
231 local $SIG{__WARN__} = sub { $warning = shift };
232 Publius::Vergilius::Maro::complain();
233 like( $warning, qr{something's wrong at /custom/path/to/Publius/Vergilius/Maro.pm}, 'warn() reports correct file source' );
234}
235
236pop @INC;
237
6b75eab3 238if ($can_fork) {
239 require PerlIO::scalar;
240 # This little bundle of joy generates n more recursive use statements,
241 # with each module chaining the next one down to 0. If it works, then we
242 # can safely nest subprocesses
243 my $use_filter_too;
244 push @INC, sub {
245 return unless $_[1] =~ /^BBBLPLAST(\d+)\.pm/;
246 my $pid = open my $fh, "-|";
247 if ($pid) {
248 # Parent
249 return $fh unless $use_filter_too;
250 # Try filters and state in addition.
251 return ($fh, sub {s/$_[1]/pass/; return}, "die")
252 }
253 die "Can't fork self: $!" unless defined $pid;
254
255 # Child
256 my $count = $1;
257 # Lets force some fun with odd sized reads.
258 $| = 1;
259 print 'push @main::bbblplast, ';
260 print "$count;\n";
261 if ($count--) {
262 print "use BBBLPLAST$count;\n";
263 }
264 if ($use_filter_too) {
265 print "die('In $_[1]');";
266 } else {
267 print "pass('In $_[1]');";
268 }
269 print '"Truth"';
270 POSIX::_exit(0);
271 die "Can't get here: $!";
272 };
273
274 @::bbblplast = ();
275 require BBBLPLAST5;
276 is ("@::bbblplast", "0 1 2 3 4 5", "All ran");
277
278 foreach (keys %INC) {
279 delete $INC{$_} if /^BBBLPLAST/;
280 }
281
282 @::bbblplast = ();
283 $use_filter_too = 1;
284
285 require BBBLPLAST5;
286
287 is ("@::bbblplast", "0 1 2 3 4 5", "All ran with a filter");
288}