#!./perl -T
BEGIN {
require Config; import Config;
if ($Config{'extensions'} !~ /\bDevel\/Peek\b/) {
print "1..0 # Skip: Devel::Peek was not built\n";
exit 0;
}
{
package t;
my $core = !!$ENV{PERL_CORE};
require($core ? '../../t/test.pl' : './t/test.pl');
}
}
use Test::More;
use Devel::Peek;
our $DEBUG = 0;
open(SAVERR, ">&STDERR") or die "Can't dup STDERR: $!";
# If I reference any lexicals in this, I get the entire outer subroutine (or
# MAIN) dumped too, which isn't really what I want, as it's a lot of faff to
# maintain that.
format PIE =
Pie @<<<<<
$::type
Good @>>>>>
$::mmmm
.
use constant thr => $Config{useithreads};
sub do_test {
my $todo = $_[3];
my $repeat_todo = $_[4];
my $pattern = $_[2];
my $do_eval = $_[5];
if (open(OUT,'>', "peek$$")) {
open(STDERR, ">&OUT") or die "Can't dup OUT: $!";
if ($do_eval) {
my $sub = eval "sub { Dump $_[1] }";
$sub->();
print STDERR "*****\n";
# second dump to compare with the first to make sure nothing
# changed.
$sub->();
}
else {
Dump($_[1]);
print STDERR "*****\n";
# second dump to compare with the first to make sure nothing
# changed.
Dump($_[1]);
}
open(STDERR, ">&SAVERR") or die "Can't restore STDERR: $!";
close(OUT);
if (open(IN, '<', "peek$$")) {
local $/;
$pattern =~ s/\$ADDR/0x[[:xdigit:]]+/g;
$pattern =~ s/\$FLOAT/(?:\\d*\\.\\d+(?:e[-+]\\d+)?|\\d+)/g;
# handle DEBUG_LEAKING_SCALARS prefix
$pattern =~ s/^(\s*)(SV =.* at )/(?:$1ALLOCATED at .*?\n)?$1$2/mg;
# Need some clear generic mechanism to eliminate (or add) lines
# of dump output dependant on perl version. The (previous) use of
# things like $IVNV gave the illusion that the string passed in was
# a regexp into which variables were interpolated, but this wasn't
# actually true as those 'variables' actually also ate the
# whitespace on the line. So it seems better to mark lines that
# need to be eliminated. I considered (?# ... ) and (?{ ... }),
# but whilst embedded code or comment syntax would keep it as a
# legitimate regexp, it still isn't true. Seems easier and clearer
# things that look like comments.
# Could do this is in a s///mge but seems clearer like this:
$pattern = join '', map {
# If we identify the version condition, take *it* out whatever
s/\s*# (\$\].*)$//
? (eval $1 ? $_ : '')
: $_ # Didn't match, so this line is in
} split /^/, $pattern;
$pattern =~ s/\$PADMY,/
$] < 5.012005 ? 'PADMY,' : '';
/mge;
$pattern =~ s/\$RV/
($] < 5.011) ? 'RV' : 'IV';
/mge;
$pattern =~ s/^\h+COW_REFCNT = .*\n//mg
if $Config{ccflags} =~
/-DPERL_(?:OLD_COPY_ON_WRITE|NO_COW)\b/
|| $] < 5.019003;
print $pattern, "\n" if $DEBUG;
my ($dump, $dump2) = split m/\*\*\*\*\*\n/, scalar <IN>;
print $dump, "\n" if $DEBUG;
like( $dump, qr/\A$pattern\Z/ms, $_[0])
or note("line " . (caller)[2]);
local $TODO = $repeat_todo;
is($dump2, $dump, "$_[0] (unchanged by dump)")
or note("line " . (caller)[2]);
close(IN);
return $1;
} else {
die "$0: failed to open peek$$: !\n";
}
} else {
die "$0: failed to create peek$$: $!\n";
}
}
our $a;
our $b;
my $c;
local $d = 0;
END {
1 while unlink("peek$$");
}
do_test('assignment of immediate constant (string)',
$a = "foo",
'SV = PV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(POK,(?:IsCOW,)?pPOK\\)
PV = $ADDR "foo"\\\0
CUR = 3
LEN = \\d+
COW_REFCNT = 1
');
do_test('immediate constant (string)',
"bar",
'SV = PV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(.*POK,READONLY,(?:IsCOW,)?pPOK\\) # $] < 5.021005
FLAGS = \\(.*POK,(?:IsCOW,)?READONLY,PROTECT,pPOK\\) # $] >=5.021005
PV = $ADDR "bar"\\\0
CUR = 3
LEN = \\d+
COW_REFCNT = 0
');
do_test('assignment of immediate constant (integer)',
$b = 123,
'SV = IV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(IOK,pIOK\\)
IV = 123');
do_test('immediate constant (integer)',
456,
'SV = IV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(.*IOK,READONLY,pIOK\\) # $] < 5.021005
FLAGS = \\(.*IOK,READONLY,PROTECT,pIOK\\) # $] >=5.021005
IV = 456');
do_test('assignment of immediate constant (integer)',
$c = 456,
'SV = IV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\($PADMY,IOK,pIOK\\)
IV = 456');
# If perl is built with PERL_PRESERVE_IVUV then maths is done as integers
# where possible and this scalar will be an IV. If NO_PERL_PRESERVE_IVUV then
# maths is done in floating point always, and this scalar will be an NV.
# ([NI]) captures the type, referred to by \1 in this regexp and $type for
# building subsequent regexps.
my $type = do_test('result of addition',
$c + $d,
'SV = ([NI])V\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(PADTMP,\1OK,p\1OK\\) # $] < 5.019003
FLAGS = \\(\1OK,p\1OK\\) # $] >=5.019003
\1V = 456');
($d = "789") += 0.1;
do_test('floating point value',
$d,
$] < 5.019003
|| $Config{ccflags} =~ /-DPERL_(?:NO_COW|OLD_COPY_ON_WRITE)\b/
?
'SV = PVNV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(NOK,pNOK\\)
IV = \d+
NV = 789\\.(?:1(?:000+\d+)?|0999+\d+)
PV = $ADDR "789"\\\0
CUR = 3
LEN = \\d+'
:
'SV = PVNV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(NOK,pNOK\\)
IV = \d+
NV = 789\\.(?:1(?:000+\d+)?|0999+\d+)
PV = 0');
do_test('integer constant',
0xabcd,
'SV = IV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(.*IOK,READONLY,pIOK\\) # $] < 5.021005
FLAGS = \\(.*IOK,READONLY,PROTECT,pIOK\\) # $] >=5.021005
IV = 43981');
do_test('undef',
undef,
'SV = NULL\\(0x0\\) at $ADDR
REFCNT = \d+
FLAGS = \\(READONLY\\) # $] < 5.021005
FLAGS = \\(READONLY,PROTECT\\) # $] >=5.021005
');
do_test('reference to scalar',
\$a,
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PV\\($ADDR\\) at $ADDR
REFCNT = 2
FLAGS = \\(POK,(?:IsCOW,)?pPOK\\)
PV = $ADDR "foo"\\\0
CUR = 3
LEN = \\d+
COW_REFCNT = 1
');
my $c_pattern;
if ($type eq 'N') {
$c_pattern = '
SV = PVNV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(IOK,NOK,pIOK,pNOK\\)
IV = 456
NV = 456
PV = 0';
} else {
$c_pattern = '
SV = IV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(IOK,pIOK\\)
IV = 456';
}
do_test('reference to array',
[$b,$c],
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVAV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(\\)
ARRAY = $ADDR
FILL = 1
MAX = 1
FLAGS = \\(REAL\\)
Elt No. 0
SV = IV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(IOK,pIOK\\)
IV = 123
Elt No. 1' . $c_pattern);
do_test('reference to hash',
{$b=>$c},
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVHV\\($ADDR\\) at $ADDR
REFCNT = [12]
FLAGS = \\(SHAREKEYS\\)
ARRAY = $ADDR \\(0:7, 1:1\\)
hash quality = 100.0%
KEYS = 1
FILL = 1
MAX = 7
Elt "123" HASH = $ADDR' . $c_pattern,
'',
$] < 5.015
&& 'The hash iterator used in dump.c sets the OOK flag');
do_test('reference to anon sub with empty prototype',
sub(){@_},
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVCV\\($ADDR\\) at $ADDR
REFCNT = 2
FLAGS = \\($PADMY,POK,pPOK,ANON,WEAKOUTSIDE,CVGV_RC\\) # $] < 5.015 || !thr
FLAGS = \\($PADMY,POK,pPOK,ANON,WEAKOUTSIDE,CVGV_RC,DYNFILE\\) # $] >= 5.015 && thr
PROTOTYPE = ""
COMP_STASH = $ADDR\\t"main"
START = $ADDR ===> \\d+
ROOT = $ADDR
GVGV::GV = $ADDR\\t"main" :: "__ANON__[^"]*"
FILE = ".*\\b(?i:peek\\.t)"
DEPTH = 0(?:
MUTEXP = $ADDR
OWNER = $ADDR)?
FLAGS = 0x490 # $] < 5.015 || !thr
FLAGS = 0x1490 # $] >= 5.015 && thr
OUTSIDE_SEQ = \\d+
PADLIST = $ADDR
PADNAME = $ADDR\\($ADDR\\) PAD = $ADDR\\($ADDR\\)
OUTSIDE = $ADDR \\(MAIN\\)');
do_test('reference to named subroutine without prototype',
\&do_test,
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVCV\\($ADDR\\) at $ADDR
REFCNT = (3|4)
FLAGS = \\((?:HASEVAL(?:,NAMED)?)?\\) # $] < 5.015 || !thr
FLAGS = \\(DYNFILE(?:,HASEVAL(?:,NAMED)?)?\\) # $] >= 5.015 && thr
COMP_STASH = $ADDR\\t"main"
START = $ADDR ===> \\d+
ROOT = $ADDR
NAME = "do_test" # $] >=5.021004
GVGV::GV = $ADDR\\t"main" :: "do_test" # $] < 5.021004
FILE = ".*\\b(?i:peek\\.t)"
DEPTH = 1(?:
MUTEXP = $ADDR
OWNER = $ADDR)?
FLAGS = 0x(?:[c4]00)?0 # $] < 5.015 || !thr
FLAGS = 0x[cd145]000 # $] >= 5.015 && thr
OUTSIDE_SEQ = \\d+
PADLIST = $ADDR
PADNAME = $ADDR\\($ADDR\\) PAD = $ADDR\\($ADDR\\)
\\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$todo"
\\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$repeat_todo"
\\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$pattern"
\\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$do_eval"
\\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$sub"
\\d+\\. $ADDR<\\d+> FAKE "\\$DEBUG" flags=0x0 index=0
\\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$dump"
\\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$dump2"
OUTSIDE = $ADDR \\(MAIN\\)');
if ($] >= 5.011) {
# note the conditionals on ENGINE and INTFLAGS were introduced in 5.19.9
do_test('reference to regexp',
qr(tic),
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = REGEXP\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(OBJECT,POK,FAKE,pPOK\\) # $] < 5.017006
FLAGS = \\(OBJECT,FAKE\\) # $] >= 5.017006
PV = $ADDR "\\(\\?\\^:tic\\)"
CUR = 8
LEN = 0 # $] < 5.017006
STASH = $ADDR\\t"Regexp"'
. ($] < 5.013 ? '' :
'
COMPFLAGS = 0x0 \(\)
EXTFLAGS = 0x680000 \(CHECK_ALL,USE_INTUIT_NOML,USE_INTUIT_ML\)
(?: ENGINE = $ADDR \(STANDARD\)
)? INTFLAGS = 0x0(?: \(\))?
NPARENS = 0
LASTPAREN = 0
LASTCLOSEPAREN = 0
MINLEN = 3
MINLENRET = 3
GOFS = 0
PRE_PREFIX = 4
SUBLEN = 0
SUBOFFSET = 0
SUBCOFFSET = 0
SUBBEG = 0x0
(?: ENGINE = $ADDR
)? MOTHER_RE = $ADDR'
. ($] < 5.019003 ? '' : '
SV = REGEXP\($ADDR\) at $ADDR
REFCNT = 2
FLAGS = \(\)
PV = $ADDR "\(\?\^:tic\)"
CUR = 8
COMPFLAGS = 0x0 \(\)
EXTFLAGS = 0x680000 \(CHECK_ALL,USE_INTUIT_NOML,USE_INTUIT_ML\)
(?: ENGINE = $ADDR \(STANDARD\)
)? INTFLAGS = 0x0(?: \(\))?
NPARENS = 0
LASTPAREN = 0
LASTCLOSEPAREN = 0
MINLEN = 3
MINLENRET = 3
GOFS = 0
PRE_PREFIX = 4
SUBLEN = 0
SUBOFFSET = 0
SUBCOFFSET = 0
SUBBEG = 0x0
(?: ENGINE = $ADDR
)? MOTHER_RE = 0x0
PAREN_NAMES = 0x0
SUBSTRS = $ADDR
PPRIVATE = $ADDR
OFFS = $ADDR
QR_ANONCV = 0x0(?:
SAVED_COPY = 0x0)?') . '
PAREN_NAMES = 0x0
SUBSTRS = $ADDR
PPRIVATE = $ADDR
OFFS = $ADDR
QR_ANONCV = 0x0(?:
SAVED_COPY = 0x0)?'
));
} else {
do_test('reference to regexp',
qr(tic),
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVMG\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(OBJECT,SMG\\)
IV = 0
NV = 0
PV = 0
MAGIC = $ADDR
MG_VIRTUAL = $ADDR
MG_TYPE = PERL_MAGIC_qr\(r\)
MG_OBJ = $ADDR
PAT = "\(\?^:tic\)"
REFCNT = 2
STASH = $ADDR\\t"Regexp"');
}
do_test('reference to blessed hash',
(bless {}, "Tac"),
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVHV\\($ADDR\\) at $ADDR
REFCNT = [12]
FLAGS = \\(OBJECT,SHAREKEYS\\)
STASH = $ADDR\\t"Tac"
ARRAY = 0x0
KEYS = 0
FILL = 0
MAX = 7', '',
$] >= 5.015
? 0
: 'The hash iterator used in dump.c sets the OOK flag');
do_test('typeglob',
*a,
'SV = PVGV\\($ADDR\\) at $ADDR
REFCNT = 5
FLAGS = \\(MULTI(?:,IN_PAD)?\\)
NAME = "a"
NAMELEN = 1
GvSTASH = $ADDR\\t"main"
FLAGS = $ADDR # $] >=5.021004
GP = $ADDR
SV = $ADDR
REFCNT = 1
IO = 0x0
FORM = 0x0
AV = 0x0
HV = 0x0
CV = 0x0
CVGEN = 0x0
GPFLAGS = 0x0 \(\) # $] >= 5.021004
LINE = \\d+
FILE = ".*\\b(?i:peek\\.t)"
FLAGS = $ADDR # $] < 5.021004
EGV = $ADDR\\t"a"');
if (ord('A') == 193) {
do_test('string with Unicode',
chr(256).chr(0).chr(512),
'SV = PV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\((?:PADTMP,)?POK,READONLY,pPOK,UTF8\\) # $] < 5.019003
FLAGS = \\((?:PADTMP,)?POK,(?:IsCOW,)?pPOK,UTF8\\) # $] >=5.019003
PV = $ADDR "\\\214\\\101\\\0\\\235\\\101"\\\0 \[UTF8 "\\\x\{100\}\\\x\{0\}\\\x\{200\}"\]
CUR = 5
LEN = \\d+
COW_REFCNT = 1 # $] < 5.019007
');
} else {
do_test('string with Unicode',
chr(256).chr(0).chr(512),
'SV = PV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\((?:PADTMP,)?POK,READONLY,pPOK,UTF8\\) # $] < 5.019003
FLAGS = \\((?:PADTMP,)?POK,(?:IsCOW,)?pPOK,UTF8\\) # $] >=5.019003
PV = $ADDR "\\\304\\\200\\\0\\\310\\\200"\\\0 \[UTF8 "\\\x\{100\}\\\x\{0\}\\\x\{200\}"\]
CUR = 5
LEN = \\d+
COW_REFCNT = 1 # $] < 5.019007
');
}
if (ord('A') == 193) {
do_test('reference to hash containing Unicode',
{chr(256)=>chr(512)},
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVHV\\($ADDR\\) at $ADDR
REFCNT = [12]
FLAGS = \\(SHAREKEYS,HASKFLAGS\\)
ARRAY = $ADDR \\(0:7, 1:1\\)
hash quality = 100.0%
KEYS = 1
FILL = 1
MAX = 7
Elt "\\\214\\\101" \[UTF8 "\\\x\{100\}"\] HASH = $ADDR
SV = PV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(POK,(?:IsCOW,)?pPOK,UTF8\\)
PV = $ADDR "\\\235\\\101"\\\0 \[UTF8 "\\\x\{200\}"\]
CUR = 2
LEN = \\d+
COW_REFCNT = 1 # $] < 5.019007
', '',
$] >= 5.015
? 0
: 'The hash iterator used in dump.c sets the OOK flag');
} else {
do_test('reference to hash containing Unicode',
{chr(256)=>chr(512)},
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVHV\\($ADDR\\) at $ADDR
REFCNT = [12]
FLAGS = \\(SHAREKEYS,HASKFLAGS\\)
ARRAY = $ADDR \\(0:7, 1:1\\)
hash quality = 100.0%
KEYS = 1
FILL = 1
MAX = 7
Elt "\\\304\\\200" \[UTF8 "\\\x\{100\}"\] HASH = $ADDR
SV = PV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(POK,(?:IsCOW,)?pPOK,UTF8\\)
PV = $ADDR "\\\310\\\200"\\\0 \[UTF8 "\\\x\{200\}"\]
CUR = 2
LEN = \\d+
COW_REFCNT = 1 # $] < 5.019007
', '',
$] >= 5.015
? 0
: 'The hash iterator used in dump.c sets the OOK flag');
}
my $x="";
$x=~/.??/g;
do_test('scalar with pos magic',
$x,
'SV = PVMG\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\($PADMY,SMG,POK,(?:IsCOW,)?pPOK\\)
IV = \d+
NV = 0
PV = $ADDR ""\\\0
CUR = 0
LEN = \d+
COW_REFCNT = [12]
MAGIC = $ADDR
MG_VIRTUAL = &PL_vtbl_mglob
MG_TYPE = PERL_MAGIC_regex_global\\(g\\)
MG_FLAGS = 0x01 # $] < 5.019003
MG_FLAGS = 0x41 # $] >=5.019003
MINMATCH
BYTES # $] >=5.019003
');
#
# TAINTEDDIR is not set on: OS2, AMIGAOS, WIN32, MSDOS
# environment variables may be invisibly case-forced, hence the (?i:PATH)
# C<scalar(@ARGV)> is turned into an IV on VMS hence the (?:IV)?
# Perl 5.18 ensures all env vars end up as strings only, hence the (?:,pIOK)?
# Perl 5.18 ensures even magic vars have public OK, hence the (?:,POK)?
# VMS is setting FAKE and READONLY flags. What VMS uses for storing
# ENV hashes is also not always null terminated.
#
if (${^TAINT}) {
# Save and restore PATH, since fresh_perl ends up using that in Windows.
my $path = $ENV{PATH};
do_test('tainted value in %ENV',
$ENV{PATH}=@ARGV, # scalar(@ARGV) is a handy known tainted value
'SV = PVMG\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(GMG,SMG,RMG(?:,POK)?(?:,pIOK)?,pPOK\\)
IV = 0
NV = 0
PV = $ADDR "0"\\\0
CUR = 1
LEN = \d+
MAGIC = $ADDR
MG_VIRTUAL = &PL_vtbl_envelem
MG_TYPE = PERL_MAGIC_envelem\\(e\\)
(?: MG_FLAGS = 0x01
TAINTEDDIR
)? MG_LEN = -?\d+
MG_PTR = $ADDR (?:"(?i:PATH)"|=> HEf_SVKEY
SV = PV(?:IV)?\\($ADDR\\) at $ADDR
REFCNT = \d+
FLAGS = \\((?:TEMP,)?POK,(?:FAKE,READONLY,)?pPOK\\)
(?: IV = 0
)? PV = $ADDR "(?i:PATH)"(?:\\\0)?
CUR = \d+
LEN = \d+)
MAGIC = $ADDR
MG_VIRTUAL = &PL_vtbl_taint
MG_TYPE = PERL_MAGIC_taint\\(t\\)');
$ENV{PATH} = $path;
}
do_test('blessed reference',
bless(\\undef, 'Foobar'),
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVMG\\($ADDR\\) at $ADDR
REFCNT = 2
FLAGS = \\(OBJECT,ROK\\)
IV = -?\d+
NV = $FLOAT
RV = $ADDR
SV = NULL\\(0x0\\) at $ADDR
REFCNT = \d+
FLAGS = \\(READONLY\\) # $] < 5.021005
FLAGS = \\(READONLY,PROTECT\\) # $] >=5.021005
PV = $ADDR ""
CUR = 0
LEN = 0
STASH = $ADDR\s+"Foobar"');
sub const () {
"Perl rules";
}
do_test('constant subroutine',
\&const,
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVCV\\($ADDR\\) at $ADDR
REFCNT = (2)
FLAGS = \\(POK,pPOK,CONST,ISXSUB\\) # $] < 5.015
FLAGS = \\(POK,pPOK,CONST,DYNFILE,ISXSUB\\) # $] >= 5.015
PROTOTYPE = ""
COMP_STASH = 0x0 # $] < 5.021004
COMP_STASH = $ADDR "main" # $] >=5.021004
XSUB = $ADDR
XSUBANY = $ADDR \\(CONST SV\\)
SV = PV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(.*POK,READONLY,(?:IsCOW,)?pPOK\\) # $] < 5.021005
FLAGS = \\(.*POK,(?:IsCOW,)?READONLY,PROTECT,pPOK\\) # $] >=5.021005
PV = $ADDR "Perl rules"\\\0
CUR = 10
LEN = \\d+
COW_REFCNT = 0
GVGV::GV = $ADDR\\t"main" :: "const"
FILE = ".*\\b(?i:peek\\.t)"
DEPTH = 0(?:
MUTEXP = $ADDR
OWNER = $ADDR)?
FLAGS = 0xc00 # $] < 5.013
FLAGS = 0xc # $] >= 5.013 && $] < 5.015
FLAGS = 0x100c # $] >= 5.015
OUTSIDE_SEQ = 0
PADLIST = 0x0 # $] < 5.021006
HSCXT = $ADDR # $] >= 5.021006
OUTSIDE = 0x0 \\(null\\)');
do_test('isUV should show on PVMG',
do { my $v = $1; $v = ~0; $v },
'SV = PVMG\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(IOK,pIOK,IsUV\\)
UV = \d+
NV = 0
PV = 0');
do_test('IO',
*STDOUT{IO},
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVIO\\($ADDR\\) at $ADDR
REFCNT = 3
FLAGS = \\(OBJECT\\)
IV = 0 # $] < 5.011
NV = 0 # $] < 5.011
STASH = $ADDR\s+"IO::File"
IFP = $ADDR
OFP = $ADDR
DIRP = 0x0
LINES = 0
PAGE = 0
PAGE_LEN = 60
LINES_LEFT = 0
TOP_GV = 0x0
FMT_GV = 0x0
BOTTOM_GV = 0x0
TYPE = \'>\'
FLAGS = 0x4');
do_test('FORMAT',
*PIE{FORMAT},
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVFM\\($ADDR\\) at $ADDR
REFCNT = 2
FLAGS = \\(\\) # $] < 5.015 || !thr
FLAGS = \\(DYNFILE\\) # $] >= 5.015 && thr
(?: PV = 0
)? COMP_STASH = 0x0
START = $ADDR ===> \\d+
ROOT = $ADDR
GVGV::GV = $ADDR\\t"main" :: "PIE"
FILE = ".*\\b(?i:peek\\.t)"(?:
DEPTH = 0)?(?:
MUTEXP = $ADDR
OWNER = $ADDR)?
FLAGS = 0x0 # $] < 5.015 || !thr
FLAGS = 0x1000 # $] >= 5.015 && thr
OUTSIDE_SEQ = \\d+
LINES = 0 # $] < 5.017_003
PADLIST = $ADDR
PADNAME = $ADDR\\($ADDR\\) PAD = $ADDR\\($ADDR\\)
OUTSIDE = $ADDR \\(MAIN\\)');
do_test('blessing to a class with embedded NUL characters',
(bless {}, "\0::foo::\n::baz::\t::\0"),
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVHV\\($ADDR\\) at $ADDR
REFCNT = [12]
FLAGS = \\(OBJECT,SHAREKEYS\\)
STASH = $ADDR\\t"\\\\0::foo::\\\\n::baz::\\\\t::\\\\0"
ARRAY = $ADDR
KEYS = 0
FILL = 0
MAX = 7', '',
$] >= 5.015
? 0
: 'The hash iterator used in dump.c sets the OOK flag');
do_test('ENAME on a stash',
\%RWOM::,
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVHV\\($ADDR\\) at $ADDR
REFCNT = 2
FLAGS = \\(OOK,SHAREKEYS\\)
AUX_FLAGS = 0 # $] > 5.019008
ARRAY = $ADDR
KEYS = 0
FILL = 0
MAX = 7
RITER = -1
EITER = 0x0
RAND = $ADDR
NAME = "RWOM"
ENAME = "RWOM" # $] > 5.012
');
*KLANK:: = \%RWOM::;
do_test('ENAMEs on a stash',
\%RWOM::,
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVHV\\($ADDR\\) at $ADDR
REFCNT = 3
FLAGS = \\(OOK,SHAREKEYS\\)
AUX_FLAGS = 0 # $] > 5.019008
ARRAY = $ADDR
KEYS = 0
FILL = 0
MAX = 7
RITER = -1
EITER = 0x0
RAND = $ADDR
NAME = "RWOM"
NAMECOUNT = 2 # $] > 5.012
ENAME = "RWOM", "KLANK" # $] > 5.012
');
undef %RWOM::;
do_test('ENAMEs on a stash with no NAME',
\%RWOM::,
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVHV\\($ADDR\\) at $ADDR
REFCNT = 3
FLAGS = \\(OOK,SHAREKEYS\\) # $] < 5.017
FLAGS = \\(OOK,OVERLOAD,SHAREKEYS\\) # $] >=5.017 && $]<5.021005
FLAGS = \\(OOK,SHAREKEYS,OVERLOAD\\) # $] >=5.021005
AUX_FLAGS = 0 # $] > 5.019008
ARRAY = $ADDR
KEYS = 0
FILL = 0
MAX = 7
RITER = -1
EITER = 0x0
RAND = $ADDR
NAMECOUNT = -3 # $] > 5.012
ENAME = "RWOM", "KLANK" # $] > 5.012
');
my %small = ("Perl", "Rules", "Beer", "Foamy");
my $b = %small;
do_test('small hash',
\%small,
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVHV\\($ADDR\\) at $ADDR
REFCNT = 2
FLAGS = \\($PADMY,SHAREKEYS\\)
ARRAY = $ADDR \\(0:[67],.*\\)
hash quality = [0-9.]+%
KEYS = 2
FILL = [12]
MAX = 7
(?: Elt "(?:Perl|Beer)" HASH = $ADDR
SV = PV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(POK,(?:IsCOW,)?pPOK\\)
PV = $ADDR "(?:Rules|Foamy)"\\\0
CUR = \d+
LEN = \d+
COW_REFCNT = 1
){2}');
$b = keys %small;
do_test('small hash after keys',
\%small,
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVHV\\($ADDR\\) at $ADDR
REFCNT = 2
FLAGS = \\($PADMY,OOK,SHAREKEYS\\)
AUX_FLAGS = 0 # $] > 5.019008
ARRAY = $ADDR \\(0:[67],.*\\)
hash quality = [0-9.]+%
KEYS = 2
FILL = [12]
MAX = 7
RITER = -1
EITER = 0x0
RAND = $ADDR
(?: Elt "(?:Perl|Beer)" HASH = $ADDR
SV = PV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(POK,(?:IsCOW,)?pPOK\\)
PV = $ADDR "(?:Rules|Foamy)"\\\0
CUR = \d+
LEN = \d+
COW_REFCNT = 1
){2}');
$b = %small;
do_test('small hash after keys and scalar',
\%small,
'SV = $RV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(ROK\\)
RV = $ADDR
SV = PVHV\\($ADDR\\) at $ADDR
REFCNT = 2
FLAGS = \\($PADMY,OOK,SHAREKEYS\\)
AUX_FLAGS = 0 # $] > 5.019008
ARRAY = $ADDR \\(0:[67],.*\\)
hash quality = [0-9.]+%
KEYS = 2
FILL = ([12])
MAX = 7
RITER = -1
EITER = 0x0
RAND = $ADDR
(?: Elt "(?:Perl|Beer)" HASH = $ADDR
SV = PV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\(POK,(?:IsCOW,)?pPOK\\)
PV = $ADDR "(?:Rules|Foamy)"\\\0
CUR = \d+
LEN = \d+
COW_REFCNT = 1
){2}');
# Dump with arrays, hashes, and operator return values
@array = 1..3;
do_test('Dump @array', '@array', <<'ARRAY', '', '', 1);
SV = PVAV\($ADDR\) at $ADDR
REFCNT = 1
FLAGS = \(\)
ARRAY = $ADDR
FILL = 2
MAX = 3
FLAGS = \(REAL\)
Elt No. 0
SV = IV\($ADDR\) at $ADDR
REFCNT = 1
FLAGS = \(IOK,pIOK\)
IV = 1
Elt No. 1
SV = IV\($ADDR\) at $ADDR
REFCNT = 1
FLAGS = \(IOK,pIOK\)
IV = 2
Elt No. 2
SV = IV\($ADDR\) at $ADDR
REFCNT = 1
FLAGS = \(IOK,pIOK\)
IV = 3
ARRAY
do_test('Dump @array,1', '@array,1', <<'ARRAY', '', '', 1);
SV = PVAV\($ADDR\) at $ADDR
REFCNT = 1
FLAGS = \(\)
ARRAY = $ADDR
FILL = 2
MAX = 3
FLAGS = \(REAL\)
Elt No. 0
SV = IV\($ADDR\) at $ADDR
REFCNT = 1
FLAGS = \(IOK,pIOK\)
IV = 1
ARRAY
%hash = 1..2;
do_test('Dump %hash', '%hash', <<'HASH', '', '', 1);
SV = PVHV\($ADDR\) at $ADDR
REFCNT = 1
FLAGS = \(SHAREKEYS\)
ARRAY = $ADDR \(0:7, 1:1\)
hash quality = 100.0%
KEYS = 1
FILL = 1
MAX = 7
Elt "1" HASH = $ADDR
SV = IV\($ADDR\) at $ADDR
REFCNT = 1
FLAGS = \(IOK,pIOK\)
IV = 2
HASH
$_ = "hello";
do_test('rvalue substr', 'substr $_, 1, 2', <<'SUBSTR', '', '', 1);
SV = PV\($ADDR\) at $ADDR
REFCNT = 1
FLAGS = \(PADTMP,POK,pPOK\)
PV = $ADDR "el"\\0
CUR = 2
LEN = \d+
SUBSTR
# Dump with no arguments
eval 'Dump';
like $@, qr/^Not enough arguments for Devel::Peek::Dump/, 'Dump;';
eval 'Dump()';
like $@, qr/^Not enough arguments for Devel::Peek::Dump/, 'Dump()';
SKIP: {
skip "Not built with usemymalloc", 2
unless $Config{usemymalloc} eq 'y';
my $x = __PACKAGE__;
ok eval { fill_mstats($x); 1 }, 'fill_mstats on COW scalar'
or diag $@;
my $y;
ok eval { fill_mstats($y); 1 }, 'fill_mstats on undef scalar';
}
# This is more a test of fbm_compile/pp_study (non) interaction than dumping
# prowess, but short of duplicating all the gubbins of this file, I can't see
# a way to make a better place for it:
use constant {
# The length of the rhs string must be such that if chr() is applied to it
# doesn't yield a character with a backslash mnemonic. For example, if it
# were 'rules' instead of 'rule', it would have 5 characters, and on
# EBCDIC, chr(5) is \t. The dumping code would translate all the 5's in
# MG_PTR into "\t", and this test code would be expecting \5's, so the
# tests would fail. No platform that Perl works on translates chr(4) into
# a mnemonic.
perl => 'rule',
beer => 'foam',
};
unless ($Config{useithreads}) {
# These end up as copies in pads under ithreads, which rather defeats the
# the point of what we're trying to test here.
do_test('regular string constant', perl,
'SV = PV\\($ADDR\\) at $ADDR
REFCNT = 5
FLAGS = \\(PADMY,POK,READONLY,(?:IsCOW,)?pPOK\\) # $] < 5.021005
FLAGS = \\(POK,(?:IsCOW,)?READONLY,pPOK\\) # $] >=5.021005
PV = $ADDR "rule"\\\0
CUR = 4
LEN = \d+
COW_REFCNT = 0
');
eval 'index "", perl';
do_test('string constant now an FBM', perl,
'SV = PVMG\\($ADDR\\) at $ADDR
REFCNT = 5
FLAGS = \\($PADMY,SMG,POK,(?:IsCOW,)?READONLY,(?:IsCOW,)?pPOK\\)
PV = $ADDR "rule"\\\0
CUR = 4
LEN = \d+
COW_REFCNT = 0
MAGIC = $ADDR
MG_VIRTUAL = &PL_vtbl_regexp
MG_TYPE = PERL_MAGIC_bm\\(B\\)
MG_LEN = 256
MG_PTR = $ADDR "(?:\\\\\d){256}"
RARE = \d+ # $] < 5.019002
PREVIOUS = 1 # $] < 5.019002
USEFUL = 100
');
is(study perl, '', "Not allowed to study an FBM");
do_test('string constant still an FBM', perl,
'SV = PVMG\\($ADDR\\) at $ADDR
REFCNT = 5
FLAGS = \\($PADMY,SMG,POK,(?:IsCOW,)?READONLY,(?:IsCOW,)?pPOK\\)
PV = $ADDR "rule"\\\0
CUR = 4
LEN = \d+
COW_REFCNT = 0
MAGIC = $ADDR
MG_VIRTUAL = &PL_vtbl_regexp
MG_TYPE = PERL_MAGIC_bm\\(B\\)
MG_LEN = 256
MG_PTR = $ADDR "(?:\\\\\d){256}"
RARE = \d+ # $] < 5.019002
PREVIOUS = 1 # $] < 5.019002
USEFUL = 100
');
do_test('regular string constant', beer,
'SV = PV\\($ADDR\\) at $ADDR
REFCNT = 6
FLAGS = \\(PADMY,POK,READONLY,(?:IsCOW,)?pPOK\\) # $] < 5.021005
FLAGS = \\(POK,(?:IsCOW,)?READONLY,pPOK\\) # $] >=5.021005
PV = $ADDR "foam"\\\0
CUR = 4
LEN = \d+
COW_REFCNT = 0
');
is(study beer, 1, "Our studies were successful");
do_test('string constant quite unaffected', beer, 'SV = PV\\($ADDR\\) at $ADDR
REFCNT = 6
FLAGS = \\(PADMY,POK,READONLY,(?:IsCOW,)?pPOK\\) # $] < 5.021005
FLAGS = \\(POK,(?:IsCOW,)?READONLY,pPOK\\) # $] >=5.021005
PV = $ADDR "foam"\\\0
CUR = 4
LEN = \d+
COW_REFCNT = 0
');
my $want = 'SV = PVMG\\($ADDR\\) at $ADDR
REFCNT = 6
FLAGS = \\($PADMY,SMG,POK,(?:IsCOW,)?READONLY,(?:IsCOW,)?pPOK\\)
PV = $ADDR "foam"\\\0
CUR = 4
LEN = \d+
COW_REFCNT = 0
MAGIC = $ADDR
MG_VIRTUAL = &PL_vtbl_regexp
MG_TYPE = PERL_MAGIC_bm\\(B\\)
MG_LEN = 256
MG_PTR = $ADDR "(?:\\\\\d){256}"
RARE = \d+ # $] < 5.019002
PREVIOUS = \d+ # $] < 5.019002
USEFUL = 100
';
is (eval 'index "not too foamy", beer', 8, 'correct index');
do_test('string constant now FBMed', beer, $want);
my $pie = 'good';
is(study $pie, 1, "Our studies were successful");
do_test('string constant still FBMed', beer, $want);
do_test('second string also unaffected', $pie, 'SV = PV\\($ADDR\\) at $ADDR
REFCNT = 1
FLAGS = \\($PADMY,POK,(?:IsCOW,)?pPOK\\)
PV = $ADDR "good"\\\0
CUR = 4
LEN = \d+
COW_REFCNT = 1
');
}
# (One block of study tests removed when study was made a no-op.)
{
open(OUT, '>', "peek$$") or die "Failed to open peek $$: $!";
open(STDERR, ">&OUT") or die "Can't dup OUT: $!";
DeadCode();
open(STDERR, ">&SAVERR") or die "Can't restore STDERR: $!";
pass "no crash with DeadCode";
close OUT;
}
# note the conditionals on ENGINE and INTFLAGS were introduced in 5.19.9
do_test('UTF-8 in a regular expression',
qr/\x{100}/,
'SV = IV\($ADDR\) at $ADDR
REFCNT = 1
FLAGS = \(ROK\)
RV = $ADDR
SV = REGEXP\($ADDR\) at $ADDR
REFCNT = 1
FLAGS = \(OBJECT,FAKE,UTF8\)
PV = $ADDR "\(\?\^u:\\\\\\\\x\{100\}\)" \[UTF8 "\(\?\^u:\\\\\\\\x\{100\}\)"\]
CUR = 13
STASH = $ADDR "Regexp"
COMPFLAGS = 0x0 \(\)
EXTFLAGS = $ADDR \(CHECK_ALL,USE_INTUIT_NOML,USE_INTUIT_ML\)
(?: ENGINE = $ADDR \(STANDARD\)
)? INTFLAGS = 0x0(?: \(\))?
NPARENS = 0
LASTPAREN = 0
LASTCLOSEPAREN = 0
MINLEN = 1
MINLENRET = 1
GOFS = 0
PRE_PREFIX = 5
SUBLEN = 0
SUBOFFSET = 0
SUBCOFFSET = 0
SUBBEG = 0x0
(?: ENGINE = $ADDR
)? MOTHER_RE = $ADDR'
. ($] < 5.019003 ? '' : '
SV = REGEXP\($ADDR\) at $ADDR
REFCNT = 2
FLAGS = \(UTF8\)
PV = $ADDR "\(\?\^u:\\\\\\\\x\{100\}\)" \[UTF8 "\(\?\^u:\\\\\\\\x\{100\}\)"\]
CUR = 13
COMPFLAGS = 0x0 \(\)
EXTFLAGS = $ADDR \(CHECK_ALL,USE_INTUIT_NOML,USE_INTUIT_ML\)
(?: ENGINE = $ADDR \(STANDARD\)
)? INTFLAGS = 0x0(?: \(\))?
NPARENS = 0
LASTPAREN = 0
LASTCLOSEPAREN = 0
MINLEN = 1
MINLENRET = 1
GOFS = 0
PRE_PREFIX = 5
SUBLEN = 0
SUBOFFSET = 0
SUBCOFFSET = 0
SUBBEG = 0x0
(?: ENGINE = $ADDR
)? MOTHER_RE = 0x0
PAREN_NAMES = 0x0
SUBSTRS = $ADDR
PPRIVATE = $ADDR
OFFS = $ADDR
QR_ANONCV = 0x0(?:
SAVED_COPY = 0x0)?') . '
PAREN_NAMES = 0x0
SUBSTRS = $ADDR
PPRIVATE = $ADDR
OFFS = $ADDR
QR_ANONCV = 0x0(?:
SAVED_COPY = 0x0)?
');
{ # perl #117793: Extend SvREFCNT* to work on any perl variable type
my %hash;
my $base_count = Devel::Peek::SvREFCNT(%hash);
my $ref = \%hash;
is(Devel::Peek::SvREFCNT(%hash), $base_count + 1, "SvREFCNT on non-scalar");
ok(!eval { &Devel::Peek::SvREFCNT(1) }, "requires prototype");
}
{
# utf8 tests
use utf8;
sub _dump {
open(OUT, '>', "peek$$") or die $!;
open(STDERR, ">&OUT") or die "Can't dup OUT: $!";
Dump($_[0]);
open(STDERR, ">&SAVERR") or die "Can't restore STDERR: $!";
close(OUT);
open(IN, '<', "peek$$") or die $!;
my $dump = do { local $/; <IN> };
close(IN);
1 while unlink "peek$$";
return $dump;
}
sub _get_coderef {
my $x = $_[0];
utf8::upgrade($x);
eval "sub $x {}; 1" or die $@;
return *{$x}{CODE};
}
like(
_dump(_get_coderef("\x{df}::\xdf")),
qr/GVGV::GV = 0x[[:xdigit:]]+\s+\Q"\xdf" :: "\xdf"/,
"GVGV's are correctly escaped for latin1 :: latin1",
);
like(
_dump(_get_coderef("\x{30cd}::\x{30cd}")),
qr/GVGV::GV = 0x[[:xdigit:]]+\s+\Q"\x{30cd}" :: "\x{30cd}"/,
"GVGV's are correctly escaped for UTF8 :: UTF8",
);
like(
_dump(_get_coderef("\x{df}::\x{30cd}")),
qr/GVGV::GV = 0x[[:xdigit:]]+\s+\Q"\xdf" :: "\x{30cd}"/,
"GVGV's are correctly escaped for latin1 :: UTF8",
);
like(
_dump(_get_coderef("\x{30cd}::\x{df}")),
qr/GVGV::GV = 0x[[:xdigit:]]+\s+\Q"\x{30cd}" :: "\xdf"/,
"GVGV's are correctly escaped for UTF8 :: latin1",
);
like(
_dump(_get_coderef("\x{30cb}::\x{df}::\x{30cd}")),
qr/GVGV::GV = 0x[[:xdigit:]]+\s+\Q"\x{30cb}::\x{df}" :: "\x{30cd}"/,
"GVGV's are correctly escaped for UTF8 :: latin 1 :: UTF8",
);
my $dump = _dump(*{"\x{30cb}::\x{df}::\x{30dc}"});
like(
$dump,
qr/NAME = \Q"\x{30dc}"/,
"NAME is correctly escaped for UTF8 globs",
);
like(
$dump,
qr/GvSTASH = 0x[[:xdigit:]]+\s+\Q"\x{30cb}::\x{df}"/,
"GvSTASH is correctly escaped for UTF8 globs"
);
like(
$dump,
qr/EGV = 0x[[:xdigit:]]+\s+\Q"\x{30dc}"/,
"EGV is correctly escaped for UTF8 globs"
);
$dump = _dump(*{"\x{df}::\x{30cc}"});
like(
$dump,
qr/NAME = \Q"\x{30cc}"/,
"NAME is correctly escaped for UTF8 globs with latin1 stashes",
);
like(
$dump,
qr/GvSTASH = 0x[[:xdigit:]]+\s+\Q"\xdf"/,
"GvSTASH is correctly escaped for UTF8 globs with latin1 stashes"
);
like(
$dump,
qr/EGV = 0x[[:xdigit:]]+\s+\Q"\x{30cc}"/,
"EGV is correctly escaped for UTF8 globs with latin1 stashes"
);
like(
_dump(bless {}, "\0::\1::\x{30cd}"),
qr/STASH = 0x[[:xdigit:]]+\s+\Q"\0::\x{01}::\x{30cd}"/,
"STASH for blessed hashrefs is correct"
);
BEGIN { $::{doof} = "\0\1\x{30cd}" }
like(
_dump(\&doof),
qr/PROTOTYPE = \Q"\0\x{01}\x{30cd}"/,
"PROTOTYPE is escaped correctly"
);
{
my $coderef = eval <<"EOP";
use feature 'lexical_subs';
no warnings 'experimental::lexical_subs';
my sub bar (\$\x{30cd}) {1}; \\&bar
EOP
like(
_dump($coderef),
qr/PROTOTYPE = "\$\Q\x{30cd}"/,
"PROTOTYPE works on lexical subs"
)
}
sub get_outside {
eval "sub $_[0] { my \$x; \$x++; return sub { eval q{\$x} } } $_[0]()";
}
sub basic { my $x; return eval q{sub { eval q{$x} }} }
like(
_dump(basic()),
qr/OUTSIDE = 0x[[:xdigit:]]+\s+\Q(basic)/,
'OUTSIDE works'
);
like(
_dump(get_outside("\x{30ce}")),
qr/OUTSIDE = 0x[[:xdigit:]]+\s+\Q(\x{30ce})/,
'OUTSIDE + UTF8 works'
);
# TODO AUTOLOAD = stashname, which requires using a XS autoload
# and calling Dump() on the cv
sub test_utf8_stashes {
my ($stash_name, $test) = @_;
$dump = _dump(\%{"${stash_name}::"});
my $format = utf8::is_utf8($stash_name) ? '\x{%2x}' : '\x%2x';
$escaped_stash_name = join "", map {
$_ eq ':' ? $_ : sprintf $format, ord $_
} split //, $stash_name;
like(
$dump,
qr/\QNAME = "$escaped_stash_name"/,
"NAME is correct escaped for $test"
);
like(
$dump,
qr/\QENAME = "$escaped_stash_name"/,
"ENAME is correct escaped for $test"
);
}
for my $test (
[ "\x{30cd}", "UTF8 stashes" ],
[ "\x{df}", "latin 1 stashes" ],
[ "\x{df}::\x{30cd}", "latin1 + UTF8 stashes" ],
[ "\x{30cd}::\x{df}", "UTF8 + latin1 stashes" ],
) {
test_utf8_stashes(@$test);
}
}
my $runperl_args = { switches => ['-Ilib'] };
sub test_DumpProg {
my ($prog, $expected, $name, $test) = @_;
$test ||= 'like';
my $u = 'use Devel::Peek "DumpProg"; DumpProg();';
# Interface between Test::Builder & test.pl
my $builder = Test::More->builder();
t::curr_test($builder->current_test() + 1);
utf8::encode($prog);
if ( $test eq 'is' ) {
t::fresh_perl_is($prog . $u, $expected, $runperl_args, $name)
}
else {
t::fresh_perl_like($prog . $u, $expected, $runperl_args, $name)
}
$builder->current_test(t::curr_test() - 1);
}
my $threads = $Config{'useithreads'};
for my $test (
[
"package test;",
qr/PACKAGE = "test"/,
"DumpProg() + package declaration"
],
[
"use utf8; package \x{30cd};",
qr/PACKAGE = "\\x\Q{30cd}"/,
"DumpProg() + UTF8 package declaration"
],
[
"use utf8; sub \x{30cc}::\x{30cd} {1}; \x{30cc}::\x{30cd};",
($threads ? qr/PADIX = \d+/ : qr/GV = \Q\x{30cc}::\x{30cd}\E/)
],
[
"use utf8; \x{30cc}: { last \x{30cc} }",
qr/LABEL = \Q"\x{30cc}"/
],
)
{
test_DumpProg(@$test);
}
{
local $TODO = 'This gets mangled by the current pipe implementation' if $^O eq 'VMS';
my $e = <<'EODUMP';
dumpindent is 4 at -e line 1.
1 leave LISTOP(0xNNN) ===> [0x0]
TARG = 1
FLAGS = (VOID,KIDS,PARENS,SLABBED)
PRIVATE = (REFC)
REFCNT = 1
|
2 +--enter OP(0xNNN) ===> 3 [nextstate 0xNNN]
| FLAGS = (UNKNOWN,SLABBED,MORESIB)
|
3 +--nextstate COP(0xNNN) ===> 4 [pushmark 0xNNN]
| FLAGS = (VOID,SLABBED,MORESIB)
| LINE = 1
| PACKAGE = "t"
| |
5 +--entersub UNOP(0xNNN) ===> 1 [leave 0xNNN]
TARG = 1
FLAGS = (VOID,KIDS,STACKED,SLABBED)
PRIVATE = (TARG)
|
6 +--null (ex-list) UNOP(0xNNN) ===> 5 [entersub 0xNNN]
FLAGS = (UNKNOWN,KIDS,SLABBED)
|
4 +--pushmark OP(0xNNN) ===> 7 [gv 0xNNN]
| FLAGS = (SCALAR,SLABBED,MORESIB)
|
8 +--null (ex-rv2cv) UNOP(0xNNN) ===> 6 [null 0xNNN]
FLAGS = (SCALAR,KIDS,SLABBED)
PRIVATE = (0x1)
|
7 +--gv SVOP(0xNNN) ===> 5 [entersub 0xNNN]
FLAGS = (SCALAR,SLABBED)
GV_OR_PADIX
EODUMP
$e =~ s/GV_OR_PADIX/$threads ? "PADIX = 2" : "GV = t::DumpProg (0xNNN)"/e;
$e =~ s/SVOP/PADOP/g if $threads;
my $out = t::runperl
switches => ['-Ilib'],
prog => 'package t; use Devel::Peek q-DumpProg-; DumpProg();',
stderr=>1;
$out =~ s/ *SEQ = .*\n//;
$out =~ s/0x[0-9a-f]{2,}\]/${1}0xNNN]/g;
$out =~ s/\(0x[0-9a-f]{3,}\)/(0xNNN)/g;
is $out, $e, "DumpProg() has no 'Attempt to free X prematurely' warning";
}
done_testing();