3 # testsuite for Data::Dumper
13 # Since Perl 5.8.1 because otherwise hash ordering is really random.
14 $Data::Dumper::Sortkeys = 1;
15 $Data::Dumper::Pad = "#";
19 # Force Data::Dumper::Dump to use perl. We test Dumpxs explicitly by calling
20 # it direct. Out here it lets us knobble the next if to test that the perl
21 # only tests do work (and count correctly)
22 $Data::Dumper::Useperl = 1;
23 if (defined &Data::Dumper::Dumpxs) {
24 print "### XS extension loaded, will run XS tests\n";
28 print "### XS extensions not loaded, will NOT run XS tests\n";
32 our ( @a, $c, $d, $foo, @foo, %foo, @globs, $v, $ping, %ping );
33 our ( @dogs, %kennel, $mutts );
35 our ( @numbers, @strings );
36 our ( @numbers_s, @numbers_i, @numbers_is, @numbers_n, @numbers_ns, @numbers_ni, @numbers_nis );
37 our ( @strings_s, @strings_i, @strings_is, @strings_n, @strings_ns, @strings_ni, @strings_nis );
39 # Perl 5.16 was the first version that correctly handled Unicode in typeglob
40 # names. Tests for how globs are dumped must revise their expectations
41 # downwards when run on earlier Perls.
42 sub change_glob_expectation {
45 $input =~ s<\\x\{([0-9a-f]+)\}>{
48 join '', map sprintf('\\%o', ord), split //, $s;
54 sub convert_to_native {
59 # The input should always be one of the following constructs
60 while ($input =~ m/ ( \\ [0-7]+ )
61 | ( \\ x \{ [[:xdigit:]]+ } )
65 #print STDERR __LINE__, ": ", $&, "\n";
68 if (defined $4) { # Literal
72 elsif (defined $3) { # backslash escape
73 $index = ord eval "\"$3\"";
76 elsif (defined $2) { # Hex
77 $index = utf8::unicode_to_native(ord eval "\"$2\"");
79 # But low hex numbers are always in octal. These are all
80 # controls. The outlier \c? control is also in octal.
81 my $format = ($index < ord(" ") || $index == ord("\c?"))
84 $replacement = sprintf($format, $index);
86 elsif (defined $1) { # Octal
87 $index = utf8::unicode_to_native(ord eval "\"$1\"");
88 $replacement = sprintf("\\%o", $index);
91 die "Unexpected match in convert_to_native()";
94 if (defined $output[$index]) {
95 print STDERR "ordinal $index already has '$output[$index]'; skipping '$replacement'\n";
99 $output[$index] = $replacement;
102 return join "", grep { defined } @output;
106 my ($string, $desc, $want) = @_;
107 Carp::confess("Tests must have a description")
110 local $Test::Builder::Level = $Test::Builder::Level + 1;
118 if (defined $error && length $error) {
119 is($error, "", "$desc set \$@");
120 skip('No point in running eval after an error', 2);
123 $have =~ s/([A-Z]+)\(0x[0-9a-f]+\)/$1(0xdeadbeef)/g
124 if $want =~ /deadbeef/;
125 is($have, $want, $desc);
132 is($@, "", "$desc - output did not eval")
133 or skip('No point in restesting if output failed eval');
141 if (defined $error && length $error) {
142 is($error, "", "$desc after eval set \$@");
145 $have =~ s/([A-Z]+)\(0x[0-9a-f]+\)/$1(0xdeadbeef)/g
146 if $want =~ /deadbeef/;
147 is($have, $want, "$desc after eval");
155 skip($reason, $XS ? 6 : 3);
159 # It's more reliable to match (and substitute) on 'Dumpxs' than 'Dump'
160 # (the latter is a substring of many things), but as historically we've tested
161 # "pure perl" then "XS" it seems better to have $want_xs as an optional
164 my ($testcase, $desc, $want, $want_xs, $skip_xs) = @_;
166 unless defined $want_xs;
168 my $testcase_pp = $testcase;
169 Carp::confess("Testcase must contain ->Dumpxs or DumperX")
170 unless $testcase_pp =~ s/->Dumpxs\b/->Dump/g
171 || $testcase_pp =~ s/\bDumperX\b/Dumper/g;
172 unless ($desc_pp =~ s/Dumpxs/Dump/ || $desc_pp =~ s/\bDumperX\b/Dumper/) {
176 local $Test::Builder::Level = $Test::Builder::Level + 1;
177 TEST($testcase_pp, $desc_pp, $want);
186 TEST($testcase, $desc, $want_xs);
195 $b = {}; # FIXME - use another variable name
196 $a = [1, $b, $c]; # FIXME - use another variable name
219 TEST_BOTH(q(Data::Dumper->Dumpxs([$a,$b,$c], [qw(a b), 6])),
220 'basic test with names: Dumpxs()',
224 local $Data::Dumper::Sparseseen = 1;
225 TEST_BOTH(q(Data::Dumper->Dumpxs([$a,$b,$c], [qw(a b), 6])),
226 'Sparseseen with names: Dumpxs()',
250 $Data::Dumper::Purity = 1; # fill in the holes for eval
251 TEST_BOTH(q(Data::Dumper->Dumpxs([$a, $b], [qw(*a b)])),
252 'Purity: basic test with dereferenced array: Dumpxs()',
256 local $Data::Dumper::Sparseseen = 1;
257 TEST_BOTH(q(Data::Dumper->Dumpxs([$a, $b], [qw(*a b)])),
258 'Purity: Sparseseen with dereferenced array: Dumpxs()',
278 #$b{'c'} = $b{'a'}[2];
282 TEST_BOTH(q(Data::Dumper->Dumpxs([$b, $a], [qw(*b a)])),
283 'basic test with dereferenced hash: Dumpxs()',
299 #$a->[1]{'b'} = $a->[1];
305 $Data::Dumper::Indent = 1;
307 $d = Data::Dumper->new([$a,$b], [qw(a b)]);
308 $d->Seen({'*c' => $c});
310 }, 'Indent: Seen: Dumpxs()',
335 $d->Purity(0)->Quotekeys(0);
336 TEST_BOTH(q( $d->Reset; $d->Dumpxs ),
337 'Indent(3): Purity(0)->Quotekeys(0): Dumpxs()',
354 #$VAR1->[1]{'a'} = $VAR1;
355 #$VAR1->[1]{'b'} = $VAR1->[1];
356 #$VAR1->[2] = $VAR1->[1]{'c'};
359 TEST_BOTH(q(Data::Dumper::DumperX($a)),
380 local $Data::Dumper::Purity = 0;
381 local $Data::Dumper::Quotekeys = 0;
382 local $Data::Dumper::Terse = 1;
383 TEST_BOTH(q(Data::Dumper::DumperX($a)),
384 'Purity 0: Quotekeys 0: Terse 1: DumperX',
392 # "abc\0'\efg" => "mno\0",
397 $foo = { "abc\000\'\efg" => "mno\000",
401 local $Data::Dumper::Useqq = 1;
402 TEST_BOTH(q(Data::Dumper::DumperX($foo)),
415 %foo = (a=>1,b=>\$foo,c=>\@foo);
437 #*::foo{ARRAY}->[1] = $foo;
438 #*::foo{ARRAY}->[2]{'b'} = *::foo{SCALAR};
439 #*::foo{ARRAY}->[2]{'c'} = *::foo{ARRAY};
440 #*::foo{ARRAY}->[2]{'d'} = *::foo{ARRAY}->[2];
441 #*::foo = *::foo{ARRAY}->[2];
442 #@bar = @{*::foo{ARRAY}};
443 #%baz = %{*::foo{ARRAY}->[2]};
446 $Data::Dumper::Purity = 1;
447 $Data::Dumper::Indent = 3;
448 TEST_BOTH(q(Data::Dumper->Dumpxs([\\*foo, \\@foo, \\%foo], ['*foo', '*bar', '*baz'])),
449 'Purity 1: Indent 3: Dumpxs()',
467 #*::foo{ARRAY}->[1] = $foo;
468 #*::foo{ARRAY}->[2]{'b'} = *::foo{SCALAR};
469 #*::foo{ARRAY}->[2]{'c'} = *::foo{ARRAY};
470 #*::foo{ARRAY}->[2]{'d'} = *::foo{ARRAY}->[2];
471 #*::foo = *::foo{ARRAY}->[2];
472 #$bar = *::foo{ARRAY};
473 #$baz = *::foo{ARRAY}->[2];
476 $Data::Dumper::Indent = 1;
477 TEST_BOTH(q(Data::Dumper->Dumpxs([\\*foo, \\@foo, \\%foo], ['foo', 'bar', 'baz'])),
478 'Purity 1: Indent 1: Dumpxs()',
497 #*::foo{HASH}->{'b'} = *::foo{SCALAR};
498 #*::foo{HASH}->{'c'} = \@bar;
499 #*::foo{HASH}->{'d'} = *::foo{HASH};
500 #$bar[2] = *::foo{HASH};
501 #%baz = %{*::foo{HASH}};
505 TEST_BOTH(q(Data::Dumper->Dumpxs([\\@foo, \\%foo, \\*foo], ['*bar', '*baz', '*foo'])),
506 'array|hash|glob dereferenced: Dumpxs()',
525 #*::foo{HASH}->{'b'} = *::foo{SCALAR};
526 #*::foo{HASH}->{'c'} = $bar;
527 #*::foo{HASH}->{'d'} = *::foo{HASH};
528 #$bar->[2] = *::foo{HASH};
529 #$baz = *::foo{HASH};
533 TEST_BOTH(q(Data::Dumper->Dumpxs([\\@foo, \\%foo, \\*foo], ['bar', 'baz', 'foo'])),
534 'array|hash|glob: not dereferenced: Dumpxs()',
554 $Data::Dumper::Purity = 0;
555 $Data::Dumper::Quotekeys = 0;
556 TEST_BOTH(q(Data::Dumper->Dumpxs([\\*foo, \\@foo, \\%foo], ['*foo', '*bar', '*baz'])),
557 'Purity 0: Quotekeys 0: dereferenced: Dumpxs',
577 TEST_BOTH(q(Data::Dumper->Dumpxs([\\*foo, \\@foo, \\%foo], ['foo', 'bar', 'baz'])),
578 'Purity 0: Quotekeys 0: not dereferenced: Dumpxs()',
587 @dogs = ( 'Fido', 'Wags' );
594 $mutts = $mutts; # avoid warning
604 # ${$kennels{First}},
605 # ${$kennels{Second}},
612 $d = Data::Dumper->new([\\%kennel, \\@dogs, $mutts],
613 [qw(*kennels *dogs *mutts)] );
615 }, 'constructor: hash|array|scalar: Dumpxs()',
621 #%kennels = %kennels;
626 TEST_BOTH(q($d->Dumpxs),
627 'object call: Dumpxs',
638 # ${$kennels{First}},
639 # ${$kennels{Second}},
645 TEST_BOTH(q($d->Reset; $d->Dumpxs),
646 'Reset and Dumpxs separate calls',
656 # First => \$dogs[0],
657 # Second => \$dogs[1]
660 #%kennels = %{$dogs[2]};
661 #%mutts = %{$dogs[2]};
665 $d = Data::Dumper->new([\\@dogs, \\%kennel, $mutts],
666 [qw(*dogs *kennels *mutts)] );
668 }, 'constructor: array|hash|scalar: Dumpxs()',
673 TEST_BOTH(q($d->Reset->Dumpxs),
674 'Reset Dumpxs chained',
695 $d = Data::Dumper->new( [\@dogs, \%kennel], [qw(*dogs *kennels)] );
696 $d->Deepcopy(1)->Dumpxs;
697 }, 'Deepcopy(1): Dumpxs',
703 sub z { print "foo\n" }
715 TEST_BOTH(q(Data::Dumper->new([\&z,$c],['a','c'])->Seen({'b' => \&z})->Dumpxs;),
716 'Seen: scalar: Dumpxs',
728 TEST_BOTH(q(Data::Dumper->new([\&z,$c],['a','c'])->Seen({'*b' => \&z})->Dumpxs;),
729 'Seen: glob: Dumpxs',
741 TEST_BOTH(q(Data::Dumper->new([\&z,$c],['*a','*c'])->Seen({'*b' => \&z})->Dumpxs;),
742 'Seen: glob: derference: Dumpxs',
760 TEST_BOTH(q(Data::Dumper->new([$a],['*a'])->Purity(1)->Dumpxs;),
761 'Purity(1): dereference: Dumpxs',
776 TEST_BOTH(q(Data::Dumper->new([$a,$b],['a','b'])->Purity(1)->Dumpxs;),
777 'Purity(1): not dereferenced: Dumpxs',
782 $a = [{ a => \$b }, { b => undef }];
783 $b = [{ c => \$b }, { d => \$a }];
803 #${$a->[0]{a}}->[0]->{c} = $a->[0]{a};
804 #${${$a->[0]{a}}->[1]->{d}} = $a;
808 TEST_BOTH(q(Data::Dumper->new([$a,$b],['a','b'])->Purity(1)->Dumpxs;),
809 'Purity(1); Dumpxs again',
814 $a = [[[[\\\\\'foo']]]];
831 #$c = ${${$a->[0][0][0][0]}};
834 TEST_BOTH(q(Data::Dumper->new([$a,$b,$c],['a','b','c'])->Purity(1)->Dumpxs;),
835 'Purity(1): Dumpxs: 3 elements',
844 $b = { 'c' => $c }; # FIXME use different variable name
845 $a = { 'b' => $b }; # FIXME use different variable name
854 # e => 'ARRAY(0xdeadbeef)'
863 TEST_BOTH(q(Data::Dumper->new([$a,$b,$c],['a','b','c'])->Maxdepth(4)->Dumpxs;),
864 'Maxdepth(4): Dumpxs()',
871 # b => 'HASH(0xdeadbeef)'
879 TEST_BOTH(q(Data::Dumper->new([$a,$b,$c],['a','b','c'])->Maxdepth(1)->Dumpxs;),
880 'Maxdepth(1): Dumpxs()',
896 TEST_BOTH(q(Data::Dumper->new([$b],['b'])->Purity(0)->Dumpxs;),
897 'Purity(0): Dumpxs()',
906 #${$b->[0]} = $b->[0];
909 TEST_BOTH(q(Data::Dumper->new([$b],['b'])->Purity(1)->Dumpxs;),
917 ## XS code was adding an extra \0
922 TEST_BOTH(q(Data::Dumper->Dumpxs([$a], ['a'])),
929 $a = { map { ("$_$_$_", ++$i) } 'I'..'Q' }; # FIXME use different variable name
947 TEST_BOTH(q(Data::Dumper->new([$a])->Dumpxs;),
948 'basic test without names: Dumpxs()',
954 $c = { map { (++$i, "$_$_$_") } 'I'..'Q' };
955 local $Data::Dumper::Sortkeys = \&sort199;
958 return [ sort { $b <=> $a } keys %$hash ];
977 TEST_BOTH(q(Data::Dumper->new([$c])->Dumpxs;),
984 $c = { map { (++$i, "$_$_$_") } 'I'..'Q' };
985 $d = { reverse %$c };
986 local $Data::Dumper::Sortkeys = \&sort205;
990 $hash eq $c ? (sort { $a <=> $b } keys %$hash)
991 : (reverse sort keys %$hash)
1024 # the XS code does number values as strings
1025 my $want_xs = $want;
1026 $want_xs =~ s/ (\d+)(,?)$/ '$1'$2/gm;
1027 TEST_BOTH(q(Data::Dumper->new([[$c, $d]])->Dumpxs;),
1028 "more sortkeys sub",
1033 local $Data::Dumper::Deparse = 1;
1034 local $Data::Dumper::Indent = 2;
1047 if(" $Config{'extensions'} " !~ m[ B ]) {
1048 SKIP_BOTH("Perl configured without B module");
1050 TEST_BOTH(q(Data::Dumper->new([{ foo => sub { print "foo"; } }])->Dumpxs),
1051 'Deparse 1: Indent 2; Dumpxs()',
1060 # The controls (bare numbers) are stored either as integers or floating point.
1061 # [depending on whether the tokeniser sees things like ".".]
1062 # The peephole optimiser only runs for constant folding, not single constants,
1063 # so I already have some NVs, some IVs
1064 # The string versions are not. They are all PV
1066 # This is arguably all far too chummy with the implementation, but I really
1067 # want to ensure that we don't go wrong when flags on scalars get as side
1068 # effects of reading them.
1070 # These tests are actually testing the precise output of the current
1071 # implementation, so will most likely fail if the implementation changes,
1072 # even if the new implementation produces different but correct results.
1073 # It would be nice to test for wrong answers, but I can't see how to do that,
1074 # so instead I'm checking for unexpected answers. (ie -2 becoming "-2" is not
1075 # wrong, but I can't see an easy, reliable way to code that knowledge)
1078 # Numbers (seen by the tokeniser as numbers, stored as numbers.
1080 0, +1, -2, 3.0, +4.0, -5.0, 6.5, +7.5, -8.5,
1081 9, +10, -11, 12.0, +13.0, -14.0, 15.5, +16.25, -17.75,
1085 "0", "+1", "-2", "3.0", "+4.0", "-5.0", "6.5", "+7.5", "-8.5", " 9",
1086 " +10", " -11", " 12.0", " +13.0", " -14.0", " 15.5", " +16.25", " -17.75",
1089 # The perl code always does things the same way for numbers.
1090 my $WANT_PL_N = <<'EOT';
1110 # The perl code knows that 0 and -2 stringify exactly back to the strings,
1111 # so it dumps them as numbers, not strings.
1112 my $WANT_PL_S = <<'EOT';
1129 #$VAR17 = ' +16.25';
1130 #$VAR18 = ' -17.75';
1133 # The XS code differs.
1134 # These are the numbers as seen by the tokeniser. Constants aren't folded
1135 # (which makes IVs where possible) so values the tokeniser thought were
1136 # floating point are stored as NVs. The XS code outputs these as strings,
1137 # but as it has converted them from NVs, leading + signs will not be there.
1138 my $WANT_XS_N = <<'EOT';
1159 # These are the strings as seen by the tokeniser. The XS code will output
1160 # these for all cases except where the scalar has been used in integer context
1161 my $WANT_XS_S = <<'EOT';
1178 #$VAR17 = ' +16.25';
1179 #$VAR18 = ' -17.75';
1182 # These are the numbers as IV-ized by &
1183 # These will differ from WANT_XS_N because now IV flags will be set on all
1184 # values that were actually integer, and the XS code will then output these
1185 # as numbers not strings.
1186 my $WANT_XS_I = <<'EOT';
1207 # Some of these tests will be redundant.
1208 @numbers_s = @numbers_i = @numbers_is = @numbers_n = @numbers_ns
1209 = @numbers_ni = @numbers_nis = @numbers;
1210 @strings_s = @strings_i = @strings_is = @strings_n = @strings_ns
1211 = @strings_ni = @strings_nis = @strings;
1212 # Use them in an integer context
1213 foreach (@numbers_i, @numbers_ni, @numbers_nis, @numbers_is,
1214 @strings_i, @strings_ni, @strings_nis, @strings_is) {
1215 my $b = sprintf "%d", $_;
1217 # Use them in a floating point context
1218 foreach (@numbers_n, @numbers_ni, @numbers_nis, @numbers_ns,
1219 @strings_n, @strings_ni, @strings_nis, @strings_ns) {
1220 my $b = sprintf "%e", $_;
1222 # Use them in a string context
1223 foreach (@numbers_s, @numbers_is, @numbers_nis, @numbers_ns,
1224 @strings_s, @strings_is, @strings_nis, @strings_ns) {
1225 my $b = sprintf "%s", $_;
1228 # use Devel::Peek; Dump ($_) foreach @vanilla_c;
1230 my $nv_preserves_uv_4bits = defined $Config{d_nv_preserves_uv}
1231 || (exists($Config{nv_preserves_uv_bits}) && $Config{nv_preserves_uv_bits} >= 4);
1233 TEST_BOTH(q(Data::Dumper->new(\@numbers)->Dumpxs),
1235 $WANT_PL_N, $WANT_XS_N);
1236 TEST_BOTH(q(Data::Dumper->new(\@numbers_s)->Dumpxs),
1238 $WANT_PL_N, $WANT_XS_N);
1239 TEST_BOTH(q(Data::Dumper->new(\@numbers_i)->Dumpxs),
1241 $WANT_PL_N, $WANT_XS_I,
1242 $nv_preserves_uv_4bits ? "" : "NV does not preserve 4bits");
1243 TEST_BOTH(q(Data::Dumper->new(\@numbers_is)->Dumpxs),
1245 $WANT_PL_N, $WANT_XS_I,
1246 $nv_preserves_uv_4bits ? "" : "NV does not preserve 4bits");
1247 TEST_BOTH(q(Data::Dumper->new(\@numbers_n)->Dumpxs),
1249 $WANT_PL_N, $WANT_XS_N);
1250 TEST_BOTH(q(Data::Dumper->new(\@numbers_ns)->Dumpxs),
1252 $WANT_PL_N, $WANT_XS_N);
1253 TEST_BOTH(q(Data::Dumper->new(\@numbers_ni)->Dumpxs),
1255 $WANT_PL_N, $WANT_XS_I,
1256 $nv_preserves_uv_4bits ? "" : "NV does not preserve 4bits");
1257 TEST_BOTH(q(Data::Dumper->new(\@numbers_nis)->Dumpxs),
1259 $WANT_PL_N, $WANT_XS_I,
1260 $nv_preserves_uv_4bits ? "" : "NV does not preserve 4bits");
1262 TEST_BOTH(q(Data::Dumper->new(\@strings)->Dumpxs),
1264 $WANT_PL_S, $WANT_XS_S);
1265 TEST_BOTH(q(Data::Dumper->new(\@strings_s)->Dumpxs),
1267 $WANT_PL_S, $WANT_XS_S);
1268 # This one used to really mess up. New code actually emulates the .pm code
1269 TEST_BOTH(q(Data::Dumper->new(\@strings_i)->Dumpxs),
1272 TEST_BOTH(q(Data::Dumper->new(\@strings_is)->Dumpxs),
1275 TEST_BOTH(q(Data::Dumper->new(\@strings_n)->Dumpxs),
1277 $WANT_PL_S, $WANT_XS_S,
1278 $nv_preserves_uv_4bits ? "" : "NV does not preserve 4bits");
1279 TEST_BOTH(q(Data::Dumper->new(\@strings_ns)->Dumpxs),
1281 $WANT_PL_S, $WANT_XS_S,
1282 $nv_preserves_uv_4bits ? "" : "NV does not preserve 4bits");
1283 # This one used to really mess up. New code actually emulates the .pm code
1284 TEST_BOTH(q(Data::Dumper->new(\@strings_ni)->Dumpxs),
1287 TEST_BOTH(q(Data::Dumper->new(\@strings_nis)->Dumpxs),
1295 ## Perl code was using /...$/ and hence missing the \n.
1301 # Can't pad with # as the output has an embedded newline.
1302 local $Data::Dumper::Pad = "my ";
1303 TEST_BOTH(q(Data::Dumper->Dumpxs(["42\n"])),
1304 "number with trailing newline",
1324 ## Perl code flips over at 10 digits.
1327 #$VAR2 = '1000000000';
1328 #$VAR3 = '9999999999';
1329 #$VAR4 = '10000000000';
1330 #$VAR5 = -999999999;
1331 #$VAR6 = '-1000000000';
1332 #$VAR7 = '-9999999999';
1333 #$VAR8 = '-10000000000';
1334 #$VAR9 = '4294967295';
1335 #$VAR10 = '4294967296';
1336 #$VAR11 = '-2147483648';
1337 #$VAR12 = '-2147483649';
1340 ## XS code flips over at 11 characters ("-" is a char) or larger than int.
1341 my $want_xs = ~0 == 0xFFFFFFFF ? << 'EOT32' : << 'EOT64';
1343 #$VAR2 = 1000000000;
1344 #$VAR3 = '9999999999';
1345 #$VAR4 = '10000000000';
1346 #$VAR5 = -999999999;
1347 #$VAR6 = '-1000000000';
1348 #$VAR7 = '-9999999999';
1349 #$VAR8 = '-10000000000';
1350 #$VAR9 = 4294967295;
1351 #$VAR10 = '4294967296';
1352 #$VAR11 = '-2147483648';
1353 #$VAR12 = '-2147483649';
1356 #$VAR2 = 1000000000;
1357 #$VAR3 = 9999999999;
1358 #$VAR4 = '10000000000';
1359 #$VAR5 = -999999999;
1360 #$VAR6 = '-1000000000';
1361 #$VAR7 = '-9999999999';
1362 #$VAR8 = '-10000000000';
1363 #$VAR9 = 4294967295;
1364 #$VAR10 = 4294967296;
1365 #$VAR11 = '-2147483648';
1366 #$VAR12 = '-2147483649';
1369 TEST_BOTH(q(Data::Dumper->Dumpxs(\@a)),
1375 $b = "Bad. XS didn't escape dollar sign";
1377 # B6 is chosen because it is UTF-8 variant on ASCII and all 3 EBCDIC
1378 # platforms that Perl currently purports to work on. It also is the only
1379 # such code point that has the same meaning on all 4, the paragraph sign.
1380 my $want = <<"EOT"; # Careful. This is '' string written inside "" here doc
1381 #\$VAR1 = '\$b\"\@\\\\\xB6';
1384 $a = "\$b\"\@\\\xB6\x{100}";
1386 my $want_xs = <<'EOT'; # While this is "" string written inside "" here doc
1387 #$VAR1 = "\$b\"\@\\\x{b6}";
1389 TEST_BOTH(q(Data::Dumper->Dumpxs([$a])),
1390 "XS utf8 flag with \" and \$",
1393 # XS used to produce "$b\"' which is 4 chars, not 3. [ie wrongly qq(\$b\\\")]
1399 $a = "\$b\"\x{100}";
1401 TEST_BOTH(q(Data::Dumper->Dumpxs([$a])),
1402 "XS utf8 flag with \" and \$",
1406 # XS used to produce 'D'oh!' which is well, D'oh!
1407 # Andreas found this one, which in turn discovered the previous two.
1413 $a = "D'oh!\x{100}";
1415 TEST_BOTH(q(Data::Dumper->Dumpxs([$a])),
1416 "XS utf8 flag with '",
1420 # Jarkko found that -Mutf8 caused some tests to fail. Turns out that there
1421 # was an otherwise untested code path in the XS for utf8 hash keys with purity
1429 # "\x{decaf}\x{decaf}\x{decaf}\x{decaf}" => do{my $o}
1431 #*::ping{HASH}->{"\x{decaf}\x{decaf}\x{decaf}\x{decaf}"} = *::ping{SCALAR};
1432 #%pong = %{*::ping{HASH}};
1434 local $Data::Dumper::Purity = 1;
1435 local $Data::Dumper::Sortkeys;
1437 %ping = (chr (0xDECAF) x 4 =>\$ping);
1438 for $Data::Dumper::Sortkeys (0, 1) {
1439 TEST_BOTH(q(Data::Dumper->Dumpxs([\\*ping, \\%ping], ['*ping', '*pong'])),
1440 "utf8: Purity 1: Sortkeys: Dumpxs()",
1445 # XS for quotekeys==0 was not being defensive enough against utf8 flagged
1454 local $Data::Dumper::Quotekeys = 0;
1455 my $k = 'perl' . chr 256;
1457 %foo = ($k => 'rocks');
1459 TEST_BOTH(q(Data::Dumper->Dumpxs([\\%foo])),
1460 "quotekeys == 0 for utf8 flagged ASCII",
1474 TEST_BOTH(q(Data::Dumper->Dumpxs([\@foo])),
1475 'Richard Clamp, Message-Id: <20030104005247.GA27685@mirth.demon.co.uk>: Dumpxs()',
1480 # Make sure $obj->Dumpxs returns the right thing in list context. This was
1481 # broken by the initial attempt to fix [perl #74170].
1486 TEST_BOTH(q(join " ", new Data::Dumper [[]],[] =>->Dumpxs),
1487 '$obj->Dumpxs in list context',
1493 my $want = '\0\1\2\3\4\5\6\a\b\t\n\13\f\r\16\17\20\21\22\23\24\25\26\27\30\31\32\e\34\35\36\37 !\"#\$%&\'()*+,-./0123456789:;<=>?\@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377';
1494 $want = convert_to_native($want);
1501 $foo = [ join "", map chr, 0..255 ];
1502 local $Data::Dumper::Useqq = 1;
1503 TEST_BOTH(q(Data::Dumper::DumperX($foo)),
1504 'All latin1 characters: DumperX',
1510 my $want = '\0\1\2\3\4\5\6\a\b\t\n\13\f\r\16\17\20\21\22\23\24\25\26\27\30\31\32\e\34\35\36\37 !\"#\$%&\'()*+,-./0123456789:;<=>?\@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\177\x{80}\x{81}\x{82}\x{83}\x{84}\x{85}\x{86}\x{87}\x{88}\x{89}\x{8a}\x{8b}\x{8c}\x{8d}\x{8e}\x{8f}\x{90}\x{91}\x{92}\x{93}\x{94}\x{95}\x{96}\x{97}\x{98}\x{99}\x{9a}\x{9b}\x{9c}\x{9d}\x{9e}\x{9f}\x{a0}\x{a1}\x{a2}\x{a3}\x{a4}\x{a5}\x{a6}\x{a7}\x{a8}\x{a9}\x{aa}\x{ab}\x{ac}\x{ad}\x{ae}\x{af}\x{b0}\x{b1}\x{b2}\x{b3}\x{b4}\x{b5}\x{b6}\x{b7}\x{b8}\x{b9}\x{ba}\x{bb}\x{bc}\x{bd}\x{be}\x{bf}\x{c0}\x{c1}\x{c2}\x{c3}\x{c4}\x{c5}\x{c6}\x{c7}\x{c8}\x{c9}\x{ca}\x{cb}\x{cc}\x{cd}\x{ce}\x{cf}\x{d0}\x{d1}\x{d2}\x{d3}\x{d4}\x{d5}\x{d6}\x{d7}\x{d8}\x{d9}\x{da}\x{db}\x{dc}\x{dd}\x{de}\x{df}\x{e0}\x{e1}\x{e2}\x{e3}\x{e4}\x{e5}\x{e6}\x{e7}\x{e8}\x{e9}\x{ea}\x{eb}\x{ec}\x{ed}\x{ee}\x{ef}\x{f0}\x{f1}\x{f2}\x{f3}\x{f4}\x{f5}\x{f6}\x{f7}\x{f8}\x{f9}\x{fa}\x{fb}\x{fc}\x{fd}\x{fe}\x{ff}\x{20ac}';
1511 $want = convert_to_native($want);
1518 $foo = [ join "", map chr, 0..255, 0x20ac ];
1519 local $Data::Dumper::Useqq = 1;
1520 TEST_BOTH(q(Data::Dumper::DumperX($foo)),
1521 'All latin1 characters with utf8 flag including a wide character: DumperX',
1527 if (!Data::Dumper::SUPPORTS_CORE_BOOLS) {
1528 SKIP_BOTH("Core booleans not supported on older perls");
1538 $foo = [ !!1, !!0 ];
1539 TEST_BOTH(q(Data::Dumper::DumperX($foo)),
1547 # If XS cannot load, the pure-Perl version cannot deparse vstrings with
1548 # underscores properly.
1549 # Says the original comment. However, the story is more complex than that.
1550 # 1) If *all* XS cannot load, Data::Dumper fails hard, because it needs
1552 # 2) However, if Data::Dumper's XS cannot load, then Data::Dumper uses the
1553 # "Pure Perl" implementation, which uses C<sprintf "%vd", $val> and the
1554 # comment above applies.
1555 # 3) However, if we "just" set $Data::Dumper::Useperl true, then Dump *calls*
1556 # the "Pure Perl" (general) implementation, but that calls a helper in the
1557 # XS code (&_vstring) and it *does* deparse these vstrings properly
1558 # Meaning that for case 3, what we actually *test*, we get "VSTRINGS_CORRECT"
1559 # The "problem" comes that if one deletes Dumper.so and re-tests, it's case 2
1560 # and this test will fail, because case 2 output is:
1567 # This is the test output removed by commit 55d1a9a4aa623c18 in Aug 2012:
1568 # Data::Dumper: Fix tests for pure-Perl implementation
1570 # Father Chrysostomos fixed vstring handling in both XS and pure-Perl
1571 # implementations of Data::Dumper in
1572 # de5ef703c7d8db6517e7d56d9c018d3ad03f210e.
1574 # He also updated the tests for the default XS implementation, but it seems
1575 # that he missed the test changes necessary for the pure-Perl implementation
1576 # which now also does the right thing.
1578 # (But the relevant previous commit is not de5ef703c7d8 but d036e907fea3)
1579 # Part of the confusion here comes because at commit d036e907fea3 it was *not*
1580 # possible to remove Dumper.so and have Data::Dumper load - that bug was fixed
1581 # later (commit 1e9285c2ad54ae39, Dec 2011)
1583 # Sigh, but even the test output added in d036e907fea3 was not correct
1584 # at least not consistent, as it had \v65.66.67, but the code at the time
1585 # generated \65.66.77 (no v). Now fixed.
1586 my $ABC_native = chr(65) . chr(66) . chr(67);
1587 my $want = $XS ? <<"VSTRINGS_CORRECT" : <<"NO_vstring_HELPER";
1589 #\$b = \\v65.66.067;
1590 #\$c = \\v65.66.6_7;
1591 #\$d = \\'$ABC_native';
1596 #\$d = \\'$ABC_native';
1601 \(eval 'v65.66.067'),
1606 TEST_BOTH(q(Data::Dumper->Dumpxs(\@::_v, [qw(a b c d)])),
1610 else { # Skip tests before 5.10. vstrings considered funny before
1611 SKIP_BOTH("vstrings considered funny before 5.10.0");
1617 # [perl #107372] blessed overloaded globs
1619 #$VAR1 = bless( \*::finkle, 'overtest' );
1623 use overload fallback=>1, q\""\=>sub{"oaoaa"};
1625 TEST_BOTH(q(Data::Dumper->Dumpxs([bless \*finkle, "overtest"])),
1626 'blessed overloaded globs',
1631 # [perl #74798] uncovered behaviour
1635 local $Data::Dumper::Useqq = 1;
1636 TEST_BOTH(q(Data::Dumper->Dumpxs(["\x000"])),
1637 "\\ octal followed by digit",
1641 #$VAR1 = "\x{100}\0000";
1643 local $Data::Dumper::Useqq = 1;
1644 TEST_BOTH(q(Data::Dumper->Dumpxs(["\x{100}\x000"])),
1645 "\\ octal followed by digit unicode",
1649 #$VAR1 = "\0\x{660}";
1651 TEST_BOTH(q(Data::Dumper->Dumpxs(["\\x00\\x{0660}"])),
1652 "\\ octal followed by unicode digit",
1655 # [perl #118933 - handling of digits
1663 #$VAR7 = "1234567890";
1665 TEST_BOTH(q(Data::Dumper->Dumpxs([0, 1, 90, -10, "010", "112345678", "1234567890" ])),
1666 "numbers and number-like scalars",
1671 # [github #18614 - handling of Unicode characters in regexes]
1672 # [github #18764 - ... without breaking subsequent Latin-1]
1673 if ($] lt '5.010') {
1674 SKIP_BOTH("Incomplete support for UTF-8 in old perls");
1686 if ($] lt '5.010001') {
1687 $want =~ s!qr/!qr/(?-xism:!g;
1688 $want =~ s!/,!)/,!g;
1690 elsif ($] gt '5.014') {
1691 $want =~ s{/(,?)$}{/u$1}mg;
1693 my $want_xs = $want;
1694 $want_xs =~ s/'\xb6'/"\\x{b6}"/;
1695 $want_xs =~ s<([[:^ascii:]])> <sprintf '\\x{%x}', ord $1>ge;
1696 TEST_BOTH(qq(Data::Dumper->Dumpxs([ [qq/\x{41f}/, qr/\x{8b80}/, qr/\x{41f}/, qr/\x{b6}/, "\xb6"] ])),
1697 "string with Unicode + regexp with Unicode",
1702 # [more perl #58608 tests]
1713 # qr/ $bs$bs$bs\\/ /
1716 if ($] lt '5.010001') {
1717 $want =~ s!qr/!qr/(?-xism:!g;
1718 $want =~ s! /! )/!g;
1720 TEST_BOTH(qq(Data::Dumper->Dumpxs([ [qr! / !, qr! \\?/ !, qr! $bs/ !, qr! $bs:/ !, qr! \\?$bs:/ !, qr! $bs$bs/ !, qr! $bs$bs:/ !, qr! $bs$bs$bs/ !, ] ])),
1726 # [github #18614, github #18764, perl #58608 corner cases]
1727 if ($] lt '5.010') {
1728 SKIP_BOTH("Incomplete support for UTF-8 in old perls");
1735 # qr/ \x{203d}\\/ /,
1736 # qr/ \\\x{203d}\\/ /,
1737 # qr/ \\\x{203d}$bs:\\/ /,
1741 if ($] lt '5.010001') {
1742 $want =~ s!qr/!qr/(?-xism:!g;
1743 $want =~ s!/,!)/,!g;
1745 elsif ($] gt '5.014') {
1746 $want =~ s{/(,?)$}{/u$1}mg;
1748 my $want_xs = $want;
1749 $want_xs =~ s/'\x{B6}'/"\\x{b6}"/;
1750 $want_xs =~ s/\x{203D}/\\x{203d}/g;
1751 TEST_BOTH(qq(Data::Dumper->Dumpxs([ [ '\x{2e18}', qr! \x{203d}/ !, qr! \\\x{203d}/ !, qr! \\\x{203d}$bs:/ !, "\xb6"] ])),
1752 "github #18614, github #18764, perl #58608 corner cases",
1758 my $dollar = '${\q($)}';
1766 # qr/$dollar \x{B6} /u,
1767 # qr/$dollar \x{203d} /u,
1768 # qr/\\\$ \x{203d} /u,
1769 # qr/\\\\$dollar \x{203d} /u,
1770 # qr/ \$| \x{203d} /u,
1771 # qr/ (\$) \x{203d} /u,
1775 if ($] lt '5.014') {
1776 $want =~ s{/u,$}{/,}mg;
1778 if ($] lt '5.010001') {
1779 $want =~ s!qr/!qr/(?-xism:!g;
1780 $want =~ s!/,!)/,!g;
1782 my $want_xs = $want;
1783 $want_xs =~ s/'\x{B6}'/"\\x{b6}"/;
1784 $want_xs =~ s/\x{B6}/\\x{b6}/;
1785 $want_xs =~ s/\x{203D}/\\x{203d}/g;
1787 Data::Dumper->Dumpxs([ [
1796 qr'\\\\\$ \x{203d} ',
1798 qr/ (\$) \x{203d} /,
1802 TEST_BOTH($have, "CPAN #84569", $want, $want_xs);
1807 # re::regexp_pattern was moved to universal.c in v5.10.0-252-g192c1e2
1808 # and apparently backported to maint-5.10
1809 my $want = $] > 5.010 ? <<'NEW' : <<'OLD';
1813 #$VAR1 = qr/(?-xism:abc)/;
1814 #$VAR2 = qr/(?i-xsm:abc)/;
1816 TEST_BOTH(q(Data::Dumper->Dumpxs([ qr/abc/, qr/abc/i ])), "qr// xs", $want);
1823 #*a = sub { "DUMMY" };
1827 TEST_BOTH(q(Data::Dumper->new([ \&foo, \\&foo ], [ "*a", "b" ])->Dumpxs),
1828 "name of code in *foo",
1831 ############# [perl #124091]
1836 local $Data::Dumper::Useqq = 1;
1837 TEST_BOTH(qq(Data::Dumper::DumperX("\n")),
1844 @globs = map { $_, \$_ } map { *$_ } map { $_, "s::$_" }
1845 "foo", "\1bar", "L\x{e9}on", "m\x{100}cron", "snow\x{2603}";
1849 my $want = change_glob_expectation(<<'EOT');
1863 # *{"::m\x{100}cron"},
1864 # \*{"::m\x{100}cron"},
1865 # *{"s::m\x{100}cron"},
1866 # \*{"s::m\x{100}cron"},
1867 # *{"::snow\x{2603}"},
1868 # \*{"::snow\x{2603}"},
1869 # *{"s::snow\x{2603}"},
1870 # \*{"s::snow\x{2603}"}
1873 local $Data::Dumper::Useqq = 1;
1874 if (ord("A") == 65) {
1875 TEST_BOTH(q(Data::Dumper->Dumpxs([\@globs], ["globs"])), 'globs: Dumpxs()',
1879 SKIP_BOTH("ASCII-dependent test");
1884 my $want = change_glob_expectation(<<'EOT');
1888 # c => \*{"::a\x{2603}b"}
1896 #*{"::a\x{2603}b"} = {
1903 *{"a/b"} = { b => 3 };
1904 *{"a\x{2603}b"} = { c => 5 };
1905 $v = { a => \*ppp, b => \*{"a/b"}, c => \*{"a\x{2603}b"} };
1907 local $Data::Dumper::Purity = 1;
1908 TEST_BOTH(q(Data::Dumper->Dumpxs([$v], ["v"])),
1909 'glob purity: Dumpxs()',
1912 local $Data::Dumper::Useqq = 1;
1913 TEST_BOTH(q(Data::Dumper->Dumpxs([$v], ["v"])),
1914 'glob purity, useqq: Dumpxs()',
1926 use overload '""' => sub { return "bang" };
1932 # 4.5/1.5 generates the *NV* 3.0, which doesn't set SVf_POK true in 5.20.0+
1933 # overloaded strings never set SVf_POK true
1934 TEST_BOTH(q(Data::Dumper->Dumpxs([{}, []], [4.5/1.5, fish->new()])),
1935 'names that are not simple strings: Dumpxs()',