#!perl
BEGIN {
chdir
't'
if
-d
't'
;
require
'./test.pl'
;
set_up_inc(
qw(../lib)
);
}
plan(
tests
=> 73);
my
%seen
;
@INC
=
grep
{!
$seen
{
$_
}++}
@INC
;
my
$nonfile
= tempfile();
for
my
$file
(
$nonfile
,
' '
) {
eval
{
require
$file
;
};
like $@,
qr/^Can't locate $file in \@INC \(\@INC[\w ]+: \Q@INC\E\) at/
,
"correct error message for require '$file'"
;
}
{
my
$I
=
"\x{393}"
;
my
$C
=
"\x{387}"
;
for
my
$test_data
(
[
"No::Such::Module1"
,
"No/Such/Module1.pm"
, 1 ],
[
"'No/Such/Module1.pm'"
,
"No/Such/Module1.pm"
, 1 ],
[
"_No::Such::Module1"
,
"_No/Such/Module1.pm"
, 1 ],
[
"'_No/Such/Module1.pm'"
,
"_No/Such/Module1.pm"
, 1 ],
[
"'No/Such./Module.pm'"
,
"No/Such./Module.pm"
, 0 ],
[
"No::1Such::Module"
,
"No/1Such/Module.pm"
, 1 ],
[
"'No/1Such/Module.pm'"
,
"No/1Such/Module.pm"
, 1 ],
[
"1No::Such::Module"
,
undef
, 0 ],
[
"'1No/Such/Module.pm'"
,
"1No/Such/Module.pm"
, 0 ],
[
"No::Such${I}::Module1"
,
"No/Such${I}/Module1.pm"
, 1 ],
[
"'No/Such${I}/Module1.pm'"
,
"No/Such${I}/Module1.pm"
, 1 ],
[
"_No::Such${I}::Module1"
,
"_No/Such${I}/Module1.pm"
, 1 ],
[
"'_No/Such${I}/Module1.pm'"
,
"_No/Such${I}/Module1.pm"
, 1 ],
[
"'No/Such${I}./Module.pm'"
,
"No/Such${I}./Module.pm"
, 0 ],
[
"No::1Such${I}::Module"
,
"No/1Such${I}/Module.pm"
, 1 ],
[
"'No/1Such${I}/Module.pm'"
,
"No/1Such${I}/Module.pm"
, 1 ],
[
"1No::Such${I}::Module"
,
undef
, 0 ],
[
"'1No/Such${I}/Module.pm'"
,
"1No/Such${I}/Module.pm"
, 0 ],
[
"No::${C}Such::Module1"
,
undef
, 0 ],
[
"'No/${C}Such/Module1.pm'"
,
"No/${C}Such/Module1.pm"
, 0 ],
[
"_No::${C}Such::Module1"
,
undef
, 0 ],
[
"'_No/${C}Such/Module1.pm'"
,
"_No/${C}Such/Module1.pm"
, 0 ],
[
"'No/${C}Such./Module.pm'"
,
"No/${C}Such./Module.pm"
, 0 ],
[
"No::${C}1Such::Module"
,
undef
, 0 ],
[
"'No/${C}1Such/Module.pm'"
,
"No/${C}1Such/Module.pm"
, 0 ],
[
"1No::${C}Such::Module"
,
undef
, 0 ],
[
"'1No/${C}Such/Module.pm'"
,
"1No/${C}Such/Module.pm"
, 0 ],
) {
my
(
$require_arg
,
$err_path
,
$has_hint
) =
@$test_data
;
my
$exp
;
if
(
defined
$err_path
) {
$exp
=
"Can't locate $err_path in \@INC"
;
if
(
$has_hint
) {
my
$hint
=
$err_path
;
$hint
=~ s{/}{::}g;
$hint
=~ s/\.pm$//;
$exp
.=
" (you may need to install the $hint module)"
;
}
$exp
.=
" (\@INC entries checked: @INC) at"
;
}
else
{
$exp
=
""
;
}
my
$err
;
{
no
warnings
qw(syntax utf8)
;
if
(
$require_arg
=~ /[^\x00-\xff]/) {
eval
"require $require_arg"
;
$err
= $@;
utf8::decode(
$err
);
}
else
{
eval
"require $require_arg"
;
$err
= $@;
}
}
for
(
$err
,
$exp
,
$require_arg
) {
s/([^\x00-\xff])/
sprintf
"\\x{%x}"
,
ord
($1)/ge;
}
if
(
length
$exp
) {
$exp
=
qr/^\Q$exp\E/
;
}
else
{
$exp
=
qr/syntax error at|Unrecognized character/
;
}
like
$err
,
$exp
,
"err for require $require_arg"
;
}
}
eval
"require ::$nonfile"
;
like $@,
qr/^Bareword in require must not start with a double-colon:/
,
"correct error message for require ::$nonfile"
;
eval
{
require
"$nonfile.ph"
;
};
like $@,
qr/^Can't locate $nonfile\.ph in \@INC \(did you run h2ph\?\) \(\@INC[\w ]+: @INC\) at/
;
for
my
$file
(
"$nonfile.h"
,
".h"
) {
eval
{
require
$file
};
like $@,
qr/^Can't locate \Q$file\E in \@INC \(change \.h to \.ph maybe\?\) \(did you run h2ph\?\) \(\@INC[\w ]+: @INC\) at/
,
"correct error message for require '$file'"
;
}
for
my
$file
(
"$nonfile.ph"
,
".ph"
) {
eval
{
require
$file
};
like $@,
qr/^Can't locate \Q$file\E in \@INC \(did you run h2ph\?\) \(\@INC[\w ]+: @INC\) at/
,
"correct error message for require '$file'"
;
}
eval
'require <foom>'
;
like $@,
qr/^<> at require-statement should be quotes at /
,
'require <> error'
;
my
$module
= tempfile();
my
$mod_file
=
"$module.pm"
;
open
my
$module_fh
,
">"
,
$mod_file
or
die
$!;
print
{
$module_fh
}
"print 1; 1;\n"
;
close
$module_fh
;
chmod
0333,
$mod_file
;
SKIP: {
skip_if_miniperl(
"these modules may not be available to miniperl"
, 2);
push
@INC
,
'../lib'
;
if
($^O eq
'cygwin'
) {
}
my
$olduid
= $>;
eval
{ $> = 1; };
skip
"Can't test permissions meaningfully if you're superuser"
, 2
if
($^O eq
'cygwin'
? Win32::IsAdminUser() : $> == 0);
local
@INC
=
"."
;
eval
"use $module"
;
like $@,
qr<^\QCan't locate $mod_file:>
,
"special error message if the file exists but can't be opened"
;
SKIP: {
skip
"Can't make the path absolute"
, 1
if
!
defined
(Cwd::getcwd());
my
$file
= File::Spec::Functions::catfile(Cwd::getcwd(),
$mod_file
);
eval
{
require
(
$file
);
};
like $@,
qr<^\QCan't locate $file:>
,
"...even if we use a full path"
;
}
eval
{ $> =
$olduid
; };
}
1
while
unlink
$mod_file
;
eval
{
no
warnings
'syscalls'
;
require
"strict.pm\0invalid"
; };
like $@,
qr/^Can't locate strict\.pm\\0invalid: /
, '
require
nul check [perl
{
my
$WARN
;
local
$SIG
{__WARN__} =
sub
{
$WARN
=
shift
};
{
my
$ret
=
do
"strict.pm\0invalid"
;
my
$exc
= $@;
my
$err
= $!;
is
$ret
,
undef
,
'do nulstring returns undef'
;
is
$exc
,
''
,
'do nulstring clears $@'
;
$! =
$err
;
ok $!{ENOENT},
'do nulstring fails with ENOENT'
;
like
$WARN
,
qr{^Invalid \\0 character in pathname for do: strict\.pm\\0invalid at }
,
'do nulstring warning'
;
}
$WARN
=
''
;
eval
{
require
"strict.pm\0invalid"
; };
like
$WARN
,
qr{^Invalid \\0 character in pathname for require: strict\.pm\\0invalid at }
,
'nul warning'
;
like $@,
qr{^Can't locate strict\.pm\\0invalid: }
, 'nul error';
$WARN
=
''
;
local
@INC
=
@INC
;
set_up_inc(
"lib\0invalid"
);
eval
{
require
"unknown.pm"
};
like
$WARN
,
qr{^Invalid \\0 character in \@INC entry for require: lib\\0invalid at }
,
'nul warning'
;
}
eval
"require strict\0::invalid;"
;
like $@,
qr/^syntax error at \(eval \d+\) line 1/
,
'parse error with \0 in barewords module names'
;
eval
{
no
warnings
'syscalls'
;
require
eval
"qr/\0/"
};
like $@,
qr/^Can't locate \(\?\^:\\0\):/
,
'require ref that stringifies with embedded null'
;
eval
{
no
strict;
no
warnings
'syscalls'
;
require
*{
"\0a"
} };
like $@,
qr/^Can't locate \*main::\\0a:/
,
'require ref that stringifies with embedded null'
;
eval
{
require
undef
};
like $@,
qr/^Missing or undefined argument to require /
;
eval
{
do
undef
};
like $@,
qr/^Missing or undefined argument to do /
;
eval
{
require
""
};
like $@,
qr/^Missing or undefined argument to require /
;
eval
{
do
""
};
like $@,
qr/^Missing or undefined argument to do /
;
my
$nonsearch
=
"./no_such_file.pm"
;
eval
"require \"$nonsearch\""
;
like $@,
qr/^Can't locate \Q$nonsearch\E at/
,
"correct error message for require $nonsearch"
;
{
push
@INC
,
"lib"
;
ok(!
eval
{
require
CannotParse; },
"should fail to load"
);
local
%INC
=
%INC
;
"check the second attempt also fails"
);
like $@,
qr/Attempt to reload/
,
"check we failed for the right reason"
;
}
{
fresh_perl_like(
'unshift @INC, sub { sub { 0 } }; require "asdasd";'
,
qr/asdasd did not return a true value/
,
{ },
'@INC hook blocks do not cause segfault'
);
}
{
fresh_perl_like(
'use lib qq(./lib); BEGIN{ unshift @INC, '
.
'sub { if ($_[1] eq "CannotParse.pm" and !$seen++) { '
.
'eval q(require $_[1]); warn $@; my $code= qq[die qq(error)];'
.
'open my $fh,"<", q(lib/Dies.pm); return $fh } } } require CannotParse;'
,
qr!\Asyntax error.*?^error at /loader/0x[A-Fa-f0-9]+/CannotParse\.pm line 1\.!
ms,
{ },
'Inc hooks have the correct cop_file'
);
}
{
fresh_perl_like(
'unshift @INC, sub { *INC=["a","b"] }; '
.
'eval "require Frobnitz" or print $@'
,
qr!\(\@INC[\w ]+: CODE\(0x[A-Fa-f0-9]+\) b\)!
,
{ },
'INC hooks do not segfault when overwritten'
);
}
{
fresh_perl_like(
'@INC = (sub { @INC=("a","b"); () }, "z"); '
.
'eval "require Frobnitz" or print $@'
,
qr!\(\@INC[\w ]+: CODE\(0x[A-Fa-f0-9]+\) b\)!
,
{ },
'INC hooks that overwrite @INC continue as expected (skips a and z)'
);
}
{
fresh_perl_like(
'@INC = (sub { @INC=qw(a b); undef $INC }, "z"); '
.
'eval "require Frobnitz" or print $@'
,
qr!\(\@INC[\w ]+: CODE\(0x[A-Fa-f0-9]+\) a b\)!
,
{ },
'INC hooks that overwrite @INC and undef $INC continue at start'
);
}
{
fresh_perl_like(
'sub CB::INCDIR { return "b", "c","d" }; '
.
'@INC = ("a",bless({},"CB"),"e");'
.
'eval "require Frobnitz" or print $@'
,
qr!\(\@INC[\w ]+: a CB=HASH\(0x[A-Fa-f0-9]+\) b c d e\)!
,
{ },
'INCDIR works as expected'
);
}
{
fresh_perl_like(
'@INC = ("a",bless({},"CB"),"e");'
.
'eval "require Frobnitz" or print $@'
,
qr!Can't locate object method "INC", nor "INCDIR" nor string overload via package "CB" in object hook in \@INC!
,
{ },
'Objects with no INC or INCDIR method and no overload throw an error'
);
}
{
fresh_perl_like(
'package CB { use overload q("") => sub { "Fnorble" };} @INC = ("a",bless({},"CB"),"e");'
.
'eval "require Frobnitz" or print $@'
,
qr!\(\@INC[\w ]+: a Fnorble e\)!
,
{ },
'Objects with no INC or INCDIR method but with an overload are stringified'
);
}
{
fresh_perl_like(
'package CB { use overload q(0+) => sub { 12345 }, fallback=>1;} @INC = ("a",bless({},"CB"),"e");'
.
'eval "require Frobnitz" or print $@'
,
qr!\(\@INC[\w ]+: a 12345 e\)!
,
{ },
'Objects with no INC or INCDIR method but with an overload with fallback are stringified'
);
}
{
fresh_perl_like(
'{package CB; use overload qw("")=>sub { "blorg"};} '
.
'@INC = ("a",bless({},"CB"),"e");'
.
'eval "require Frobnitz" or print $@'
,
qr!\(\@INC[\w ]+: a blorg e\)!
,
{ },
'Objects with overload and no INC or INCDIR method are stringified'
);
}
{
fresh_perl_like(
'@INC = ("a",bless(sub { warn "blessed sub called" },"CB"),"e");'
.
'eval "require Frobnitz" or print $@'
,
qr!blessed sub called.*\(\@INC[\w ]+: a CB=CODE\(0x[a-fA-F0-9]+\) e\)!
s,
{ },
'Blessed subs with no hook methods are executed'
);
}
{
fresh_perl_like(
'@INC = ("a",bless(sub { die "blessed sub called" },"CB"),"e");'
.
'eval "require Frobnitz" or print $@'
,
qr!INC sub hook died--halting \@INC search!
s,
{ },
'Blessed subs that die produce expected extra message'
);
}
{
fresh_perl_like(
'sub CB::INC { die "bad mojo" } '
.
'@INC = ("a",bless(sub { die "blessed sub called" },"CB"),"e");'
.
'eval "require Frobnitz" or print $@'
,
qr!bad mojo.*INC method hook died--halting \@INC search!
s,
{ },
'Blessed subs with methods call method and produce expected message'
);
}
{
fresh_perl_like(
'@INC = ("a",[bless([],"CB"),1],"e");'
.
'eval "require Frobnitz" or print $@'
,
qr!Can't locate object method "INC", nor "INCDIR" nor string overload via package "CB" in object in ARRAY hook in \@INC!
s,
{ },
'Blessed objects with no hook methods in array form produce expected exception'
);
}
{
fresh_perl_like(
'sub CB::INCDIR { "i" } sub CB2::INCDIR { }'
.
'@INC = ("a",bless(sub{"b"},"CB"),bless(sub{"c"},"CB2"),"e");'
.
'eval "require Frobnitz" or print $@'
,
qr!\(\@INC[\w ]+: a CB=CODE\(0x[a-fA-F0-9]+\) i CB2=CODE\(0x[a-fA-F0-9]+\) e\)!
s,
{ },
'Blessed subs with INCDIR methods call INCDIR'
);
}
{
fresh_perl_like(
'sub CB::INCDIR { return @{$_[2]} }'
.
'@INC = ("a",[bless([],"CB"),"b"],"c");'
.
'eval "require Frobnitz" or print $@'
,
qr!\(\@INC[\w ]+: a ARRAY\(0x[a-fA-F0-9]+\) CB=ARRAY\(0x[a-fA-F0-9]+\) b c\)!
s,
{ },
'INCDIR ref returns are stringified'
);
}