diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2009-10-12 18:30:29 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2009-10-12 18:30:29 +0000 |
commit | 9ee81f49d98a3a8c104e555916192c1eaf02f94f (patch) | |
tree | 0676e661fc136118c1c61ffe747bbb6941687440 /gnu/usr.bin/perl/t/op | |
parent | 7bed5fce775e8466f8c0c970eaeb5071d8a7718c (diff) |
Merge in perl 5.10.1; part two
Diffstat (limited to 'gnu/usr.bin/perl/t/op')
34 files changed, 5256 insertions, 4552 deletions
diff --git a/gnu/usr.bin/perl/t/op/bop.t b/gnu/usr.bin/perl/t/op/bop.t index 7e8a0c7aa21..b7f82eefc5f 100644 --- a/gnu/usr.bin/perl/t/op/bop.t +++ b/gnu/usr.bin/perl/t/op/bop.t @@ -15,7 +15,7 @@ BEGIN { # If you find tests are failing, please try adding names to tests to track # down where the failure is, and supply your new names as a patch. # (Just-in-time test naming) -plan tests => 161; +plan tests => 161 + (10*13*2) + 4; # numerics ok ((0xdead & 0xbeef) == 0x9ead); @@ -428,3 +428,105 @@ SKIP: { my $ref = "\x{10000}\0"; is(~~$str, $ref); } + +# ref tests + +my %res; + +for my $str ("x", "\x{100}") { + for my $chr (qw/S A H G X ( * F/) { + for my $op (qw/| & ^/) { + my $co = ord $chr; + my $so = ord $str; + $res{"$chr$op$str"} = eval qq/chr($co $op $so)/; + } + } + $res{"undef|$str"} = $str; + $res{"undef&$str"} = ""; + $res{"undef^$str"} = $str; +} + +sub PVBM () { "X" } +index "foo", PVBM; + +my $warn = 0; +local $^W = 1; +local $SIG{__WARN__} = sub { $warn++ }; + +sub is_first { + my ($got, $orig, $op, $str, $name) = @_; + is(substr($got, 0, 1), $res{"$orig$op$str"}, $name); +} + +for ( + # [object to test, first char of stringification, name] + [undef, "undef", "undef" ], + [\1, "S", "scalar ref" ], + [[], "A", "array ref" ], + [{}, "H", "hash ref" ], + [qr/x/, "(", "qr//" ], + [*foo, "*", "glob" ], + [\*foo, "G", "glob ref" ], + [PVBM, "X", "PVBM" ], + [\PVBM, "S", "PVBM ref" ], + [bless([], "Foo"), "F", "object" ], +) { + my ($val, $orig, $type) = @$_; + + for (["x", "string"], ["\x{100}", "utf8"]) { + my ($str, $desc) = @$_; + + $warn = 0; + + is_first($val | $str, $orig, "|", $str, "$type | $desc"); + is_first($val & $str, $orig, "&", $str, "$type & $desc"); + is_first($val ^ $str, $orig, "^", $str, "$type ^ $desc"); + + is_first($str | $val, $orig, "|", $str, "$desc | $type"); + is_first($str & $val, $orig, "&", $str, "$desc & $type"); + is_first($str ^ $val, $orig, "^", $str, "$desc ^ $type"); + + my $new; + ($new = $val) |= $str; + is_first($new, $orig, "|", $str, "$type |= $desc"); + ($new = $val) &= $str; + is_first($new, $orig, "&", $str, "$type &= $desc"); + ($new = $val) ^= $str; + is_first($new, $orig, "^", $str, "$type ^= $desc"); + + ($new = $str) |= $val; + is_first($new, $orig, "|", $str, "$desc |= $type"); + ($new = $str) &= $val; + is_first($new, $orig, "&", $str, "$desc &= $type"); + ($new = $str) ^= $val; + is_first($new, $orig, "^", $str, "$desc ^= $type"); + + if ($orig eq "undef") { + # undef |= and undef ^= don't warn + is($warn, 10, "no duplicate warnings"); + } + else { + is($warn, 0, "no warnings"); + } + } +} + +my $strval; + +{ + package Bar; + use overload q/""/ => sub { $strval }; + + package Baz; + use overload q/|/ => sub { "y" }; +} + +ok(!eval { bless([], "Bar") | "x"; 1 }, "string overload can't use |"); +like($@, qr/no method found/, "correct error"); +is(eval { bless([], "Baz") | "x" }, "y", "| overload works"); + +my $obj = bless [], "Bar"; +$strval = "x"; +eval { $obj |= "Q" }; +$strval = "z"; +is("$obj", "z", "|= doesn't break string overload"); diff --git a/gnu/usr.bin/perl/t/op/closure.t b/gnu/usr.bin/perl/t/op/closure.t index 7d8df6a2cc4..5e3bf455911 100644 --- a/gnu/usr.bin/perl/t/op/closure.t +++ b/gnu/usr.bin/perl/t/op/closure.t @@ -14,7 +14,7 @@ BEGIN { use Config; require './test.pl'; # for runperl() -print "1..187\n"; +print "1..188\n"; my $test = 1; sub test (&) { @@ -463,9 +463,8 @@ END } } else { # No fork(). Do it the hard way. - my $cmdfile = "tcmd$$"; $cmdfile++ while -e $cmdfile; - my $errfile = "terr$$"; $errfile++ while -e $errfile; - my @tmpfiles = ($cmdfile, $errfile); + my $cmdfile = tempfile(); + my $errfile = tempfile(); open CMD, ">$cmdfile"; print CMD $code; close CMD; my $cmd = which_perl(); $cmd .= " -w $cmdfile 2>$errfile"; @@ -477,18 +476,15 @@ END { local $/; $output = join '', <PERL> } close PERL; } else { - my $outfile = "tout$$"; $outfile++ while -e $outfile; - push @tmpfiles, $outfile; + my $outfile = tempfile(); system "$cmd >$outfile"; { local $/; open IN, $outfile; $output = <IN>; close IN } } if ($?) { printf "not ok: exited with error code %04X\n", $?; - $debugging or do { 1 while unlink @tmpfiles }; exit; } { local $/; open IN, $errfile; $errors = <IN>; close IN } - 1 while unlink @tmpfiles; } print $output; print STDERR $errors; @@ -688,7 +684,22 @@ __EOF__ test { $flag == 1 }; } +# don't copy a stale lexical; crate a fresh undef one instead +sub f { + my $x if $_[0]; + sub { \$x } +} + +{ + f(1); + my $c1= f(0); + my $c2= f(0); + + my $r1 = $c1->(); + my $r2 = $c2->(); + test { $r1 != $r2 }; +} diff --git a/gnu/usr.bin/perl/t/op/eval.t b/gnu/usr.bin/perl/t/op/eval.t index 2eb9b1e9edd..071b2fa05ce 100644 --- a/gnu/usr.bin/perl/t/op/eval.t +++ b/gnu/usr.bin/perl/t/op/eval.t @@ -3,9 +3,10 @@ BEGIN { chdir 't' if -d 't'; @INC = '../lib'; + require './test.pl'; } -print "1..95\n"; +print "1..99\n"; eval 'print "ok 1\n";'; @@ -38,11 +39,12 @@ $fact = 'local($foo)=$foo; $foo <= 1 ? 1 : $foo-- * (eval $fact);'; $ans = eval $fact; if ($ans == 120) {print "ok 9\n";} else {print "not ok 9 $ans\n";} -open(try,'>Op.eval'); -print try 'print "ok 10\n"; unlink "Op.eval";',"\n"; +my $tempfile = tempfile(); +open(try,'>',$tempfile); +print try 'print "ok 10\n";',"\n"; close try; -do './Op.eval'; print $@; +do "./$tempfile"; print $@; # Test the singlequoted eval optimizer @@ -485,4 +487,73 @@ print "ok $test - eval and last\n"; $test++; } +# [perl #51370] eval { die "\x{a10d}" } followed by eval { 1 } did not reset +# length $@ +$@ = ""; +eval { die "\x{a10d}"; }; +$_ = length $@; +eval { 1 }; + +print "not " if ($@ ne ""); +print "ok $test # length of \$@ after eval\n"; $test++; + +print "not " if (length $@ != 0); +print "ok $test # length of \$@ after eval\n"; $test++; + +# Check if eval { 1 }; compeltly resets $@ +if (eval "use Devel::Peek; 1;") { + $tempfile = tempfile(); + $outfile = tempfile(); + open PROG, ">", $tempfile or die "Can't create test file"; + my $prog = <<'END_EVAL_TEST'; + use Devel::Peek; + $! = 0; + $@ = $!; + my $ok = 0; + open(SAVERR, ">&STDERR") or die "Can't dup STDERR: $!"; + if (open(OUT, '>', '@@@@')) { + open(STDERR, ">&OUT") or die "Can't dup OUT: $!"; + Dump($@); + print STDERR "******\n"; + eval { die "\x{a10d}"; }; + $_ = length $@; + eval { 1 }; + Dump($@); + open(STDERR, ">&SAVERR") or die "Can't restore STDERR: $!"; + close(OUT); + if (open(IN, '<', '@@@@')) { + local $/; + my $in = <IN>; + my ($first, $second) = split (/\*\*\*\*\*\*\n/, $in, 2); + $first =~ s/,pNOK//; + $ok = 1 if ($first eq $second); + } + } + + print $ok; +END_EVAL_TEST + $prog =~ s/\@\@\@\@/$outfile/g; + print PROG $prog; + close PROG; + my $ok = runperl(progfile => $tempfile); + print "not " unless $ok; + print "ok $test # eval { 1 } completly resets \$@\n"; +} +else { + print "ok $test # skipped - eval { 1 } completly resets \$@\n"; +} +$test++; + +# Test that "use feature" and other hint transmission in evals and s///ee +# don't leak memory +{ + use feature qw(:5.10); + my $count_expected = ($^H & 0x20000) ? 2 : 1; + my $t; + my $s = "a"; + $s =~ s/a/$t = \%^H; qq( qq() );/ee; + print "not " if Internals::SvREFCNT(%$t) != $count_expected; + print "ok $test - RT 63110\n"; + $test++; +} diff --git a/gnu/usr.bin/perl/t/op/exec.t b/gnu/usr.bin/perl/t/op/exec.t index c23364b29d4..91821aa08e6 100644 --- a/gnu/usr.bin/perl/t/op/exec.t +++ b/gnu/usr.bin/perl/t/op/exec.t @@ -6,6 +6,25 @@ BEGIN { require './test.pl'; } +my $vms_exit_mode = 0; + +if ($^O eq 'VMS') { + if (eval 'require VMS::Feature') { + $vms_exit_mode = !(VMS::Feature::current("posix_exit")); + } else { + my $env_unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || ''; + my $env_posix_ex = $ENV{'PERL_VMS_POSIX_EXIT'} || ''; + my $unix_rpt = $env_unix_rpt =~ /^[ET1]/i; + my $posix_ex = $env_posix_ex =~ /^[ET1]/i; + if (($unix_rpt || $posix_ex) ) { + $vms_exit_mode = 0; + } else { + $vms_exit_mode = 1; + } + } +} + + # supress VMS whinging about bad execs. use vmsish qw(hushed); @@ -85,7 +104,7 @@ is( $echo_out, "ok\n", 'piped echo emulation'); is( system(qq{$Perl -e "exit 0"}), 0, 'Explicit exit of 0' ); -my $exit_one = $Is_VMS ? 4 << 8 : 1 << 8; +my $exit_one = $vms_exit_mode ? 4 << 8 : 1 << 8; is( system(qq{$Perl "-I../lib" -e "use vmsish qw(hushed); exit 1"}), $exit_one, 'Explicit exit of 1' ); diff --git a/gnu/usr.bin/perl/t/op/fork.t b/gnu/usr.bin/perl/t/op/fork.t index 7318449a7c7..9fe8107cfa1 100644 --- a/gnu/usr.bin/perl/t/op/fork.t +++ b/gnu/usr.bin/perl/t/op/fork.t @@ -11,6 +11,7 @@ BEGIN { exit 0; } $ENV{PERL5LIB} = "../lib"; + require './test.pl'; } if ($^O eq 'mpeix') { @@ -24,9 +25,8 @@ undef $/; @prgs = split "\n########\n", <DATA>; print "1..", scalar @prgs, "\n"; -$tmpfile = "forktmp000"; -1 while -f ++$tmpfile; -END { close TEST; unlink $tmpfile if $tmpfile; } +$tmpfile = tempfile(); +END { close TEST } $CAT = (($^O eq 'MSWin32') ? '.\perl -e "print <>"' : (($^O eq 'NetWare') ? 'perl -e "print <>"' : 'cat')); @@ -54,8 +54,8 @@ for (@prgs){ } $status = $?; $results =~ s/\n+$//; - $results =~ s/at\s+forktmp\d+\s+line/at - line/g; - $results =~ s/of\s+forktmp\d+\s+aborted/of - aborted/g; + $results =~ s/at\s+$::tempfile_regexp\s+line/at - line/g; + $results =~ s/of\s+$::tempfile_regexp\s+aborted/of - aborted/g; # bison says 'parse error' instead of 'syntax error', # various yaccs may or may not capitalize 'syntax'. $results =~ s/^(syntax|parse) error/syntax error/mig; @@ -445,16 +445,14 @@ pipe(RDR,WTR) or die $!; my $pid = fork; die "fork: $!" if !defined $pid; if ($pid == 0) { - my $rand_child = rand; close RDR; - print WTR $rand_child, "\n"; + print WTR "STRING_FROM_CHILD\n"; close WTR; } else { - my $rand_parent = rand; close WTR; - chomp(my $rand_child = <RDR>); + chomp(my $string_from_child = <RDR>); close RDR; - print $rand_child ne $rand_parent, "\n"; + print $string_from_child eq "STRING_FROM_CHILD", "\n"; } EXPECT 1 diff --git a/gnu/usr.bin/perl/t/op/goto.t b/gnu/usr.bin/perl/t/op/goto.t index 9254d7c7c23..c79b424b905 100644 --- a/gnu/usr.bin/perl/t/op/goto.t +++ b/gnu/usr.bin/perl/t/op/goto.t @@ -205,7 +205,7 @@ is($ok, 1, 'goto in for(;;) with continuation'); # bug #22299 - goto in require doesn't find label -open my $f, ">goto01.pm" or die; +open my $f, ">Op_goto01.pm" or die; print $f <<'EOT'; package goto01; goto YYY; @@ -215,9 +215,9 @@ YYY: print "OK\n"; EOT close $f; -$r = runperl(prog => 'use goto01; print qq[DONE\n]'); +$r = runperl(prog => 'use Op_goto01; print qq[DONE\n]'); is($r, "OK\nDONE\n", "goto within use-d file"); -unlink "goto01.pm"; +unlink "Op_goto01.pm"; # test for [perl #24108] $ok = 1; diff --git a/gnu/usr.bin/perl/t/op/groups.t b/gnu/usr.bin/perl/t/op/groups.t index f682f610d1f..404b8cd8ab6 100644 --- a/gnu/usr.bin/perl/t/op/groups.t +++ b/gnu/usr.bin/perl/t/op/groups.t @@ -1,7 +1,7 @@ #!./perl $ENV{PATH} ="/bin:/usr/bin:/usr/xpg4/bin:/usr/ucb" . - exists $ENV{PATH} ? ":$ENV{PATH}" : ""; + exists $ENV{PATH} ? ":$ENV{PATH}" : "" unless $^O eq 'VMS'; $ENV{LC_ALL} = "C"; # so that external utilities speak English $ENV{LANGUAGE} = 'C'; # GNU locale extension @@ -27,7 +27,8 @@ unless (eval { getgrgid(0); 1 }) { exit 0; } -quit() if (($^O eq 'MSWin32' || $^O eq 'NetWare') or $^O =~ /lynxos/i); +quit() if (($^O eq 'MSWin32' || $^O eq 'NetWare' || $^O eq 'VMS') + or $^O =~ /lynxos/i); # We have to find a command that prints all (effective # and real) group names (not ids). The known commands are: @@ -136,7 +137,7 @@ for (split(' ', $()) { print "# gr = @gr\n"; my %did; -if ($^O =~ /^(?:uwin|cygwin|interix|solaris)$/) { +if ($^O =~ /^(?:uwin|cygwin|interix|solaris|linux)$/) { # Or anybody else who can have spaces in group names. $gr1 = join(' ', grep(!$did{$_}++, sort split(' ', join(' ', @gr)))); } else { diff --git a/gnu/usr.bin/perl/t/op/gv.t b/gnu/usr.bin/perl/t/op/gv.t index 5b04f8719ad..e04c2cafc84 100644 --- a/gnu/usr.bin/perl/t/op/gv.t +++ b/gnu/usr.bin/perl/t/op/gv.t @@ -12,7 +12,7 @@ BEGIN { use warnings; require './test.pl'; -plan( tests => 161 ); +plan( tests => 178 ); # type coersion on assignment $foo = 'foo'; @@ -377,18 +377,15 @@ is (ref $::{oonk}, 'SCALAR', "Export doesn't affect original"); is (eval 'spritsits', "Value", "Constant has correct value"); is (ref \$::{spritsits}, 'GLOB', "Symbol table has full typeglob"); -my $result; # Check that assignment to an existing typeglob works { my $w = ''; local $SIG{__WARN__} = sub { $w = $_[0] }; - $result = *{"plunk"} = \&{"oonk"}; + *{"plunk"} = []; + *{"plunk"} = \&{"oonk"}; is($w, '', "Should be no warning"); } -is (ref \$result, 'GLOB', - "Non void assignment should still return a typeglob"); - is (ref $::{oonk}, 'SCALAR', "Export doesn't affect original"); is (eval 'plunk', "Value", "Constant has correct value"); is (ref \$::{plunk}, 'GLOB', "Symbol table has full typeglob"); @@ -398,7 +395,7 @@ my $gr = eval '\*plunk' or die; { my $w = ''; local $SIG{__WARN__} = sub { $w = $_[0] }; - $result = *{$gr} = \&{"oonk"}; + *{$gr} = \&{"oonk"}; is($w, '', "Redefining a constant sub to another constant sub with the same underlying value should not warn (It's just re-exporting, and that was always legal)"); } @@ -406,6 +403,48 @@ is (ref $::{oonk}, 'SCALAR', "Export doesn't affect original"); is (eval 'plunk', "Value", "Constant has correct value"); is (ref \$::{plunk}, 'GLOB', "Symbol table has full typeglob"); +# Non-void context should defeat the optimisation, and will cause the original +# to be promoted (what change 26482 intended) +my $result; +{ + my $w = ''; + local $SIG{__WARN__} = sub { $w = $_[0] }; + $result = *{"awkkkkkk"} = \&{"oonk"}; + is($w, '', "Should be no warning"); +} + +is (ref \$result, 'GLOB', + "Non void assignment should still return a typeglob"); + +is (ref \$::{oonk}, 'GLOB', "This export does affect original"); +is (eval 'plunk', "Value", "Constant has correct value"); +is (ref \$::{plunk}, 'GLOB', "Symbol table has full typeglob"); + +delete $::{oonk}; +$::{oonk} = \"Value"; + +sub non_dangling { + my $w = ''; + local $SIG{__WARN__} = sub { $w = $_[0] }; + *{"zap"} = \&{"oonk"}; + is($w, '', "Should be no warning"); +} + +non_dangling(); +is (ref $::{oonk}, 'SCALAR', "Export doesn't affect original"); +is (eval 'zap', "Value", "Constant has correct value"); +is (ref $::{zap}, 'SCALAR', "Exported target is also a PCS"); + +sub dangling { + local $SIG{__WARN__} = sub { die $_[0] }; + *{"biff"} = \&{"oonk"}; +} + +dangling(); +is (ref \$::{oonk}, 'GLOB', "This export does affect original"); +is (eval 'biff', "Value", "Constant has correct value"); +is (ref \$::{biff}, 'GLOB', "Symbol table has full typeglob"); + { use vars qw($glook $smek $foof); # Check reference assignment isn't affected by the SV type (bug #38439) @@ -494,6 +533,30 @@ foreach my $value ([1,2,3], {1=>2}, *STDOUT{IO}, \&ok, *STDOUT{FORMAT}) { "Assigment works when glob created midway (bug 45607)"); 1' or die $@; } + +# For now these tests are here, but they would probably be better in a file for +# tests for croaks. (And in turn, that probably deserves to be in a different +# directory. Gerard Goossen has a point about the layout being unclear + +sub coerce_integer { + no warnings 'numeric'; + $_[0] |= 0; +} +sub coerce_number { + no warnings 'numeric'; + $_[0] += 0; +} +sub coerce_string { + $_[0] .= ''; +} + +foreach my $type (qw(integer number string)) { + my $prog = "coerce_$type(*STDERR)"; + is (scalar eval "$prog; 1", undef, "$prog failed..."); + like ($@, qr/Can't coerce GLOB to $type in/, + "with the correct error message"); +} + __END__ Perl Rules diff --git a/gnu/usr.bin/perl/t/op/inc.t b/gnu/usr.bin/perl/t/op/inc.t index 3eec5cd872a..5606f85a4f3 100644 --- a/gnu/usr.bin/perl/t/op/inc.t +++ b/gnu/usr.bin/perl/t/op/inc.t @@ -2,7 +2,7 @@ # use strict; -print "1..34\n"; +print "1..38\n"; my $test = 1; @@ -194,3 +194,14 @@ ok ($a == 2147483647, $a); $x--; ok ($x == 0, "(void) i_postdec"); } + +# these will segfault if they fail + +sub PVBM () { 'foo' } +{ my $dummy = index 'foo', PVBM } + +ok (scalar eval { my $pvbm = PVBM; $pvbm++ }); +ok (scalar eval { my $pvbm = PVBM; $pvbm-- }); +ok (scalar eval { my $pvbm = PVBM; ++$pvbm }); +ok (scalar eval { my $pvbm = PVBM; --$pvbm }); + diff --git a/gnu/usr.bin/perl/t/op/index.t b/gnu/usr.bin/perl/t/op/index.t index b384bef445c..834814e296a 100644 --- a/gnu/usr.bin/perl/t/op/index.t +++ b/gnu/usr.bin/perl/t/op/index.t @@ -7,7 +7,11 @@ BEGIN { } use strict; -plan( tests => 69 ); +plan( tests => 111 ); + +run_tests() unless caller; + +sub run_tests { my $foo = 'Now is the time for all good men to come to the aid of their country.'; @@ -155,3 +159,43 @@ SKIP: { local ${^UTF8CACHE} = -1; is(index($t, 'xyz'), 4, "0xfffffffd and utf8cache"); } + + +# Tests for NUL characters. +{ + my @tests = ( + ["", -1, -1, -1], + ["foo", -1, -1, -1], + ["\0", 0, -1, -1], + ["\0\0", 0, 0, -1], + ["\0\0\0", 0, 0, 0], + ["foo\0", 3, -1, -1], + ["foo\0foo\0\0", 3, 7, -1], + ); + foreach my $l (1 .. 3) { + my $q = "\0" x $l; + my $i = 0; + foreach my $test (@tests) { + $i ++; + my $str = $$test [0]; + my $res = $$test [$l]; + + { + is (index ($str, $q), $res, "Find NUL character(s)"); + } + + # + # Bug #53746 shows a difference between variables and literals, + # so test literals as well. + # + my $test_str = qq {is (index ("$str", "$q"), $res, } . + qq {"Find NUL character(s)")}; + $test_str =~ s/\0/\\0/g; + + eval $test_str; + die $@ if $@; + } + } +} + +} diff --git a/gnu/usr.bin/perl/t/op/local.t b/gnu/usr.bin/perl/t/op/local.t index ee250e111d6..5bf56af36ac 100644 --- a/gnu/usr.bin/perl/t/op/local.t +++ b/gnu/usr.bin/perl/t/op/local.t @@ -5,7 +5,7 @@ BEGIN { @INC = qw(. ../lib); require './test.pl'; } -plan tests => 122; +plan tests => 123; my $list_assignment_supported = 1; @@ -451,6 +451,11 @@ sub f { ok(0 == $[); } is($h{'k1'},111); } +like( runperl(stderr => 1, + prog => 'use constant foo => q(a);' . + 'index(q(a), foo);' . + 'local *g=${::}{foo};print q(ok);'), "ok", "[perl #52740]"); + # Keep this test last, as it can SEGV { local *@; diff --git a/gnu/usr.bin/perl/t/op/magic.t b/gnu/usr.bin/perl/t/op/magic.t index 799c7178ac2..bfb68a75104 100644 --- a/gnu/usr.bin/perl/t/op/magic.t +++ b/gnu/usr.bin/perl/t/op/magic.t @@ -5,38 +5,14 @@ BEGIN { chdir 't' if -d 't'; @INC = '../lib'; $SIG{__WARN__} = sub { die "Dying on warning: ", @_ }; + require './test.pl'; } use warnings; use Config; -my $test = 1; -sub ok { - my($ok, $info, $todo) = @_; - # You have to do it this way or VMS will get confused. - printf "%s $test%s\n", $ok ? "ok" : "not ok", - $todo ? " # TODO $todo" : ''; - - unless( $ok ) { - printf "# Failed test at line %d\n", (caller)[2]; - print "# $info\n" if defined $info; - } - - $test++; - return $ok; -} - -sub skip { - my($reason) = @_; - - printf "ok $test # skipped%s\n", defined $reason ? ": $reason" : ''; - - $test++; - return 1; -} - -print "1..58\n"; +plan (tests => 59); $Is_MSWin32 = $^O eq 'MSWin32'; $Is_NetWare = $^O eq 'NetWare'; @@ -55,24 +31,28 @@ $PERL = $ENV{PERL} $Is_MSWin32 ? '.\perl' : './perl'); +END { + # On VMS, environment variable changes are peristent after perl exits + delete $ENV{'FOO'} if $Is_VMS; +} + eval '$ENV{"FOO"} = "hi there";'; # check that ENV is inited inside eval # cmd.exe will echo 'variable=value' but 4nt will echo just the value # -- Nikola Knezevic -if ($Is_MSWin32) { ok `set FOO` =~ /^(?:FOO=)?hi there$/; } +if ($Is_MSWin32) { like `set FOO`, qr/^(?:FOO=)?hi there$/; } elsif ($Is_MacOS) { ok "1 # skipped", 1; } -elsif ($Is_VMS) { ok `write sys\$output f\$trnlnm("FOO")` eq "hi there\n"; } -else { ok `echo \$FOO` eq "hi there\n"; } +elsif ($Is_VMS) { is `write sys\$output f\$trnlnm("FOO")`, "hi there\n"; } +else { is `echo \$FOO`, "hi there\n"; } unlink 'ajslkdfpqjsjfk'; $! = 0; open(FOO,'ajslkdfpqjsjfk'); -ok $!, $!; +isnt($!, 0); close FOO; # just mention it, squelch used-only-once -if ($Is_MSWin32 || $Is_NetWare || $Is_Dos || $Is_MPE || $Is_MacOS) { - skip('SIGINT not safe on this platform') for 1..4; -} -else { +SKIP: { + skip('SIGINT not safe on this platform', 5) + if $Is_MSWin32 || $Is_NetWare || $Is_Dos || $Is_MPE || $Is_MacOS; # the next tests are done in a subprocess because sh spits out a # newline onto stderr when a child process kills itself with SIGINT. # We use a pipe rather than system() because the VMS command buffer @@ -131,58 +111,72 @@ END my $todo = ($^O eq 'os2' ? ' # TODO: EMX v0.9d_fix4 bug: wrong nibble? ' : ''); print $? & 0xFF ? "ok 6$todo\n" : "not ok 6$todo\n"; - $test += 4; + open(CMDPIPE, "| $PERL"); + print CMDPIPE <<'END'; + + sub PVBM () { 'foo' } + index 'foo', PVBM; + my $pvbm = PVBM; + + sub foo { exit 0 } + + $SIG{"INT"} = $pvbm; + kill "INT", $$; sleep 1; +END + close CMDPIPE; + $? >>= 8 if $^O eq 'VMS'; + print $? ? "not ok 7\n" : "ok 7\n"; + + curr_test(curr_test() + 5); } # can we slice ENV? @val1 = @ENV{keys(%ENV)}; @val2 = values(%ENV); -ok join(':',@val1) eq join(':',@val2); -ok @val1 > 1; +is join(':',@val1), join(':',@val2); +cmp_ok @val1, '>', 1; # regex vars 'foobarbaz' =~ /b(a)r/; -ok $` eq 'foo', $`; -ok $& eq 'bar', $&; -ok $' eq 'baz', $'; -ok $+ eq 'a', $+; +is $`, 'foo'; +is $&, 'bar'; +is $', 'baz'; +is $+, 'a'; # $" @a = qw(foo bar baz); -ok "@a" eq "foo bar baz", "@a"; +is "@a", "foo bar baz"; { local $" = ','; - ok "@a" eq "foo,bar,baz", "@a"; + is "@a", "foo,bar,baz"; } # $; %h = (); $h{'foo', 'bar'} = 1; -ok((keys %h)[0] eq "foo\034bar", (keys %h)[0]); +is((keys %h)[0], "foo\034bar"); { local $; = 'x'; %h = (); $h{'foo', 'bar'} = 1; - ok((keys %h)[0] eq 'fooxbar', (keys %h)[0]); + is((keys %h)[0], 'fooxbar'); } # $?, $@, $$ -if ($Is_MacOS) { - skip('$? + system are broken on MacPerl') for 1..2; -} -else { +SKIP: { + skip('$? + system are broken on MacPerl', 2) if $Is_MacOS; system qq[$PERL "-I../lib" -e "use vmsish qw(hushed); exit(0)"]; - ok $? == 0, $?; + is $?, 0; system qq[$PERL "-I../lib" -e "use vmsish qw(hushed); exit(1)"]; - ok $? != 0, $?; + isnt $?, 0; } eval { die "foo\n" }; -ok $@ eq "foo\n", $@; +is $@, "foo\n"; -ok $$ > 0, $$; +cmp_ok($$, '>', 0); eval { $$++ }; -ok $@ =~ /^Modification of a read-only value attempted/; +like ($@, qr/^Modification of a read-only value attempted/); # $^X and $0 { @@ -251,70 +245,88 @@ EOX EOH } $s1 = "\$^X is $perl, \$0 is $script\n"; - ok open(SCRIPT, ">$script"), $!; - ok print(SCRIPT $headmaybe . <<EOB . $middlemaybe . <<'EOF' . $tailmaybe), $!; + ok open(SCRIPT, ">$script") or diag $!; + ok print(SCRIPT $headmaybe . <<EOB . $middlemaybe . <<'EOF' . $tailmaybe) or diag $!; #!$wd/perl EOB print "\$^X is $^X, \$0 is $0\n"; EOF - ok close(SCRIPT), $!; - ok chmod(0755, $script), $!; + ok close(SCRIPT) or diag $!; + ok chmod(0755, $script) or diag $!; $_ = ($Is_MacOS || $Is_VMS) ? `$perl $script` : `$script`; s/\.exe//i if $Is_Dos or $Is_Cygwin or $Is_os2; s{./$script}{$script} if $Is_BeOS; # revert BeOS execvp() side-effect s{\bminiperl\b}{perl}; # so that test doesn't fail with miniperl s{is perl}{is $perl}; # for systems where $^X is only a basename s{\\}{/}g; - ok((($Is_MSWin32 || $Is_os2) ? uc($_) eq uc($s1) : $_ eq $s1), " :$_:!=:$s1:"); + if ($Is_MSWin32 || $Is_os2) { + is uc $_, uc $s1; + } else { + is $_, $s1; + } $_ = `$perl $script`; s/\.exe//i if $Is_Dos or $Is_os2 or $Is_Cygwin; s{./$perl}{$perl} if $Is_BeOS; # revert BeOS execvp() side-effect s{\\}{/}g; - ok((($Is_MSWin32 || $Is_os2) ? uc($_) eq uc($s1) : $_ eq $s1), " :$_:!=:$s1: after `$perl $script`"); - ok unlink($script), $!; + if ($Is_MSWin32 || $Is_os2) { + is uc $_, uc $s1; + } else { + is $_, $s1; + } + ok unlink($script) or diag $!; } # $], $^O, $^T -ok $] >= 5.00319, $]; +cmp_ok $], '>=', 5.00319; ok $^O; -ok $^T > 850000000, $^T; +cmp_ok $^T, '>', 850000000; # Test change 25062 is working my $orig_osname = $^O; { local $^I = '.bak'; -ok($^O eq $orig_osname, 'Assigning $^I does not clobber $^O'); +is $^O, $orig_osname, 'Assigning $^I does not clobber $^O'; } $^O = $orig_osname; -if ($Is_VMS || $Is_Dos || $Is_MacOS) { - skip("%ENV manipulations fail or aren't safe on $^O") for 1..4; -} -else { - if ($ENV{PERL_VALGRIND}) { - skip("clearing \%ENV is not safe when running under valgrind"); - } else { +SKIP: { + skip("%ENV manipulations fail or aren't safe on $^O", 4) + if $Is_VMS || $Is_Dos || $Is_MacOS; + + SKIP: { + skip("clearing \%ENV is not safe when running under valgrind") + if $ENV{PERL_VALGRIND}; + $PATH = $ENV{PATH}; $PDL = $ENV{PERL_DESTRUCT_LEVEL} || 0; $ENV{foo} = "bar"; %ENV = (); $ENV{PATH} = $PATH; $ENV{PERL_DESTRUCT_LEVEL} = $PDL || 0; - ok ($Is_MSWin32 ? (`set foo 2>NUL` eq "") - : (`echo \$foo` eq "\n") ); + if ($Is_MSWin32) { + is `set foo 2>NUL`, ""; + } else { + is `echo \$foo`, "\n"; + } } $ENV{__NoNeSuCh} = "foo"; $0 = "bar"; # cmd.exe will echo 'variable=value' but 4nt will echo just the value # -- Nikola Knezevic - ok ($Is_MSWin32 ? (`set __NoNeSuCh` =~ /^(?:__NoNeSuCh=)?foo$/) - : (`echo \$__NoNeSuCh` eq "foo\n") ); - if ($^O =~ /^(linux|freebsd)$/ && - open CMDLINE, "/proc/$$/cmdline") { + if ($Is_MSWin32) { + like `set __NoNeSuCh`, qr/^(?:__NoNeSuCh=)?foo$/; + } else { + is `echo \$__NoNeSuCh`, "foo\n"; + } + SKIP: { + skip("\$0 check only on Linux and FreeBSD", 2) + unless $^O =~ /^(linux|freebsd)$/ + && open CMDLINE, "/proc/$$/cmdline"; + chomp(my $line = scalar <CMDLINE>); my $me = (split /\0/, $line)[0]; - ok($me eq $0, 'altering $0 is effective (testing with /proc/)'); + is $me, $0, 'altering $0 is effective (testing with /proc/)'; close CMDLINE; # perlbug #22811 my $mydollarzero = sub { @@ -342,37 +354,34 @@ else { # can get rid of the first one. || ($^O eq 'freebsd' && $ps =~ m/^(?:perl: )?x(?: \(perl\))?$/), 'altering $0 is effective (testing with `ps`)'); - } else { - skip("\$0 check only on Linux and FreeBSD") for 0, 1; } } { my $ok = 1; my $warn = ''; - local $SIG{'__WARN__'} = sub { $ok = 0; $warn = join '', @_; }; + local $SIG{'__WARN__'} = sub { $ok = 0; $warn = join '', @_; $warn =~ s/\n$//; }; $! = undef; - ok($ok, $warn, $Is_VMS ? "'\$!=undef' does throw a warning" : ''); + local $TODO = $Is_VMS ? "'\$!=undef' does throw a warning" : ''; + ok($ok, $warn); } # test case-insignificance of %ENV (these tests must be enabled only # when perl is compiled with -DENV_IS_CASELESS) -if ($Is_MSWin32 || $Is_NetWare) { +SKIP: { + skip('no caseless %ENV support', 4) unless $Is_MSWin32 || $Is_NetWare; + %ENV = (); $ENV{'Foo'} = 'bar'; $ENV{'fOo'} = 'baz'; - ok (scalar(keys(%ENV)) == 1); - ok exists($ENV{'FOo'}); - ok (delete($ENV{'foO'}) eq 'baz'); - ok (scalar(keys(%ENV)) == 0); -} -else { - skip('no caseless %ENV support') for 1..4; + is scalar(keys(%ENV)), 1; + ok exists $ENV{'FOo'}; + is delete $ENV{'foO'}, 'baz'; + is scalar(keys(%ENV)), 0; } -if ($Is_miniperl) { - skip ("miniperl can't rely on loading %Errno") for 1..2; -} else { +SKIP: { + skip ("miniperl can't rely on loading %Errno", 2) if $Is_miniperl; no warnings 'void'; # Make sure Errno hasn't been prematurely autoloaded @@ -387,9 +396,8 @@ if ($Is_miniperl) { }, $@; } -if ($Is_miniperl) { - skip ("miniperl can't rely on loading %Errno"); -} else { +SKIP: { + skip ("miniperl can't rely on loading %Errno") if $Is_miniperl; # Make sure that Errno loading doesn't clobber $! undef %Errno::; @@ -400,21 +408,21 @@ if ($Is_miniperl) { ok ${"!"}{ENOENT}; } -ok $^S == 0 && defined $^S; -eval { ok $^S == 1 }; +is $^S, 0; +eval { is $^S,1 }; eval " BEGIN { ok ! defined \$^S } "; -ok $^S == 0 && defined $^S; +is $^S, 0; -ok ${^TAINT} == 0; +is ${^TAINT}, 0; eval { ${^TAINT} = 1 }; -ok ${^TAINT} == 0; +is ${^TAINT}, 0; # 5.6.1 had a bug: @+ and @- were not properly interpolated # into double-quoted strings # 20020414 mjd-perl-patch+@plover.com "I like pie" =~ /(I) (like) (pie)/; -ok "@-" eq "0 0 2 7"; -ok "@+" eq "10 1 6 10"; +is "@-", "0 0 2 7"; +is "@+", "10 1 6 10"; # Tests for the magic get of $\ { @@ -443,29 +451,27 @@ ok "@+" eq "10 1 6 10"; return @+; }; my @y = f(); - ok( $x eq "@y", "return a magic array ($x) vs (@y)" ); + is $x, "@y", "return a magic array ($x) vs (@y)"; } # Test for bug [perl #36434] -if (!$Is_VMS) { +# Can not do this test on VMS, EPOC, and SYMBIAN according to comments +# in mg.c/Perl_magic_clear_all_env() +SKIP: { + skip('Can\'t make assignment to \%ENV on this system', 3) if $Is_VMS; + local @ISA; local %ENV; # This used to be __PACKAGE__, but that causes recursive # inheritance, which is detected earlier now and broke # this test eval { push @ISA, __FILE__ }; - ok( $@ eq '', 'Push a constant on a magic array'); + is $@, '', 'Push a constant on a magic array'; $@ and print "# $@"; eval { %ENV = (PATH => __PACKAGE__) }; - ok( $@ eq '', 'Assign a constant to a magic hash'); + is $@, '', 'Assign a constant to a magic hash'; $@ and print "# $@"; eval { my %h = qw(A B); %ENV = (PATH => (keys %h)[0]) }; - ok( $@ eq '', 'Assign a shared key to a magic hash'); + is $@, '', 'Assign a shared key to a magic hash'; $@ and print "# $@"; } -else { -# Can not do this test on VMS, EPOC, and SYMBIAN according to comments -# in mg.c/Perl_magic_clear_all_env() -# - skip('Can\'t make assignment to \%ENV on this system') for 1..3; -} diff --git a/gnu/usr.bin/perl/t/op/method.t b/gnu/usr.bin/perl/t/op/method.t index aaf29be8df1..46c46426eb9 100644 --- a/gnu/usr.bin/perl/t/op/method.t +++ b/gnu/usr.bin/perl/t/op/method.t @@ -183,23 +183,23 @@ is(defined(@{"unknown_package::ISA"}) ? "defined" : "undefined", "undefined"); # test error messages if method loading fails -is(do { eval '$e = bless {}, "E::A"; E::A->foo()'; - $@ =~ /^\QCan't locate object method "foo" via package "E::A" at/ ? 1 : $@}, 1); -is(do { eval '$e = bless {}, "E::B"; $e->foo()'; - $@ =~ /^\QCan't locate object method "foo" via package "E::B" at/ ? 1 : $@}, 1); -is(do { eval 'E::C->foo()'; - $@ =~ /^\QCan't locate object method "foo" via package "E::C" (perhaps / ? 1 : $@}, 1); - -is(do { eval 'UNIVERSAL->E::D::foo()'; - $@ =~ /^\QCan't locate object method "foo" via package "E::D" (perhaps / ? 1 : $@}, 1); -is(do { eval '$e = bless {}, "UNIVERSAL"; $e->E::E::foo()'; - $@ =~ /^\QCan't locate object method "foo" via package "E::E" (perhaps / ? 1 : $@}, 1); +eval '$e = bless {}, "E::A"; E::A->foo()'; +like ($@, qr/^\QCan't locate object method "foo" via package "E::A" at/); +eval '$e = bless {}, "E::B"; $e->foo()'; +like ($@, qr/^\QCan't locate object method "foo" via package "E::B" at/); +eval 'E::C->foo()'; +like ($@, qr/^\QCan't locate object method "foo" via package "E::C" (perhaps /); + +eval 'UNIVERSAL->E::D::foo()'; +like ($@, qr/^\QCan't locate object method "foo" via package "E::D" (perhaps /); +eval '$e = bless {}, "UNIVERSAL"; $e->E::E::foo()'; +like ($@, qr/^\QCan't locate object method "foo" via package "E::E" (perhaps /); $e = bless {}, "E::F"; # force package to exist -is(do { eval 'UNIVERSAL->E::F::foo()'; - $@ =~ /^\QCan't locate object method "foo" via package "E::F" at/ ? 1 : $@}, 1); -is(do { eval '$e = bless {}, "UNIVERSAL"; $e->E::F::foo()'; - $@ =~ /^\QCan't locate object method "foo" via package "E::F" at/ ? 1 : $@}, 1); +eval 'UNIVERSAL->E::F::foo()'; +like ($@, qr/^\QCan't locate object method "foo" via package "E::F" at/); +eval '$e = bless {}, "UNIVERSAL"; $e->E::F::foo()'; +like ($@, qr/^\QCan't locate object method "foo" via package "E::F" at/); # TODO: we need some tests for the SUPER:: pseudoclass diff --git a/gnu/usr.bin/perl/t/op/pack.t b/gnu/usr.bin/perl/t/op/pack.t index 9312646cbb3..4b5f9a5bc5a 100644 --- a/gnu/usr.bin/perl/t/op/pack.t +++ b/gnu/usr.bin/perl/t/op/pack.t @@ -12,7 +12,7 @@ my $no_endianness = $] > 5.009 ? '' : my $no_signedness = $] > 5.009 ? '' : "Signed/unsigned pack modifiers not available on this perl"; -plan tests => 14696; +plan tests => 14697; use strict; use warnings qw(FATAL all); @@ -1980,3 +1980,8 @@ is(unpack('c'), 65, "one-arg unpack (change #18751)"); # defaulting to $_ is(unpack('@!4 a*', "\x{301}\x{302}\x{303}\x{304}\x{305}"), "\x{303}\x{304}\x{305}", 'Test basic utf8 @!'); } +{ + #50256 + my ($v) = split //, unpack ('(B)*', 'ab'); + is($v, 0); # Doesn't SEGV :-) +} diff --git a/gnu/usr.bin/perl/t/op/pat.t b/gnu/usr.bin/perl/t/op/pat.t index 7d03eb6b824..0b2c729b238 100644 --- a/gnu/usr.bin/perl/t/op/pat.t +++ b/gnu/usr.bin/perl/t/op/pat.t @@ -4,4564 +4,4370 @@ # the format supported by op/regexp.t. If you want to add a test # that does fit that format, add it to op/re_tests, not here. +use strict; +use warnings; +use 5.010; + + +sub run_tests; + $| = 1; -# Test counter output is generated by a BEGIN block at bottom of file +my $EXPECTED_TESTS = 4065; # Update this when adding/deleting tests. BEGIN { chdir 't' if -d 't'; @INC = '../lib'; } +our $TODO; our $Message = "Noname test"; - +our $Error; +our $DiePattern; +our $WarnPattern; +our $BugId; +our $PatchId; +our $running_as_thread; + +my $ordA = ord ('A'); # This defines ASCII/UTF-8 vs EBCDIC/UTF-EBCDIC +# This defined the platform. +my $IS_ASCII = $ordA == 65; +my $IS_EBCDIC = $ordA == 193; + +use vars '%Config'; eval 'use Config'; # Defaults assumed if this fails -$x = "abc\ndef\n"; +my $test = 0; -if ($x =~ /^abc/) {print "ok 1\n";} else {print "not ok 1\n";} -if ($x !~ /^def/) {print "ok 2\n";} else {print "not ok 2\n";} +print "1..$EXPECTED_TESTS\n"; -# used to be a test for $* -if ($x =~ /^def/m) {print "ok 3\n";} else {print "not ok 3\n";} +run_tests unless caller (); -$_ = '123'; -if (/^([0-9][0-9]*)/) {print "ok 4\n";} else {print "not ok 4\n";} +END { +} -if ($x =~ /^xxx/) {print "not ok 5\n";} else {print "ok 5\n";} -if ($x !~ /^abc/) {print "not ok 6\n";} else {print "ok 6\n";} +sub pretty { + my ($mess) = @_; + $mess =~ s/\n/\\n/g; + $mess =~ s/\r/\\r/g; + $mess =~ s/\t/\\t/g; + $mess =~ s/([\00-\37\177])/sprintf '\%03o', ord $1/eg; + $mess =~ s/#/\\#/g; + $mess; +} -if ($x =~ /def/) {print "ok 7\n";} else {print "not ok 7\n";} -if ($x !~ /def/) {print "not ok 8\n";} else {print "ok 8\n";} +sub safe_globals { + defined($_) and s/#/\\#/g for $BugId, $PatchId, $TODO; +} -if ($x !~ /.def/) {print "ok 9\n";} else {print "not ok 9\n";} -if ($x =~ /.def/) {print "not ok 10\n";} else {print "ok 10\n";} +sub _ok { + my ($ok, $mess, $error) = @_; + safe_globals(); + $mess = pretty ($mess // $Message); + $mess .= "; Bug $BugId" if defined $BugId; + $mess .= "; Patch $PatchId" if defined $PatchId; + $mess .= " # TODO $TODO" if defined $TODO; -if ($x =~ /\ndef/) {print "ok 11\n";} else {print "not ok 11\n";} -if ($x !~ /\ndef/) {print "not ok 12\n";} else {print "ok 12\n";} + my $line_nr = (caller(1)) [2]; -$_ = 'aaabbbccc'; -if (/(a*b*)(c*)/ && $1 eq 'aaabbb' && $2 eq 'ccc') { - print "ok 13\n"; -} else { - print "not ok 13\n"; -} -if (/(a+b+c+)/ && $1 eq 'aaabbbccc') { - print "ok 14\n"; -} else { - print "not ok 14\n"; -} + printf "%sok %d - %s\n", + ($ok ? "" : "not "), + ++ $test, + "$mess\tLine $line_nr"; -if (/a+b?c+/) {print "not ok 15\n";} else {print "ok 15\n";} + unless ($ok) { + print "# Failed test at line $line_nr\n" unless defined $TODO; + if ($error //= $Error) { + no warnings 'utf8'; + chomp $error; + $error = join "\n#", map {pretty $_} split /\n\h*#/ => $error; + $error = "# $error" unless $error =~ /^\h*#/; + print $error, "\n"; + } + } -$_ = 'aaabccc'; -if (/a+b?c+/) {print "ok 16\n";} else {print "not ok 16\n";} -if (/a*b+c*/) {print "ok 17\n";} else {print "not ok 17\n";} + return $ok; +} -$_ = 'aaaccc'; -if (/a*b?c*/) {print "ok 18\n";} else {print "not ok 18\n";} -if (/a*b+c*/) {print "not ok 19\n";} else {print "ok 19\n";} +# Force scalar context on the pattern match +sub ok ($;$$) {_ok $_ [0], $_ [1], $_ [2]} +sub nok ($;$$) {_ok !$_ [0], "Failed: " . ($_ [1] // $Message), $_ [2]} -$_ = 'abcdef'; -if (/bcd|xyz/) {print "ok 20\n";} else {print "not ok 20\n";} -if (/xyz|bcd/) {print "ok 21\n";} else {print "not ok 21\n";} -if (m|bc/*d|) {print "ok 22\n";} else {print "not ok 22\n";} +sub skip { + my $why = shift; + safe_globals(); + $why =~ s/\n.*//s; + $why .= "; Bug $BugId" if defined $BugId; + # seems like the new harness code doesnt like todo and skip to be mixed. + # which seems like a bug in the harness to me. -- dmq + #$why .= " # TODO $TODO" if defined $TODO; + + my $n = shift // 1; + my $line_nr = (caller(0)) [2]; + for (1 .. $n) { + ++ $test; + #print "not " if defined $TODO; + print "ok $test # skip $why\tLine $line_nr\n"; + } + no warnings "exiting"; + last SKIP; +} -if (/^$_$/) {print "ok 23\n";} else {print "not ok 23\n";} +sub iseq ($$;$) { + my ($got, $expect, $name) = @_; + + $_ = defined ($_) ? "'$_'" : "undef" for $got, $expect; + + my $ok = $got eq $expect; + my $error = "# expected: $expect\n" . + "# result: $got"; -# used to be a test for $* -if ("ab\ncd\n" =~ /^cd/m) {print "ok 24\n";} else {print "not ok 24\n";} + _ok $ok, $name, $error; +} -$XXX{123} = 123; -$XXX{234} = 234; -$XXX{345} = 345; +sub isneq ($$;$) { + my ($got, $expect, $name) = @_; + my $todo = $TODO ? " # TODO $TODO" : ''; + + $_ = defined ($_) ? "'$_'" : "undef" for $got, $expect; + + my $ok = $got ne $expect; + my $error = "# results are equal ($got)"; -@XXX = ('ok 25','not ok 25', 'ok 26','not ok 26','not ok 27'); -while ($_ = shift(@XXX)) { - ?(.*)? && (print $1,"\n"); - /not/ && reset; - if (/not ok 26/) { - if ($^O eq 'VMS') { - $_ = shift(@XXX); - } - else { - reset 'X'; - } - } -} + _ok $ok, $name, $error; +} -if ($^O ne 'VMS') { - while (($key,$val) = each(%XXX)) { - print "not ok 27\n"; - exit; - } -} -print "ok 27\n"; - -'cde' =~ /[^ab]*/; -'xyz' =~ //; -if ($& eq 'xyz') {print "ok 28\n";} else {print "not ok 28\n";} - -$foo = '[^ab]*'; -'cde' =~ /$foo/; -'xyz' =~ //; -if ($& eq 'xyz') {print "ok 29\n";} else {print "not ok 29\n";} - -$foo = '[^ab]*'; -'cde' =~ /$foo/; -'xyz' =~ /$null/; -if ($& eq 'xyz') {print "ok 30\n";} else {print "not ok 30\n";} - -$_ = 'abcdefghi'; -/def/; # optimized up to cmd -if ("$`:$&:$'" eq 'abc:def:ghi') {print "ok 31\n";} else {print "not ok 31\n";} - -/cde/ + 0; # optimized only to spat -if ("$`:$&:$'" eq 'ab:cde:fghi') {print "ok 32\n";} else {print "not ok 32\n";} - -/[d][e][f]/; # not optimized -if ("$`:$&:$'" eq 'abc:def:ghi') {print "ok 33\n";} else {print "not ok 33\n";} - -$_ = 'now is the {time for all} good men to come to.'; -/ {([^}]*)}/; -if ($1 eq 'time for all') {print "ok 34\n";} else {print "not ok 34 $1\n";} - -$_ = 'xxx {3,4} yyy zzz'; -print /( {3,4})/ ? "ok 35\n" : "not ok 35\n"; -print $1 eq ' ' ? "ok 36\n" : "not ok 36\n"; -print /( {4,})/ ? "not ok 37\n" : "ok 37\n"; -print /( {2,3}.)/ ? "ok 38\n" : "not ok 38\n"; -print $1 eq ' y' ? "ok 39\n" : "not ok 39\n"; -print /(y{2,3}.)/ ? "ok 40\n" : "not ok 40\n"; -print $1 eq 'yyy ' ? "ok 41\n" : "not ok 41\n"; -print /x {3,4}/ ? "not ok 42\n" : "ok 42\n"; -print /^xxx {3,4}/ ? "not ok 43\n" : "ok 43\n"; - -$_ = "now is the time for all good men to come to."; -@words = /(\w+)/g; -print join(':',@words) eq "now:is:the:time:for:all:good:men:to:come:to" - ? "ok 44\n" - : "not ok 44\n"; - -@words = (); -while (/\w+/g) { - push(@words, $&); -} -print join(':',@words) eq "now:is:the:time:for:all:good:men:to:come:to" - ? "ok 45\n" - : "not ok 45\n"; - -@words = (); -pos = 0; -while (/to/g) { - push(@words, $&); -} -print join(':',@words) eq "to:to" - ? "ok 46\n" - : "not ok 46 `@words'\n"; - -pos $_ = 0; -@words = /to/g; -print join(':',@words) eq "to:to" - ? "ok 47\n" - : "not ok 47 `@words'\n"; - -$_ = "abcdefghi"; - -$pat1 = 'def'; -$pat2 = '^def'; -$pat3 = '.def.'; -$pat4 = 'abc'; -$pat5 = '^abc'; -$pat6 = 'abc$'; -$pat7 = 'ghi'; -$pat8 = '\w*ghi'; -$pat9 = 'ghi$'; - -$t1=$t2=$t3=$t4=$t5=$t6=$t7=$t8=$t9=0; - -for $iter (1..5) { - $t1++ if /$pat1/o; - $t2++ if /$pat2/o; - $t3++ if /$pat3/o; - $t4++ if /$pat4/o; - $t5++ if /$pat5/o; - $t6++ if /$pat6/o; - $t7++ if /$pat7/o; - $t8++ if /$pat8/o; - $t9++ if /$pat9/o; +sub eval_ok ($;$) { + my ($code, $name) = @_; + local $@; + if (ref $code) { + _ok eval {&$code} && !$@, $name; + } + else { + _ok eval ($code) && !$@, $name; + } } -$x = "$t1$t2$t3$t4$t5$t6$t7$t8$t9"; -print $x eq '505550555' ? "ok 48\n" : "not ok 48 $x\n"; - -$xyz = 'xyz'; -print "abc" =~ /^abc$|$xyz/ ? "ok 49\n" : "not ok 49\n"; - -# perl 4.009 says "unmatched ()" -eval '"abc" =~ /a(bc$)|$xyz/; $result = "$&:$1"'; -print $@ eq "" ? "ok 50\n" : "not ok 50\n"; -print $result eq "abc:bc" ? "ok 51\n" : "not ok 51\n"; - - -$_="abcfooabcbar"; -$x=/abc/g; -print $` eq "" ? "ok 52\n" : "not ok 52\n" if $x; -$x=/abc/g; -print $` eq "abcfoo" ? "ok 53\n" : "not ok 53\n" if $x; -$x=/abc/g; -print $x == 0 ? "ok 54\n" : "not ok 54\n"; -pos = 0; -$x=/ABC/gi; -print $` eq "" ? "ok 55\n" : "not ok 55\n" if $x; -$x=/ABC/gi; -print $` eq "abcfoo" ? "ok 56\n" : "not ok 56\n" if $x; -$x=/ABC/gi; -print $x == 0 ? "ok 57\n" : "not ok 57\n"; -pos = 0; -$x=/abc/g; -print $' eq "fooabcbar" ? "ok 58\n" : "not ok 58\n" if $x; -$x=/abc/g; -print $' eq "bar" ? "ok 59\n" : "not ok 59\n" if $x; -$_ .= ''; -@x=/abc/g; -print scalar @x == 2 ? "ok 60\n" : "not ok 60\n"; - -$_ = "abdc"; -pos $_ = 2; -/\Gc/gc; -print "not " if (pos $_) != 2; -print "ok 61\n"; -/\Gc/g; -print "not " if defined pos $_; -print "ok 62\n"; - -$out = 1; -'abc' =~ m'a(?{ $out = 2 })b'; -print "not " if $out != 2; -print "ok 63\n"; - -$out = 1; -'abc' =~ m'a(?{ $out = 3 })c'; -print "not " if $out != 1; -print "ok 64\n"; - -$_ = 'foobar1 bar2 foobar3 barfoobar5 foobar6'; -@out = /(?<!foo)bar./g; -print "not " if "@out" ne 'bar2 barf'; -print "ok 65\n"; - -# Tests which depend on REG_INFTY -$reg_infty = defined $Config{reg_infty} ? $Config{reg_infty} : 32767; -$reg_infty_m = $reg_infty - 1; $reg_infty_p = $reg_infty + 1; - -# As well as failing if the pattern matches do unexpected things, the -# next three tests will fail if you should have picked up a lower-than- -# default value for $reg_infty from Config.pm, but have not. - -undef $@; -print "not " if eval q(('aaa' =~ /(a{1,$reg_infty_m})/)[0] ne 'aaa') || $@; -print "ok 66\n"; - -undef $@; -print "not " if eval q(('a' x $reg_infty_m) !~ /a{$reg_infty_m}/) || $@; -print "ok 67\n"; - -undef $@; -print "not " if eval q(('a' x ($reg_infty_m - 1)) =~ /a{$reg_infty_m}/) || $@; -print "ok 68\n"; - -undef $@; -eval "'aaa' =~ /a{1,$reg_infty}/"; -print "not " if $@ !~ m%^\QQuantifier in {,} bigger than%; -print "ok 69\n"; - -eval "'aaa' =~ /a{1,$reg_infty_p}/"; -print "not " - if $@ !~ m%^\QQuantifier in {,} bigger than%; -print "ok 70\n"; -undef $@; - -# Poke a couple more parse failures - -$context = 'x' x 256; -eval qq("${context}y" =~ /(?<=$context)y/); -print "not " if $@ !~ m%^\QLookbehind longer than 255 not%; -print "ok 71\n"; - -# removed test -print "ok 72\n"; - -# Long Monsters -$test = 73; -for $l (125, 140, 250, 270, 300000, 30) { # Ordered to free memory - $a = 'a' x $l; - print "# length=$l\nnot " unless "ba$a=" =~ /a$a=/; - print "ok $test\n"; - $test++; - - print "not " if "b$a=" =~ /a$a=/; - print "ok $test\n"; - $test++; +sub must_die { + my ($code, $pattern, $name) = @_; + $pattern //= $DiePattern; + undef $@; + ref $code ? &$code : eval $code; + my $r = $@ && $@ =~ /$pattern/; + _ok $r, $name // $Message // "\$\@ =~ /$pattern/"; } -# 20000 nodes, each taking 3 words per string, and 1 per branch -$long_constant_len = join '|', 12120 .. 32645; -$long_var_len = join '|', 8120 .. 28645; -%ans = ( 'ax13876y25677lbc' => 1, - 'ax13876y25677mcb' => 0, # not b. - 'ax13876y35677nbc' => 0, # Num too big - 'ax13876y25677y21378obc' => 1, - 'ax13876y25677y21378zbc' => 0, # Not followed by [k-o] - 'ax13876y25677y21378y21378kbc' => 1, - 'ax13876y25677y21378y21378kcb' => 0, # Not b. - 'ax13876y25677y21378y21378y21378kbc' => 0, # 5 runs - ); - -for ( keys %ans ) { - print "# const-len `$_' not => $ans{$_}\nnot " - if $ans{$_} xor /a(?=([yx]($long_constant_len)){2,4}[k-o]).*b./o; - print "ok $test\n"; - $test++; - print "# var-len `$_' not => $ans{$_}\nnot " - if $ans{$_} xor /a(?=([yx]($long_var_len)){2,4}[k-o]).*b./o; - print "ok $test\n"; - $test++; +sub must_warn { + my ($code, $pattern, $name) = @_; + $pattern //= $WarnPattern; + my $w; + local $SIG {__WARN__} = sub {$w .= join "" => @_}; + use warnings 'all'; + ref $code ? &$code : eval $code; + my $r = $w && $w =~ /$pattern/; + $w //= "UNDEF"; + _ok $r, $name // $Message // "Got warning /$pattern/", + "# expected: /$pattern/\n" . + "# result: $w"; +} + +sub may_not_warn { + my ($code, $name) = @_; + my $w; + local $SIG {__WARN__} = sub {$w .= join "" => @_}; + use warnings 'all'; + ref $code ? &$code : eval $code; + _ok !$w, $name // ($Message ? "$Message (did not warn)" + : "Did not warn"), + "Got warning '$w'"; } -$_ = " a (bla()) and x(y b((l)u((e))) and b(l(e)e)e"; -$expect = "(bla()) ((l)u((e))) (l(e)e)"; - -sub matchit { - m/ - ( - \( - (?{ $c = 1 }) # Initialize - (?: - (?(?{ $c == 0 }) # PREVIOUS iteration was OK, stop the loop - (?! - ) # Fail: will unwind one iteration back - ) - (?: - [^()]+ # Match a big chunk - (?= - [()] - ) # Do not try to match subchunks - | - \( - (?{ ++$c }) - | - \) - (?{ --$c }) - ) - )+ # This may not match with different subblocks - ) - (?(?{ $c != 0 }) - (?! - ) # Fail - ) # Otherwise the chunk 1 may succeed with $c>0 - /xg; -} -@ans = (); -push @ans, $res while $res = matchit; - -print "# ans='@ans'\n# expect='$expect'\nnot " if "@ans" ne "1 1 1"; -print "ok $test\n"; -$test++; - -@ans = matchit; - -print "# ans='@ans'\n# expect='$expect'\nnot " if "@ans" ne $expect; -print "ok $test\n"; -$test++; - -print "not " unless "abc" =~ /^(??{"a"})b/; -print "ok $test\n"; -$test++; - -my $matched; -$matched = qr/\((?:(?>[^()]+)|(??{$matched}))*\)/; - -@ans = @ans1 = (); -push(@ans, $res), push(@ans1, $&) while $res = m/$matched/g; - -print "# ans='@ans'\n# expect='$expect'\nnot " if "@ans" ne "1 1 1"; -print "ok $test\n"; -$test++; - -print "# ans1='@ans1'\n# expect='$expect'\nnot " if "@ans1" ne $expect; -print "ok $test\n"; -$test++; - -@ans = m/$matched/g; - -print "# ans='@ans'\n# expect='$expect'\nnot " if "@ans" ne $expect; -print "ok $test\n"; -$test++; - -@ans = ('a/b' =~ m%(.*/)?(.*)%); # Stack may be bad -print "not " if "@ans" ne 'a/ b'; -print "ok $test\n"; -$test++; - -$code = '{$blah = 45}'; -$blah = 12; -eval { /(?$code)/ }; -print "not " unless $@ and $@ =~ /not allowed at runtime/ and $blah == 12; -print "ok $test\n"; -$test++; - -for $code ('{$blah = 45}','=xx') { - $blah = 12; - $res = eval { "xx" =~ /(?$code)/o }; - if ($code eq '=xx') { - print "#'$@','$res','$blah'\nnot " unless not $@ and $res; - } else { - print "#'$@','$res','$blah'\nnot " unless $@ and $@ =~ /not allowed at runtime/ and $blah == 12; - } - print "ok $test\n"; - $test++; -} +# +# Tests start here. +# +sub run_tests { -$code = '{$blah = 45}'; -$blah = 12; -eval "/(?$code)/"; -print "not " if $blah != 45; -print "ok $test\n"; -$test++; - -$blah = 12; -/(?{$blah = 45})/; -print "not " if $blah != 45; -print "ok $test\n"; -$test++; - -$x = 'banana'; -$x =~ /.a/g; -print "not " unless pos($x) == 2; -print "ok $test\n"; -$test++; - -$x =~ /.z/gc; -print "not " unless pos($x) == 2; -print "ok $test\n"; -$test++; - -sub f { - my $p = $_[0]; - return $p; -} + { -$x =~ /.a/g; -print "not " unless f(pos($x)) == 4; -print "ok $test\n"; -$test++; - -$x = $^R = 67; -'foot' =~ /foo(?{$x = 12; 75})[t]/; -print "not " unless $^R eq '75'; -print "ok $test\n"; -$test++; - -$x = $^R = 67; -'foot' =~ /foo(?{$x = 12; 75})[xy]/; -print "not " unless $^R eq '67' and $x eq '12'; -print "ok $test\n"; -$test++; - -$x = $^R = 67; -'foot' =~ /foo(?{ $^R + 12 })((?{ $x = 12; $^R + 17 })[xy])?/; -print "not " unless $^R eq '79' and $x eq '12'; -print "ok $test\n"; -$test++; - -print "not " unless qr/\b\v$/i eq '(?i-xsm:\b\v$)'; -print "ok $test\n"; -$test++; - -print "not " unless qr/\b\v$/s eq '(?s-xim:\b\v$)'; -print "ok $test\n"; -$test++; - -print "not " unless qr/\b\v$/m eq '(?m-xis:\b\v$)'; -print "ok $test\n"; -$test++; - -print "not " unless qr/\b\v$/x eq '(?x-ism:\b\v$)'; -print "ok $test\n"; -$test++; - -print "not " unless qr/\b\v$/xism eq '(?msix:\b\v$)'; -print "ok $test\n"; -$test++; - -print "not " unless qr/\b\v$/ eq '(?-xism:\b\v$)'; -print "ok $test\n"; -$test++; - -$_ = 'xabcx'; -foreach $ans ('', 'c') { - /(?<=(?=a)..)((?=c)|.)/g; - print "# \$1 ='$1'\n# \$ans='$ans'\nnot " unless $1 eq $ans; - print "ok $test\n"; - $test++; -} + my $x = "abc\ndef\n"; -$_ = 'a'; -foreach $ans ('', 'a', '') { - /^|a|$/g; - print "# \$& ='$&'\n# \$ans='$ans'\nnot " unless $& eq $ans; - print "ok $test\n"; - $test++; -} + ok $x =~ /^abc/, qq ["$x" =~ /^abc/]; + ok $x !~ /^def/, qq ["$x" !~ /^def/]; -sub prefixify { - my($v,$a,$b,$res) = @_; - $v =~ s/\Q$a\E/$b/; - print "not " unless $res eq $v; - print "ok $test\n"; - $test++; -} -prefixify('/a/b/lib/arch', "/a/b/lib", 'X/lib', 'X/lib/arch'); -prefixify('/a/b/man/arch', "/a/b/man", 'X/man', 'X/man/arch'); - -$_ = 'var="foo"'; -/(\")/; -print "not " unless $1 and /$1/; -print "ok $test\n"; -$test++; - -$a=qr/(?{++$b})/; -$b = 7; -/$a$a/; -print "not " unless $b eq '9'; -print "ok $test\n"; -$test++; - -$c="$a"; -/$a$a/; -print "not " unless $b eq '11'; -print "ok $test\n"; -$test++; - -{ - use re "eval"; - /$a$c$a/; - print "not " unless $b eq '14'; - print "ok $test\n"; - $test++; - - local $lex_a = 2; - my $lex_a = 43; - my $lex_b = 17; - my $lex_c = 27; - my $lex_res = ($lex_b =~ qr/$lex_b(?{ $lex_c = $lex_a++ })/); - print "not " unless $lex_res eq '1'; - print "ok $test\n"; - $test++; - print "not " unless $lex_a eq '44'; - print "ok $test\n"; - $test++; - print "not " unless $lex_c eq '43'; - print "ok $test\n"; - $test++; - - - no re "eval"; - $match = eval { /$a$c$a/ }; - print "not " - unless $b eq '14' and $@ =~ /Eval-group not allowed/ and not $match; - print "ok $test\n"; - $test++; -} + # used to be a test for $* + ok $x =~ /^def/m, qq ["$x" =~ /^def/m]; -{ - local $lex_a = 2; - my $lex_a = 43; - my $lex_b = 17; - my $lex_c = 27; - my $lex_res = ($lex_b =~ qr/17(?{ $lex_c = $lex_a++ })/); - print "not " unless $lex_res eq '1'; - print "ok $test\n"; - $test++; - print "not " unless $lex_a eq '44'; - print "ok $test\n"; - $test++; - print "not " unless $lex_c eq '43'; - print "ok $test\n"; - $test++; -} + nok $x =~ /^xxx/, qq ["$x" =~ /^xxx/]; + nok $x !~ /^abc/, qq ["$x" !~ /^abc/]; -{ - package aa; - $c = 2; - $::c = 3; - '' =~ /(?{ $c = 4 })/; - print "not " unless $c == 4; -} -print "ok $test\n"; -$test++; -print "not " unless $c == 3; -print "ok $test\n"; -$test++; - -sub must_warn_pat { - my $warn_pat = shift; - return sub { print "not " unless $_[0] =~ /$warn_pat/ } -} + ok $x =~ /def/, qq ["$x" =~ /def/]; + nok $x !~ /def/, qq ["$x" !~ /def/]; -sub must_warn { - my ($warn_pat, $code) = @_; - local %SIG; - eval 'BEGIN { use warnings; $SIG{__WARN__} = $warn_pat };' . $code; - print "ok $test\n"; - $test++; -} + ok $x !~ /.def/, qq ["$x" !~ /.def/]; + nok $x =~ /.def/, qq ["$x" =~ /.def/]; + ok $x =~ /\ndef/, qq ["$x" =~ /\ndef/]; + nok $x !~ /\ndef/, qq ["$x" !~ /\ndef/]; + } -sub make_must_warn { - my $warn_pat = shift; - return sub { must_warn(must_warn_pat($warn_pat)) } -} + { + $_ = '123'; + ok /^([0-9][0-9]*)/, qq [\$_ = '$_'; /^([0-9][0-9]*)/]; + } -my $for_future = make_must_warn('reserved for future extensions'); - -&$for_future('q(a:[b]:) =~ /[x[:foo:]]/'); - -#&$for_future('q(a=[b]=) =~ /[x[=foo=]]/'); -print "ok $test\n"; $test++; # now a fatal croak - -#&$for_future('q(a.[b].) =~ /[x[.foo.]]/'); -print "ok $test\n"; $test++; # now a fatal croak - -# test if failure of patterns returns empty list -$_ = 'aaa'; -@_ = /bbb/; -print "not " if @_; -print "ok $test\n"; -$test++; - -@_ = /bbb/g; -print "not " if @_; -print "ok $test\n"; -$test++; - -@_ = /(bbb)/; -print "not " if @_; -print "ok $test\n"; -$test++; - -@_ = /(bbb)/g; -print "not " if @_; -print "ok $test\n"; -$test++; - -/a(?=.$)/; -print "not " if $#+ != 0 or $#- != 0; -print "ok $test\n"; -$test++; - -print "not " if $+[0] != 2 or $-[0] != 1; -print "ok $test\n"; -$test++; - -print "not " - if defined $+[1] or defined $-[1] or defined $+[2] or defined $-[2]; -print "ok $test\n"; -$test++; - -/a(a)(a)/; -print "not " if $#+ != 2 or $#- != 2; -print "ok $test\n"; -$test++; - -print "not " if $+[0] != 3 or $-[0] != 0; -print "ok $test\n"; -$test++; - -print "not " if $+[1] != 2 or $-[1] != 1; -print "ok $test\n"; -$test++; - -print "not " if $+[2] != 3 or $-[2] != 2; -print "ok $test\n"; -$test++; - -print "not " - if defined $+[3] or defined $-[3] or defined $+[4] or defined $-[4]; -print "ok $test\n"; -$test++; - -/.(a)(b)?(a)/; -print "not " if $#+ != 3 or $#- != 3; -print "ok $test\n"; -$test++; - -print "not " if $+[0] != 3 or $-[0] != 0; -print "ok $test\n"; -$test++; - -print "not " if $+[1] != 2 or $-[1] != 1; -print "ok $test\n"; -$test++; - -print "not " if $+[3] != 3 or $-[3] != 2; -print "ok $test\n"; -$test++; - -print "not " - if defined $+[2] or defined $-[2] or defined $+[4] or defined $-[4]; -print "ok $test\n"; -$test++; - -/.(a)/; -print "not " if $#+ != 1 or $#- != 1; -print "ok $test\n"; -$test++; - -print "not " if $+[0] != 2 or $-[0] != 0; -print "ok $test\n"; -$test++; - -print "not " if $+[1] != 2 or $-[1] != 1; -print "ok $test\n"; -$test++; - -print "not " - if defined $+[2] or defined $-[2] or defined $+[3] or defined $-[3]; -print "ok $test\n"; -$test++; - -eval { $+[0] = 13; }; -print "not " - if $@ !~ /^Modification of a read-only value attempted/; -print "ok $test\n"; -$test++; - -eval { $-[0] = 13; }; -print "not " - if $@ !~ /^Modification of a read-only value attempted/; -print "ok $test\n"; -$test++; - -eval { @+ = (7, 6, 5); }; -print "not " - if $@ !~ /^Modification of a read-only value attempted/; -print "ok $test\n"; -$test++; - -eval { @- = qw(foo bar); }; -print "not " - if $@ !~ /^Modification of a read-only value attempted/; -print "ok $test\n"; -$test++; - -/.(a)(ba*)?/; -print "#$#-..$#+\nnot " if $#+ != 2 or $#- != 1; -print "ok $test\n"; -$test++; - -$_ = 'aaa'; -pos = 1; -@a = /\Ga/g; -print "not " unless "@a" eq "a a"; -print "ok $test\n"; -$test++; - -$str = 'abcde'; -pos $str = 2; - -print "not " if $str =~ /^\G/; -print "ok $test\n"; -$test++; - -print "not " if $str =~ /^.\G/; -print "ok $test\n"; -$test++; - -print "not " unless $str =~ /^..\G/; -print "ok $test\n"; -$test++; - -print "not " if $str =~ /^...\G/; -print "ok $test\n"; -$test++; - -print "not " unless $str =~ /.\G./ and $& eq 'bc'; -print "ok $test\n"; -$test++; - -print "not " unless $str =~ /\G../ and $& eq 'cd'; -print "ok $test\n"; -$test++; - -undef $foo; undef $bar; -print "#'$str','$foo','$bar'\nnot " - unless $str =~ /b(?{$foo = $_; $bar = pos})c/ - and $foo eq 'abcde' and $bar eq 2; -print "ok $test\n"; -$test++; - -undef $foo; undef $bar; -pos $str = undef; -print "#'$str','$foo','$bar'\nnot " - unless $str =~ /b(?{$foo = $_; $bar = pos})c/g - and $foo eq 'abcde' and $bar eq 2 and pos $str eq 3; -print "ok $test\n"; -$test++; - -$_ = $str; - -undef $foo; undef $bar; -print "#'$str','$foo','$bar'\nnot " - unless /b(?{$foo = $_; $bar = pos})c/ - and $foo eq 'abcde' and $bar eq 2; -print "ok $test\n"; -$test++; - -undef $foo; undef $bar; -print "#'$str','$foo','$bar'\nnot " - unless /b(?{$foo = $_; $bar = pos})c/g - and $foo eq 'abcde' and $bar eq 2 and pos eq 3; -print "ok $test\n"; -$test++; - -undef $foo; undef $bar; -pos = undef; -1 while /b(?{$foo = $_; $bar = pos})c/g; -print "#'$str','$foo','$bar'\nnot " - unless $foo eq 'abcde' and $bar eq 2 and not defined pos; -print "ok $test\n"; -$test++; - -undef $foo; undef $bar; -$_ = 'abcde|abcde'; -print "#'$str','$foo','$bar','$_'\nnot " - unless s/b(?{$foo = $_; $bar = pos})c/x/g and $foo eq 'abcde|abcde' - and $bar eq 8 and $_ eq 'axde|axde'; -print "ok $test\n"; -$test++; - -@res = (); -# List context: -$_ = 'abcde|abcde'; -@dummy = /([ace]).(?{push @res, $1,$2})([ce])(?{push @res, $1,$2})/g; -@res = map {defined $_ ? "'$_'" : 'undef'} @res; -$res = "@res"; -print "#'@res' '$_'\nnot " - unless "@res" eq "'a' undef 'a' 'c' 'e' undef 'a' undef 'a' 'c'"; -print "ok $test\n"; -$test++; - -@res = (); -@dummy = /([ace]).(?{push @res, $`,$&,$'})([ce])(?{push @res, $`,$&,$'})/g; -@res = map {defined $_ ? "'$_'" : 'undef'} @res; -$res = "@res"; -print "#'@res' '$_'\nnot " - unless "@res" eq - "'' 'ab' 'cde|abcde' " . - "'' 'abc' 'de|abcde' " . - "'abcd' 'e|' 'abcde' " . - "'abcde|' 'ab' 'cde' " . - "'abcde|' 'abc' 'de'" ; -print "ok $test\n"; -$test++; - -#Some more \G anchor checks -$foo='aabbccddeeffgg'; - -pos($foo)=1; - -$foo=~/.\G(..)/g; -iseq($1,'ab'); - -pos($foo) += 1; -$foo=~/.\G(..)/g; -print "not " unless($1 eq 'cc'); -print "ok $test\n"; -$test++; - -pos($foo) += 1; -$foo=~/.\G(..)/g; -print "not " unless($1 eq 'de'); -print "ok $test\n"; -$test++; - -print "not " unless $foo =~ /\Gef/g; -print "ok $test\n"; -$test++; - -undef pos $foo; - -$foo=~/\G(..)/g; -print "not " unless($1 eq 'aa'); -print "ok $test\n"; -$test++; - -$foo=~/\G(..)/g; -print "not " unless($1 eq 'bb'); -print "ok $test\n"; -$test++; - -pos($foo)=5; -$foo=~/\G(..)/g; -print "not " unless($1 eq 'cd'); -print "ok $test\n"; -$test++; - -$_='123x123'; -@res = /(\d*|x)/g; -print "not " unless('123||x|123|' eq join '|', @res); -print "ok $test\n"; -$test++; - -# see if matching against temporaries (created via pp_helem()) is safe -{ foo => "ok $test\n".$^X }->{foo} =~ /^(.*)\n/g; -print "$1\n"; -$test++; - -# See if $i work inside (?{}) in the presense of saved substrings and -# changing $_ -@a = qw(foo bar); -@b = (); -s/(\w)(?{push @b, $1})/,$1,/g for @a; - -print "# \@b='@b', expect 'f o o b a r'\nnot " unless("@b" eq "f o o b a r"); -print "ok $test\n"; -$test++; - -print "not " unless("@a" eq ",f,,o,,o, ,b,,a,,r,"); -print "ok $test\n"; -$test++; - -$brackets = qr{ - { (?> [^{}]+ | (??{ $brackets }) )* } - }x; - -"{{}" =~ $brackets; -print "ok $test\n"; # Did we survive? -$test++; - -"something { long { and } hairy" =~ $brackets; -print "ok $test\n"; # Did we survive? -$test++; - -"something { long { and } hairy" =~ m/((??{ $brackets }))/; -print "not " unless $1 eq "{ and }"; -print "ok $test\n"; -$test++; - -$_ = "a-a\nxbb"; -pos=1; -m/^-.*bb/mg and print "not "; -print "ok $test\n"; -$test++; - -$text = "aaXbXcc"; -pos($text)=0; -$text =~ /\GXb*X/g and print 'not '; -print "ok $test\n"; -$test++; - -$text = "xA\n" x 500; -$text =~ /^\s*A/m and print 'not '; -print "ok $test\n"; -$test++; - -$text = "abc dbf"; -@res = ($text =~ /.*?(b).*?\b/g); -"@res" eq 'b b' or print 'not '; -print "ok $test\n"; -$test++; - -@a = map chr,0..255; - -@b = grep(/\S/,@a); -@c = grep(/[^\s]/,@a); -print "not " if "@b" ne "@c"; -print "ok $test\n"; -$test++; - -@b = grep(/\S/,@a); -@c = grep(/[\S]/,@a); -print "not " if "@b" ne "@c"; -print "ok $test\n"; -$test++; - -@b = grep(/\s/,@a); -@c = grep(/[^\S]/,@a); -print "not " if "@b" ne "@c"; -print "ok $test\n"; -$test++; - -@b = grep(/\s/,@a); -@c = grep(/[\s]/,@a); -print "not " if "@b" ne "@c"; -print "ok $test\n"; -$test++; - -@b = grep(/\D/,@a); -@c = grep(/[^\d]/,@a); -print "not " if "@b" ne "@c"; -print "ok $test\n"; -$test++; - -@b = grep(/\D/,@a); -@c = grep(/[\D]/,@a); -print "not " if "@b" ne "@c"; -print "ok $test\n"; -$test++; - -@b = grep(/\d/,@a); -@c = grep(/[^\D]/,@a); -print "not " if "@b" ne "@c"; -print "ok $test\n"; -$test++; - -@b = grep(/\d/,@a); -@c = grep(/[\d]/,@a); -print "not " if "@b" ne "@c"; -print "ok $test\n"; -$test++; - -@b = grep(/\W/,@a); -@c = grep(/[^\w]/,@a); -print "not " if "@b" ne "@c"; -print "ok $test\n"; -$test++; - -@b = grep(/\W/,@a); -@c = grep(/[\W]/,@a); -print "not " if "@b" ne "@c"; -print "ok $test\n"; -$test++; - -@b = grep(/\w/,@a); -@c = grep(/[^\W]/,@a); -print "not " if "@b" ne "@c"; -print "ok $test\n"; -$test++; - -@b = grep(/\w/,@a); -@c = grep(/[\w]/,@a); -iseq("@b","@c"); - -# see if backtracking optimization works correctly -"\n\n" =~ /\n $ \n/x or print "not "; -print "ok $test\n"; -$test++; - -"\n\n" =~ /\n* $ \n/x or print "not "; -print "ok $test\n"; -$test++; - -"\n\n" =~ /\n+ $ \n/x or print "not "; -print "ok $test\n"; -$test++; - -[] =~ /^ARRAY/ or print "# [] \nnot "; -print "ok $test\n"; -$test++; - -eval << 'EOE'; -{ - package S; - use overload '""' => sub { 'Object S' }; - sub new { bless [] } -} -$a = 'S'->new; -EOE - -$a and $a =~ /^Object\sS/ or print "# '$a' \nnot "; -print "ok $test\n"; -$test++; - -# test result of match used as match (!) -'a1b' =~ ('xyz' =~ /y/) and $` eq 'a' or print "not "; -print "ok $test\n"; -$test++; - -'a1b' =~ ('xyz' =~ /t/) and $` eq 'a' or print "not "; -print "ok $test\n"; -$test++; - -$w = 0; -{ - local $SIG{__WARN__} = sub { $w = 1 }; - local $^W = 1; - $w = 1 if ("1\n" x 102) =~ /^\s*\n/m; -} -print $w ? "not " : "", "ok $test\n"; -$test++; - -my %space = ( spc => " ", - tab => "\t", - cr => "\r", - lf => "\n", - ff => "\f", -# There's no \v but the vertical tabulator seems miraculously -# be 11 both in ASCII and EBCDIC. - vt => chr(11), - false => "space" ); - -my @space0 = sort grep { $space{$_} =~ /\s/ } keys %space; -my @space1 = sort grep { $space{$_} =~ /[[:space:]]/ } keys %space; -my @space2 = sort grep { $space{$_} =~ /[[:blank:]]/ } keys %space; - -print "not " unless "@space0" eq "cr ff lf spc tab"; -print "ok $test # @space0\n"; -$test++; - -print "not " unless "@space1" eq "cr ff lf spc tab vt"; -print "ok $test # @space1\n"; -$test++; - -print "not " unless "@space2" eq "spc tab"; -print "ok $test # @space2\n"; -$test++; - -# bugid 20001021.005 - this caused a SEGV -print "not " unless undef =~ /^([^\/]*)(.*)$/; -print "ok $test\n"; -$test++; - -# bugid 20000731.001 - -print "not " unless "A \x{263a} B z C" =~ /A . B (??{ "z" }) C/; -print "ok $test\n"; -$test++; - -my $ordA = ord('A'); - -$_ = "a\x{100}b"; -if (/(.)(\C)(\C)(.)/) { - print "ok 232\n"; - if ($1 eq "a") { - print "ok 233\n"; - } else { - print "not ok 233\n"; - } - if ($ordA == 65) { # ASCII (or equivalent), should be UTF-8 - if ($2 eq "\xC4") { - print "ok 234\n"; - } else { - print "not ok 234\n"; - } - if ($3 eq "\x80") { - print "ok 235\n"; - } else { - print "not ok 235\n"; - } - } elsif ($ordA == 193) { # EBCDIC (or equivalent), should be UTF-EBCDIC - if ($2 eq "\x8C") { - print "ok 234\n"; - } else { - print "not ok 234\n"; - } - if ($3 eq "\x41") { - print "ok 235\n"; - } else { - print "not ok 235\n"; - } - } else { - for (234..235) { - print "not ok $_ # ord('A') == $ordA\n"; - } - } - if ($4 eq "b") { - print "ok 236\n"; - } else { - print "not ok 236\n"; - } -} else { - for (232..236) { - print "not ok $_\n"; - } -} -$_ = "\x{100}"; -if (/(\C)/g) { - print "ok 237\n"; - # currently \C are still tagged as UTF-8 - if ($ordA == 65) { - if ($1 eq "\xC4") { - print "ok 238\n"; - } else { - print "not ok 238\n"; - } - } elsif ($ordA == 193) { - if ($1 eq "\x8C") { - print "ok 238\n"; - } else { - print "not ok 238\n"; - } - } else { - print "not ok 238 # ord('A') == $ordA\n"; - } -} else { - for (237..238) { - print "not ok $_\n"; - } -} -if (/(\C)/g) { - print "ok 239\n"; - # currently \C are still tagged as UTF-8 - if ($ordA == 65) { - if ($1 eq "\x80") { - print "ok 240\n"; - } else { - print "not ok 240\n"; - } - } elsif ($ordA == 193) { - if ($1 eq "\x41") { - print "ok 240\n"; - } else { - print "not ok 240\n"; - } - } else { - print "not ok 240 # ord('A') == $ordA\n"; - } -} else { - for (239..240) { - print "not ok $_\n"; - } -} + { + $_ = 'aaabbbccc'; + ok /(a*b*)(c*)/ && $1 eq 'aaabbb' && $2 eq 'ccc', + qq [\$_ = '$_'; /(a*b*)(c*)/]; + ok /(a+b+c+)/ && $1 eq 'aaabbbccc', qq [\$_ = '$_'; /(a+b+c+)/]; + nok /a+b?c+/, qq [\$_ = '$_'; /a+b?c+/]; + + $_ = 'aaabccc'; + ok /a+b?c+/, qq [\$_ = '$_'; /a+b?c+/]; + ok /a*b?c*/, qq [\$_ = '$_'; /a*b?c*/]; + + $_ = 'aaaccc'; + ok /a*b?c*/, qq [\$_ = '$_'; /a*b?c*/]; + nok /a*b+c*/, qq [\$_ = '$_'; /a*b+c*/]; + + $_ = 'abcdef'; + ok /bcd|xyz/, qq [\$_ = '$_'; /bcd|xyz/]; + ok /xyz|bcd/, qq [\$_ = '$_'; /xyz|bcd/]; + ok m|bc/*d|, qq [\$_ = '$_'; m|bc/*d|]; + ok /^$_$/, qq [\$_ = '$_'; /^\$_\$/]; + } -{ - # japhy -- added 03/03/2001 - () = (my $str = "abc") =~ /(...)/; - $str = "def"; - print "not " if $1 ne "abc"; - print "ok 241\n"; -} + { + # used to be a test for $* + ok "ab\ncd\n" =~ /^cd/m, qq ["ab\ncd\n" =~ /^cd/m]; + } -# The 242 and 243 go with the 244 and 245. -# The trick is that in EBCDIC the explicit numeric range should match -# (as also in non-EBCDIC) but the explicit alphabetic range should not match. + { + our %XXX = map {($_ => $_)} 123, 234, 345; + + our @XXX = ('ok 1','not ok 1', 'ok 2','not ok 2','not ok 3'); + while ($_ = shift(@XXX)) { + my $f = index ($_, 'not') >= 0 ? \&nok : \&ok; + my $r = ?(.*)?; + &$f ($r, "?(.*)?"); + /not/ && reset; + if (/not ok 2/) { + if ($^O eq 'VMS') { + $_ = shift(@XXX); + } + else { + reset 'X'; + } + } + } -if ("\x8e" =~ /[\x89-\x91]/) { - print "ok 242\n"; -} else { - print "not ok 242\n"; -} + SKIP: { + if ($^O eq 'VMS') { + skip "Reset 'X'", 1; + } + ok !keys %XXX, "%XXX is empty"; + } -if ("\xce" =~ /[\xc9-\xd1]/) { - print "ok 243\n"; -} else { - print "not ok 243\n"; -} + } -# In most places these tests would succeed since \x8e does not -# in most character sets match 'i' or 'j' nor would \xce match -# 'I' or 'J', but strictly speaking these tests are here for -# the good of EBCDIC, so let's test these only there. -if (ord('i') == 0x89 && ord('J') == 0xd1) { # EBCDIC - if ("\x8e" !~ /[i-j]/) { - print "ok 244\n"; - } else { - print "not ok 244\n"; - } - if ("\xce" !~ /[I-J]/) { - print "ok 245\n"; - } else { - print "not ok 245\n"; - } -} else { - for (244..245) { - print "ok $_ # Skip: only in EBCDIC\n"; - } -} + { + local $Message = "Test empty pattern"; + my $xyz = 'xyz'; + my $cde = 'cde'; + + $cde =~ /[^ab]*/; + $xyz =~ //; + iseq $&, $xyz; + + my $foo = '[^ab]*'; + $cde =~ /$foo/; + $xyz =~ //; + iseq $&, $xyz; + + $cde =~ /$foo/; + my $null; + no warnings 'uninitialized'; + $xyz =~ /$null/; + iseq $&, $xyz; + + $null = ""; + $xyz =~ /$null/; + iseq $&, $xyz; + } -print "not " unless "\x{ab}" =~ /\x{ab}/; -print "ok 246\n"; + { + local $Message = q !Check $`, $&, $'!; + $_ = 'abcdefghi'; + /def/; # optimized up to cmd + iseq "$`:$&:$'", 'abc:def:ghi'; -print "not " unless "\x{abcd}" =~ /\x{abcd}/; -print "ok 247\n"; + no warnings 'void'; + /cde/ + 0; # optimized only to spat + iseq "$`:$&:$'", 'ab:cde:fghi'; -{ - # bug id 20001008.001 + /[d][e][f]/; # not optimized + iseq "$`:$&:$'", 'abc:def:ghi'; + } - $test = 248; - my @x = ("stra\337e 138","stra\337e 138"); - for (@x) { - s/(\d+)\s*([\w\-]+)/$1 . uc $2/e; - my($latin) = /^(.+)(?:\s+\d)/; - print $latin eq "stra\337e" ? "ok $test\n" : # 248,249 - "#latin[$latin]\nnot ok $test\n"; - $test++; - $latin =~ s/stra\337e/straße/; # \303\237 after the 2nd a - use utf8; # needed for the raw UTF-8 - $latin =~ s!(s)tr(?:aß|s+e)!$1tr.!; # \303\237 after the a + { + $_ = 'now is the {time for all} good men to come to.'; + / {([^}]*)}/; + iseq $1, 'time for all', "Match braces"; } -} -{ - print "not " unless "ba\xd4c" =~ /([a\xd4]+)/ && $1 eq "a\xd4"; - print "ok 250\n"; + { + local $Message = "{N,M} quantifier"; + $_ = 'xxx {3,4} yyy zzz'; + ok /( {3,4})/; + iseq $1, ' '; + ok !/( {4,})/; + ok /( {2,3}.)/; + iseq $1, ' y'; + ok /(y{2,3}.)/; + iseq $1, 'yyy '; + ok !/x {3,4}/; + ok !/^xxx {3,4}/; + } - print "not " unless "ba\xd4c" =~ /([a\xd4]+)/ && $1 eq "a\x{d4}"; - print "ok 251\n"; + { + local $Message = "Test /g"; + local $" = ":"; + $_ = "now is the time for all good men to come to."; + my @words = /(\w+)/g; + my $exp = "now:is:the:time:for:all:good:men:to:come:to"; - print "not " unless "ba\x{d4}c" =~ /([a\xd4]+)/ && $1 eq "a\x{d4}"; - print "ok 252\n"; + iseq "@words", $exp; - print "not " unless "ba\x{d4}c" =~ /([a\xd4]+)/ && $1 eq "a\xd4"; - print "ok 253\n"; + @words = (); + while (/\w+/g) { + push (@words, $&); + } + iseq "@words", $exp; - print "not " unless "ba\xd4c" =~ /([a\x{d4}]+)/ && $1 eq "a\xd4"; - print "ok 254\n"; + @words = (); + pos = 0; + while (/to/g) { + push(@words, $&); + } + iseq "@words", "to:to"; - print "not " unless "ba\xd4c" =~ /([a\x{d4}]+)/ && $1 eq "a\x{d4}"; - print "ok 255\n"; + pos $_ = 0; + @words = /to/g; + iseq "@words", "to:to"; + } - print "not " unless "ba\x{d4}c" =~ /([a\x{d4}]+)/ && $1 eq "a\x{d4}"; - print "ok 256\n"; + { + $_ = "abcdefghi"; + + my $pat1 = 'def'; + my $pat2 = '^def'; + my $pat3 = '.def.'; + my $pat4 = 'abc'; + my $pat5 = '^abc'; + my $pat6 = 'abc$'; + my $pat7 = 'ghi'; + my $pat8 = '\w*ghi'; + my $pat9 = 'ghi$'; + + my $t1 = my $t2 = my $t3 = my $t4 = my $t5 = + my $t6 = my $t7 = my $t8 = my $t9 = 0; + + for my $iter (1 .. 5) { + $t1++ if /$pat1/o; + $t2++ if /$pat2/o; + $t3++ if /$pat3/o; + $t4++ if /$pat4/o; + $t5++ if /$pat5/o; + $t6++ if /$pat6/o; + $t7++ if /$pat7/o; + $t8++ if /$pat8/o; + $t9++ if /$pat9/o; + } + my $x = "$t1$t2$t3$t4$t5$t6$t7$t8$t9"; + iseq $x, '505550555', "Test /o"; + } - print "not " unless "ba\x{d4}c" =~ /([a\x{d4}]+)/ && $1 eq "a\xd4"; - print "ok 257\n"; -} -{ - # the first half of 20001028.003 + SKIP: { + my $xyz = 'xyz'; + ok "abc" =~ /^abc$|$xyz/, "| after \$"; - my $X = chr(1448); - my ($Y) = $X =~ /(.*)/; - print "not " unless $Y eq v1448 && length($Y) == 1; - print "ok 258\n"; -} + # perl 4.009 says "unmatched ()" + local $Message = '$ inside ()'; -{ - # 20001108.001 + my $result; + eval '"abc" =~ /a(bc$)|$xyz/; $result = "$&:$1"'; + iseq $@, "" or skip "eval failed", 1; + iseq $result, "abc:bc"; + } - my $X = "Szab\x{f3},Bal\x{e1}zs"; - my $Y = $X; - $Y =~ s/(B)/$1/ for 0..3; - print "not " unless $Y eq $X && $X eq "Szab\x{f3},Bal\x{e1}zs"; - print "ok 259\n"; -} -{ - # the second half of 20001028.003 + { + local $Message = "Scalar /g"; + $_ = "abcfooabcbar"; + + ok /abc/g && $` eq ""; + ok /abc/g && $` eq "abcfoo"; + ok !/abc/g; + + local $Message = "Scalar /gi"; + pos = 0; + ok /ABC/gi && $` eq ""; + ok /ABC/gi && $` eq "abcfoo"; + ok !/ABC/gi; + + local $Message = "Scalar /g"; + pos = 0; + ok /abc/g && $' eq "fooabcbar"; + ok /abc/g && $' eq "bar"; + + $_ .= ''; + my @x = /abc/g; + iseq @x, 2, "/g reset after assignment"; + } - my $X = ''; - $X =~ s/^/chr(1488)/e; - print "not " unless length $X == 1 && ord($X) == 1488; - print "ok 260\n"; -} + { + local $Message = '/g, \G and pos'; + $_ = "abdc"; + pos $_ = 2; + /\Gc/gc; + iseq pos $_, 2; + /\Gc/g; + ok !defined pos $_; + } -{ - # 20000517.001 + { + local $Message = '(?{ })'; + our $out = 1; + 'abc' =~ m'a(?{ $out = 2 })b'; + iseq $out, 2; + + $out = 1; + 'abc' =~ m'a(?{ $out = 3 })c'; + iseq $out, 1; + } - my $x = "\x{100}A"; - $x =~ s/A/B/; + { + $_ = 'foobar1 bar2 foobar3 barfoobar5 foobar6'; + my @out = /(?<!foo)bar./g; + iseq "@out", 'bar2 barf', "Negative lookbehind"; + } - print "not " unless $x eq "\x{100}B" && length($x) == 2; - print "ok 261\n"; -} + { + local $Message = "REG_INFTY tests"; + # Tests which depend on REG_INFTY + $::reg_infty = $Config {reg_infty} // 32767; + $::reg_infty_m = $::reg_infty - 1; + $::reg_infty_p = $::reg_infty + 1; + $::reg_infty_m = $::reg_infty_m; # Surpress warning. + + # As well as failing if the pattern matches do unexpected things, the + # next three tests will fail if you should have picked up a lower-than- + # default value for $reg_infty from Config.pm, but have not. + + eval_ok q (('aaa' =~ /(a{1,$::reg_infty_m})/)[0] eq 'aaa'); + eval_ok q (('a' x $::reg_infty_m) =~ /a{$::reg_infty_m}/); + eval_ok q (('a' x ($::reg_infty_m - 1)) !~ /a{$::reg_infty_m}/); + eval "'aaa' =~ /a{1,$::reg_infty}/"; + ok $@ =~ /^\QQuantifier in {,} bigger than/; + eval "'aaa' =~ /a{1,$::reg_infty_p}/"; + ok $@ =~ /^\QQuantifier in {,} bigger than/; + } -{ - # bug id 20001230.002 + { + # Poke a couple more parse failures + my $context = 'x' x 256; + eval qq("${context}y" =~ /(?<=$context)y/); + ok $@ =~ /^\QLookbehind longer than 255 not/, "Lookbehind limit"; + } - print "not " unless "École" =~ /^\C\C(.)/ && $1 eq 'c'; - print "ok 262\n"; + { + # Long Monsters + local $Message = "Long monster"; + for my $l (125, 140, 250, 270, 300000, 30) { # Ordered to free memory + my $a = 'a' x $l; + local $Error = "length = $l"; + ok "ba$a=" =~ /a$a=/; + nok "b$a=" =~ /a$a=/; + ok "b$a=" =~ /ba+=/; + + ok "ba$a=" =~ /b(?:a|b)+=/; + } + } - print "not " unless "École" =~ /^\C\C(c)/; - print "ok 263\n"; -} -SKIP: { - $test = 264; # till 575 - - use charnames ":full"; - - # This is far from complete testing, there are dozens of character - # classes in Unicode. The mixing of literals and \N{...} is - # intentional so that in non-Latin-1 places we test the native - # characters, not the Unicode code points. - - my %s = ( - "a" => 'Ll', - "\N{CYRILLIC SMALL LETTER A}" => 'Ll', - "A" => 'Lu', - "\N{GREEK CAPITAL LETTER ALPHA}" => 'Lu', - "\N{HIRAGANA LETTER SMALL A}" => 'Lo', - "\N{COMBINING GRAVE ACCENT}" => 'Mn', - "0" => 'Nd', - "\N{ARABIC-INDIC DIGIT ZERO}" => 'Nd', - "_" => 'N', - "!" => 'P', - " " => 'Zs', - "\0" => 'Cc', - ); - - for my $char (map { s/^\S+ //; $_ } - sort map { sprintf("%06x", ord($_))." $_" } keys %s) { - my $class = $s{$char}; - my $code = sprintf("%06x", ord($char)); - printf "#\n# 0x$code\n#\n"; - print "# IsAlpha\n"; - if ($class =~ /^[LM]/) { - print "not " unless $char =~ /\p{IsAlpha}/; - print "ok $test\n"; $test++; - print "not " if $char =~ /\P{IsAlpha}/; - print "ok $test\n"; $test++; - } else { - print "not " if $char =~ /\p{IsAlpha}/; - print "ok $test\n"; $test++; - print "not " unless $char =~ /\P{IsAlpha}/; - print "ok $test\n"; $test++; - } - print "# IsAlnum\n"; - if ($class =~ /^[LMN]/ && $char ne "_") { - print "not " unless $char =~ /\p{IsAlnum}/; - print "ok $test\n"; $test++; - print "not " if $char =~ /\P{IsAlnum}/; - print "ok $test\n"; $test++; - } else { - print "not " if $char =~ /\p{IsAlnum}/; - print "ok $test\n"; $test++; - print "not " unless $char =~ /\P{IsAlnum}/; - print "ok $test\n"; $test++; - } - print "# IsASCII\n"; - if (ord("A") == 193) { - print "ok $test # Skip: in EBCDIC\n"; $test++; - print "ok $test # Skip: in EBCDIC\n"; $test++; - } else { - if ($code le '00007f') { - print "not " unless $char =~ /\p{IsASCII}/; - print "ok $test\n"; $test++; - print "not " if $char =~ /\P{IsASCII}/; - print "ok $test\n"; $test++; - } else { - print "not " if $char =~ /\p{IsASCII}/; - print "ok $test\n"; $test++; - print "not " unless $char =~ /\P{IsASCII}/; - print "ok $test\n"; $test++; - } - } - print "# IsCntrl\n"; - if ($class =~ /^C/) { - print "not " unless $char =~ /\p{IsCntrl}/; - print "ok $test\n"; $test++; - print "not " if $char =~ /\P{IsCntrl}/; - print "ok $test\n"; $test++; - } else { - print "not " if $char =~ /\p{IsCntrl}/; - print "ok $test\n"; $test++; - print "not " unless $char =~ /\P{IsCntrl}/; - print "ok $test\n"; $test++; - } - print "# IsBlank\n"; - if ($class =~ /^Z[lp]/ || $char eq " ") { - print "not " unless $char =~ /\p{IsBlank}/; - print "ok $test\n"; $test++; - print "not " if $char =~ /\P{IsBlank}/; - print "ok $test\n"; $test++; - } else { - print "not " if $char =~ /\p{IsBlank}/; - print "ok $test\n"; $test++; - print "not " unless $char =~ /\P{IsBlank}/; - print "ok $test\n"; $test++; - } - print "# IsDigit\n"; - if ($class =~ /^Nd$/) { - print "not " unless $char =~ /\p{IsDigit}/; - print "ok $test\n"; $test++; - print "not " if $char =~ /\P{IsDigit}/; - print "ok $test\n"; $test++; - } else { - print "not " if $char =~ /\p{IsDigit}/; - print "ok $test\n"; $test++; - print "not " unless $char =~ /\P{IsDigit}/; - print "ok $test\n"; $test++; - } - print "# IsGraph\n"; - if ($class =~ /^([LMNPS])|Co/) { - print "not " unless $char =~ /\p{IsGraph}/; - print "ok $test\n"; $test++; - print "not " if $char =~ /\P{IsGraph}/; - print "ok $test\n"; $test++; - } else { - print "not " if $char =~ /\p{IsGraph}/; - print "ok $test\n"; $test++; - print "not " unless $char =~ /\P{IsGraph}/; - print "ok $test\n"; $test++; - } - print "# IsLower\n"; - if ($class =~ /^Ll$/) { - print "not " unless $char =~ /\p{IsLower}/; - print "ok $test\n"; $test++; - print "not " if $char =~ /\P{IsLower}/; - print "ok $test\n"; $test++; - } else { - print "not " if $char =~ /\p{IsLower}/; - print "ok $test\n"; $test++; - print "not " unless $char =~ /\P{IsLower}/; - print "ok $test\n"; $test++; - } - print "# IsPrint\n"; - if ($class =~ /^([LMNPS])|Co|Zs/) { - print "not " unless $char =~ /\p{IsPrint}/; - print "ok $test\n"; $test++; - print "not " if $char =~ /\P{IsPrint}/; - print "ok $test\n"; $test++; - } else { - print "not " if $char =~ /\p{IsPrint}/; - print "ok $test\n"; $test++; - print "not " unless $char =~ /\P{IsPrint}/; - print "ok $test\n"; $test++; - } - print "# IsPunct\n"; - if ($class =~ /^P/ || $char eq "_") { - print "not " unless $char =~ /\p{IsPunct}/; - print "ok $test\n"; $test++; - print "not " if $char =~ /\P{IsPunct}/; - print "ok $test\n"; $test++; - } else { - print "not " if $char =~ /\p{IsPunct}/; - print "ok $test\n"; $test++; - print "not " unless $char =~ /\P{IsPunct}/; - print "ok $test\n"; $test++; - } - print "# IsSpace\n"; - if ($class =~ /^Z/ || ($code =~ /^(0009|000A|000B|000C|000D)$/)) { - print "not " unless $char =~ /\p{IsSpace}/; - print "ok $test\n"; $test++; - print "not " if $char =~ /\P{IsSpace}/; - print "ok $test\n"; $test++; - } else { - print "not " if $char =~ /\p{IsSpace}/; - print "ok $test\n"; $test++; - print "not " unless $char =~ /\P{IsSpace}/; - print "ok $test\n"; $test++; - } - print "# IsUpper\n"; - if ($class =~ /^L[ut]/) { - print "not " unless $char =~ /\p{IsUpper}/; - print "ok $test\n"; $test++; - print "not " if $char =~ /\P{IsUpper}/; - print "ok $test\n"; $test++; - } else { - print "not " if $char =~ /\p{IsUpper}/; - print "ok $test\n"; $test++; - print "not " unless $char =~ /\P{IsUpper}/; - print "ok $test\n"; $test++; - } - print "# IsWord\n"; - if ($class =~ /^[LMN]/ || $char eq "_") { - print "not " unless $char =~ /\p{IsWord}/; - print "ok $test\n"; $test++; - print "not " if $char =~ /\P{IsWord}/; - print "ok $test\n"; $test++; - } else { - print "not " if $char =~ /\p{IsWord}/; - print "ok $test\n"; $test++; - print "not " unless $char =~ /\P{IsWord}/; - print "ok $test\n"; $test++; - } + { + # 20000 nodes, each taking 3 words per string, and 1 per branch + my $long_constant_len = join '|', 12120 .. 32645; + my $long_var_len = join '|', 8120 .. 28645; + my %ans = ( 'ax13876y25677lbc' => 1, + 'ax13876y25677mcb' => 0, # not b. + 'ax13876y35677nbc' => 0, # Num too big + 'ax13876y25677y21378obc' => 1, + 'ax13876y25677y21378zbc' => 0, # Not followed by [k-o] + 'ax13876y25677y21378y21378kbc' => 1, + 'ax13876y25677y21378y21378kcb' => 0, # Not b. + 'ax13876y25677y21378y21378y21378kbc' => 0, # 5 runs + ); + + local $Message = "20000 nodes"; + for (keys %ans) { + local $Error = "const-len '$_'"; + ok !($ans{$_} xor /a(?=([yx]($long_constant_len)){2,4}[k-o]).*b./o); + + local $Error = "var-len '$_'"; + ok !($ans{$_} xor /a(?=([yx]($long_var_len)){2,4}[k-o]).*b./o); + } } -} -{ - $_ = "abc\x{100}\x{200}\x{300}\x{380}\x{400}defg"; + { + local $Message = "Complicated backtracking"; + $_ = " a (bla()) and x(y b((l)u((e))) and b(l(e)e)e"; + my $expect = "(bla()) ((l)u((e))) (l(e)e)"; + + use vars '$c'; + sub matchit { + m/ + ( + \( + (?{ $c = 1 }) # Initialize + (?: + (?(?{ $c == 0 }) # PREVIOUS iteration was OK, stop the loop + (?! + ) # Fail: will unwind one iteration back + ) + (?: + [^()]+ # Match a big chunk + (?= + [()] + ) # Do not try to match subchunks + | + \( + (?{ ++$c }) + | + \) + (?{ --$c }) + ) + )+ # This may not match with different subblocks + ) + (?(?{ $c != 0 }) + (?! + ) # Fail + ) # Otherwise the chunk 1 may succeed with $c>0 + /xg; + } + + my @ans = (); + my $res; + push @ans, $res while $res = matchit; + iseq "@ans", "1 1 1"; + + @ans = matchit; + iseq "@ans", $expect; - if (/(.\x{300})./) { - print "ok 576\n"; + local $Message = "Recursion with (??{ })"; + our $matched; + $matched = qr/\((?:(?>[^()]+)|(??{$matched}))*\)/; - print "not " unless $` eq "abc\x{100}" && length($`) == 4; - print "ok 577\n"; + @ans = my @ans1 = (); + push (@ans, $res), push (@ans1, $&) while $res = m/$matched/g; - print "not " unless $& eq "\x{200}\x{300}\x{380}" && length($&) == 3; - print "ok 578\n"; + iseq "@ans", "1 1 1"; + iseq "@ans1", $expect; - print "not " unless $' eq "\x{400}defg" && length($') == 5; - print "ok 579\n"; + @ans = m/$matched/g; + iseq "@ans", $expect; - print "not " unless $1 eq "\x{200}\x{300}" && length($1) == 2; - print "ok 580\n"; - } else { - for (576..580) { print "not ok $_\n" } } -} -{ - # bug id 20010306.008 + { + ok "abc" =~ /^(??{"a"})b/, '"abc" =~ /^(??{"a"})b/'; + } - $a = "a\x{1234}"; - # The original bug report had 'no utf8' here but that was irrelevant. - $a =~ m/\w/; # used to core dump + { + my @ans = ('a/b' =~ m%(.*/)?(.*)%); # Stack may be bad + iseq "@ans", 'a/ b', "Stack may be bad"; + } - print "ok 581\n"; -} + { + local $Message = "Eval-group not allowed at runtime"; + my $code = '{$blah = 45}'; + our $blah = 12; + eval { /(?$code)/ }; + ok $@ && $@ =~ /not allowed at runtime/ && $blah == 12; + + for $code ('{$blah = 45}','=xx') { + $blah = 12; + my $res = eval { "xx" =~ /(?$code)/o }; + no warnings 'uninitialized'; + local $Error = "'$@', '$res', '$blah'"; + if ($code eq '=xx') { + ok !$@ && $res; + } + else { + ok $@ && $@ =~ /not allowed at runtime/ && $blah == 12; + } + } -{ - $test = 582; + $code = '{$blah = 45}'; + $blah = 12; + eval "/(?$code)/"; + iseq $blah, 45; + + $blah = 12; + /(?{$blah = 45})/; + iseq $blah, 45; + } - # bugid 20010410.006 - for my $rx ( - '/(.*?)\{(.*?)\}/csg', - '/(.*?)\{(.*?)\}/cg', - '/(.*?)\{(.*?)\}/sg', - '/(.*?)\{(.*?)\}/g', - '/(.+?)\{(.+?)\}/csg', - ) { - my($input, $i); + local $Message = "Pos checks"; + my $x = 'banana'; + $x =~ /.a/g; + iseq pos ($x), 2; - $i = 0; - $input = "a{b}c{d}"; - eval <<EOT; - while (eval \$input =~ $rx) { - print "# \\\$1 = '\$1' \\\$2 = '\$2'\n"; - ++\$i; - } -EOT - print "not " unless $i == 2; - print "ok " . $test++ . "\n"; + $x =~ /.z/gc; + iseq pos ($x), 2; + + sub f { + my $p = $_[0]; + return $p; + } + + $x =~ /.a/g; + iseq f (pos ($x)), 4; } -} -{ - # from Robin Houston + { + local $Message = 'Checking $^R'; + our $x = $^R = 67; + 'foot' =~ /foo(?{$x = 12; 75})[t]/; + iseq $^R, 75; + + $x = $^R = 67; + 'foot' =~ /foo(?{$x = 12; 75})[xy]/; + ok $^R eq '67' && $x eq '12'; + + $x = $^R = 67; + 'foot' =~ /foo(?{ $^R + 12 })((?{ $x = 12; $^R + 17 })[xy])?/; + ok $^R eq '79' && $x eq '12'; + } - my $x = "\x{10FFFD}"; - $x =~ s/(.)/$1/g; - print "not " unless ord($x) == 0x10FFFD && length($x) == 1; - print "ok 587\n"; -} + { + iseq qr/\b\v$/i, '(?i-xsm:\b\v$)', 'qr/\b\v$/i'; + iseq qr/\b\v$/s, '(?s-xim:\b\v$)', 'qr/\b\v$/s'; + iseq qr/\b\v$/m, '(?m-xis:\b\v$)', 'qr/\b\v$/m'; + iseq qr/\b\v$/x, '(?x-ism:\b\v$)', 'qr/\b\v$/x'; + iseq qr/\b\v$/xism, '(?msix:\b\v$)', 'qr/\b\v$/xism'; + iseq qr/\b\v$/, '(?-xism:\b\v$)', 'qr/\b\v$/'; + } -{ - my $x = "\x7f"; - print "not " if $x =~ /[\x80-\xff]/; - print "ok 588\n"; + { + local $Message = "Look around"; + $_ = 'xabcx'; + SKIP: + foreach my $ans ('', 'c') { + ok /(?<=(?=a)..)((?=c)|.)/g or skip "Match failed", 1; + iseq $1, $ans; + } + } - print "not " if $x =~ /[\x80-\x{100}]/; - print "ok 589\n"; + { + local $Message = "Empty clause"; + $_ = 'a'; + foreach my $ans ('', 'a', '') { + ok /^|a|$/g or skip "Match failed", 1; + iseq $&, $ans; + } + } - print "not " if $x =~ /[\x{100}]/; - print "ok 590\n"; + { + local $Message = "Prefixify"; + sub prefixify { + SKIP: { + my ($v, $a, $b, $res) = @_; + ok $v =~ s/\Q$a\E/$b/ or skip "Match failed", 1; + iseq $v, $res; + } + } - print "not " if $x =~ /\p{InLatin1Supplement}/; - print "ok 591\n"; + prefixify ('/a/b/lib/arch', "/a/b/lib", 'X/lib', 'X/lib/arch'); + prefixify ('/a/b/man/arch', "/a/b/man", 'X/man', 'X/man/arch'); + } - print "not " unless $x =~ /\P{InLatin1Supplement}/; - print "ok 592\n"; + { + $_ = 'var="foo"'; + /(\")/; + ok $1 && /$1/, "Capture a quote"; + } - print "not " if $x =~ /\p{InLatinExtendedA}/; - print "ok 593\n"; + { + local $Message = "Call code from qr //"; + $a = qr/(?{++$b})/; + $b = 7; + ok /$a$a/ && $b eq '9'; + + $c="$a"; + ok /$a$a/ && $b eq '11'; + + undef $@; + eval {/$c/}; + ok $@ && $@ =~ /not allowed at runtime/; + + use re "eval"; + /$a$c$a/; + iseq $b, '14'; + + our $lex_a = 43; + our $lex_b = 17; + our $lex_c = 27; + my $lex_res = ($lex_b =~ qr/$lex_b(?{ $lex_c = $lex_a++ })/); + + iseq $lex_res, 1; + iseq $lex_a, 44; + iseq $lex_c, 43; + + no re "eval"; + undef $@; + my $match = eval { /$a$c$a/ }; + ok $@ && $@ =~ /Eval-group not allowed/ && !$match; + iseq $b, '14'; + + $lex_a = 2; + $lex_a = 43; + $lex_b = 17; + $lex_c = 27; + $lex_res = ($lex_b =~ qr/17(?{ $lex_c = $lex_a++ })/); + + iseq $lex_res, 1; + iseq $lex_a, 44; + iseq $lex_c, 43; - print "not " unless $x =~ /\P{InLatinExtendedA}/; - print "ok 594\n"; -} + } -{ - my $x = "\x80"; - print "not " unless $x =~ /[\x80-\xff]/; - print "ok 595\n"; + { + no warnings 'closure'; + local $Message = '(?{ $var } refers to package vars'; + package aa; + our $c = 2; + $::c = 3; + '' =~ /(?{ $c = 4 })/; + main::iseq $c, 4; + main::iseq $::c, 3; + } - print "not " unless $x =~ /[\x80-\x{100}]/; - print "ok 596\n"; - print "not " if $x =~ /[\x{100}]/; - print "ok 597\n"; + { + must_die 'q(a:[b]:) =~ /[x[:foo:]]/', + 'POSIX class \[:[^:]+:\] unknown in regex', + 'POSIX class [: :] must have valid name'; + + for my $d (qw [= .]) { + must_die "/[[${d}foo${d}]]/", + "\QPOSIX syntax [$d $d] is reserved for future extensions", + "POSIX syntax [[$d $d]] is an error"; + } + } - print "not " unless $x =~ /\p{InLatin1Supplement}/; - print "ok 598\n"; - print "not " if $x =~ /\P{InLatin1Supplement}/; - print "ok 599\n"; + { + # test if failure of patterns returns empty list + local $Message = "Failed pattern returns empty list"; + $_ = 'aaa'; + @_ = /bbb/; + iseq "@_", ""; - print "not " if $x =~ /\p{InLatinExtendedA}/; - print "ok 600\n"; + @_ = /bbb/g; + iseq "@_", ""; - print "not " unless $x =~ /\P{InLatinExtendedA}/; - print "ok 601\n"; -} + @_ = /(bbb)/; + iseq "@_", ""; -{ - my $x = "\xff"; + @_ = /(bbb)/g; + iseq "@_", ""; + } - print "not " unless $x =~ /[\x80-\xff]/; - print "ok 602\n"; + + { + local $Message = '@- and @+ tests'; + + /a(?=.$)/; + iseq $#+, 0; + iseq $#-, 0; + iseq $+ [0], 2; + iseq $- [0], 1; + ok !defined $+ [1] && !defined $- [1] && + !defined $+ [2] && !defined $- [2]; + + /a(a)(a)/; + iseq $#+, 2; + iseq $#-, 2; + iseq $+ [0], 3; + iseq $- [0], 0; + iseq $+ [1], 2; + iseq $- [1], 1; + iseq $+ [2], 3; + iseq $- [2], 2; + ok !defined $+ [3] && !defined $- [3] && + !defined $+ [4] && !defined $- [4]; + + + /.(a)(b)?(a)/; + iseq $#+, 3; + iseq $#-, 3; + iseq $+ [1], 2; + iseq $- [1], 1; + iseq $+ [3], 3; + iseq $- [3], 2; + ok !defined $+ [2] && !defined $- [2] && + !defined $+ [4] && !defined $- [4]; + + + /.(a)/; + iseq $#+, 1; + iseq $#-, 1; + iseq $+ [0], 2; + iseq $- [0], 0; + iseq $+ [1], 2; + iseq $- [1], 1; + ok !defined $+ [2] && !defined $- [2] && + !defined $+ [3] && !defined $- [3]; + + /.(a)(ba*)?/; + iseq $#+, 2; + iseq $#-, 1; + } - print "not " unless $x =~ /[\x80-\x{100}]/; - print "ok 603\n"; - print "not " if $x =~ /[\x{100}]/; - print "ok 604\n"; + { + local $DiePattern = '^Modification of a read-only value attempted'; + local $Message = 'Elements of @- and @+ are read-only'; + must_die '$+[0] = 13'; + must_die '$-[0] = 13'; + must_die '@+ = (7, 6, 5)'; + must_die '@- = qw (foo bar)'; + } - # the next two tests must be ignored on EBCDIC - print "not " unless $x =~ /\p{InLatin1Supplement}/ or ord("A") == 193; - print "ok 605\n"; - print "not " if $x =~ /\P{InLatin1Supplement}/ and ord("A") != 193; - print "ok 606\n"; + { + local $Message = '\G testing'; + $_ = 'aaa'; + pos = 1; + my @a = /\Ga/g; + iseq "@a", "a a"; + + my $str = 'abcde'; + pos $str = 2; + ok $str !~ /^\G/; + ok $str !~ /^.\G/; + ok $str =~ /^..\G/; + ok $str !~ /^...\G/; + ok $str =~ /\G../ && $& eq 'cd'; + + local $TODO = $running_as_thread; + ok $str =~ /.\G./ && $& eq 'bc'; + } - print "not " if $x =~ /\p{InLatinExtendedA}/; - print "ok 607\n"; - print "not " unless $x =~ /\P{InLatinExtendedA}/; - print "ok 608\n"; -} + { + local $Message = 'pos inside (?{ })'; + my $str = 'abcde'; + our ($foo, $bar); + ok $str =~ /b(?{$foo = $_; $bar = pos})c/; + iseq $foo, $str; + iseq $bar, 2; + ok !defined pos ($str); + + undef $foo; + undef $bar; + pos $str = undef; + ok $str =~ /b(?{$foo = $_; $bar = pos})c/g; + iseq $foo, $str; + iseq $bar, 2; + iseq pos ($str), 3; + + $_ = $str; + undef $foo; + undef $bar; + ok /b(?{$foo = $_; $bar = pos})c/; + iseq $foo, $str; + iseq $bar, 2; + + undef $foo; + undef $bar; + ok /b(?{$foo = $_; $bar = pos})c/g; + iseq $foo, $str; + iseq $bar, 2; + iseq pos, 3; + + undef $foo; + undef $bar; + pos = undef; + 1 while /b(?{$foo = $_; $bar = pos})c/g; + iseq $foo, $str; + iseq $bar, 2; + ok !defined pos; + + undef $foo; + undef $bar; + $_ = 'abcde|abcde'; + ok s/b(?{$foo = $_; $bar = pos})c/x/g; + iseq $foo, 'abcde|abcde'; + iseq $bar, 8; + iseq $_, 'axde|axde'; + + # List context: + $_ = 'abcde|abcde'; + our @res; + () = /([ace]).(?{push @res, $1,$2})([ce])(?{push @res, $1,$2})/g; + @res = map {defined $_ ? "'$_'" : 'undef'} @res; + iseq "@res", "'a' undef 'a' 'c' 'e' undef 'a' undef 'a' 'c'"; + + @res = (); + () = /([ace]).(?{push @res, $`,$&,$'})([ce])(?{push @res, $`,$&,$'})/g; + @res = map {defined $_ ? "'$_'" : 'undef'} @res; + iseq "@res", "'' 'ab' 'cde|abcde' " . + "'' 'abc' 'de|abcde' " . + "'abcd' 'e|' 'abcde' " . + "'abcde|' 'ab' 'cde' " . + "'abcde|' 'abc' 'de'" ; + } -{ - my $x = "\x{100}"; - print "not " if $x =~ /[\x80-\xff]/; - print "ok 609\n"; + { + local $Message = '\G anchor checks'; + my $foo = 'aabbccddeeffgg'; + pos ($foo) = 1; + { + local $TODO = $running_as_thread; + no warnings 'uninitialized'; + ok $foo =~ /.\G(..)/g; + iseq $1, 'ab'; - print "not " unless $x =~ /[\x80-\x{100}]/; - print "ok 610\n"; + pos ($foo) += 1; + ok $foo =~ /.\G(..)/g; + iseq $1, 'cc'; - print "not " unless $x =~ /[\x{100}]/; - print "ok 611\n"; + pos ($foo) += 1; + ok $foo =~ /.\G(..)/g; + iseq $1, 'de'; - print "not " if $x =~ /\p{InLatin1Supplement}/; - print "ok 612\n"; + ok $foo =~ /\Gef/g; + } - print "not " unless $x =~ /\P{InLatin1Supplement}/; - print "ok 613\n"; + undef pos $foo; + ok $foo =~ /\G(..)/g; + iseq $1, 'aa'; - print "not " unless $x =~ /\p{InLatinExtendedA}/; - print "ok 614\n"; + ok $foo =~ /\G(..)/g; + iseq $1, 'bb'; - print "not " if $x =~ /\P{InLatinExtendedA}/; - print "ok 615\n"; -} + pos ($foo) = 5; + ok $foo =~ /\G(..)/g; + iseq $1, 'cd'; + } -{ - # from japhy - my $w; - use warnings; - local $SIG{__WARN__} = sub { $w .= shift }; - - $w = ""; - eval 'qr/(?c)/'; - print "not " if $w !~ /^Useless \(\?c\)/; - print "ok 616\n"; - - $w = ""; - eval 'qr/(?-c)/'; - print "not " if $w !~ /^Useless \(\?-c\)/; - print "ok 617\n"; - - $w = ""; - eval 'qr/(?g)/'; - print "not " if $w !~ /^Useless \(\?g\)/; - print "ok 618\n"; - - $w = ""; - eval 'qr/(?-g)/'; - print "not " if $w !~ /^Useless \(\?-g\)/; - print "ok 619\n"; - - $w = ""; - eval 'qr/(?o)/'; - print "not " if $w !~ /^Useless \(\?o\)/; - print "ok 620\n"; - - $w = ""; - eval 'qr/(?-o)/'; - print "not " if $w !~ /^Useless \(\?-o\)/; - print "ok 621\n"; - - # now test multi-error regexes - - $w = ""; - eval 'qr/(?g-o)/'; - print "not " if $w !~ /^Useless \(\?g\).*\nUseless \(\?-o\)/; - print "ok 622\n"; - - $w = ""; - eval 'qr/(?g-c)/'; - print "not " if $w !~ /^Useless \(\?g\).*\nUseless \(\?-c\)/; - print "ok 623\n"; - - $w = ""; - eval 'qr/(?o-cg)/'; # (?c) means (?g) error won't be thrown - print "not " if $w !~ /^Useless \(\?o\).*\nUseless \(\?-c\)/; - print "ok 624\n"; - - $w = ""; - eval 'qr/(?ogc)/'; - print "not " if $w !~ /^Useless \(\?o\).*\nUseless \(\?g\).*\nUseless \(\?c\)/; - print "ok 625\n"; -} -# More Unicode "class" tests + { + $_ = '123x123'; + my @res = /(\d*|x)/g; + local $" = '|'; + iseq "@res", "123||x|123|", "0 match in alternation"; + } -{ - use charnames ':full'; - print "not " unless "\N{LATIN CAPITAL LETTER A}" =~ /\p{InBasicLatin}/; - print "ok 626\n"; + { + local $Message = "Match against temporaries (created via pp_helem())" . + " is safe"; + ok {foo => "bar\n" . $^X} -> {foo} =~ /^(.*)\n/g; + iseq $1, "bar"; + } - print "not " unless "\N{LATIN CAPITAL LETTER A WITH GRAVE}" =~ /\p{InLatin1Supplement}/; - print "ok 627\n"; - print "not " unless "\N{LATIN CAPITAL LETTER A WITH MACRON}" =~ /\p{InLatinExtendedA}/; - print "ok 628\n"; + { + local $Message = 'package $i inside (?{ }), ' . + 'saved substrings and changing $_'; + our @a = qw [foo bar]; + our @b = (); + s/(\w)(?{push @b, $1})/,$1,/g for @a; + iseq "@b", "f o o b a r"; + iseq "@a", ",f,,o,,o, ,b,,a,,r,"; + + local $Message = 'lexical $i inside (?{ }), ' . + 'saved substrings and changing $_'; + no warnings 'closure'; + my @c = qw [foo bar]; + my @d = (); + s/(\w)(?{push @d, $1})/,$1,/g for @c; + iseq "@d", "f o o b a r"; + iseq "@c", ",f,,o,,o, ,b,,a,,r,"; + } - print "not " unless "\N{LATIN SMALL LETTER B WITH STROKE}" =~ /\p{InLatinExtendedB}/; - print "ok 629\n"; - print "not " unless "\N{KATAKANA LETTER SMALL A}" =~ /\p{InKatakana}/; - print "ok 630\n"; -} + { + local $Message = 'Brackets'; + our $brackets; + $brackets = qr { + { (?> [^{}]+ | (??{ $brackets }) )* } + }x; + + ok "{{}" =~ $brackets; + iseq $&, "{}"; + ok "something { long { and } hairy" =~ $brackets; + iseq $&, "{ and }"; + ok "something { long { and } hairy" =~ m/((??{ $brackets }))/; + iseq $&, "{ and }"; + } -$_ = "foo"; - -eval <<"EOT"; die if $@; - /f - o\r - o - \$ - /x && print "ok 631\n"; -EOT - -eval <<"EOT"; die if $@; - /f - o - o - \$\r - /x && print "ok 632\n"; -EOT - -#test /o feature -sub test_o { $_[0] =~/$_[1]/o; return $1} -if(test_o('abc','(.)..') eq 'a') { - print "ok 633\n"; -} else { - print "not ok 633\n"; -} -if(test_o('abc','..(.)') eq 'a') { - print "ok 634\n"; -} else { - print "not ok 634\n"; -} -# 635..639: ID 20010619.003 (only the space character is -# supposed to be [:print:], not the whole isprint()). - -print "not " if "\n" =~ /[[:print:]]/; -print "ok 635\n"; - -print "not " if "\t" =~ /[[:print:]]/; -print "ok 636\n"; - -# Amazingly vertical tabulator is the same in ASCII and EBCDIC. -print "not " if "\014" =~ /[[:print:]]/; -print "ok 637\n"; - -print "not " if "\r" =~ /[[:print:]]/; -print "ok 638\n"; - -print "not " unless " " =~ /[[:print:]]/; -print "ok 639\n"; - -## -## Test basic $^N usage outside of a regex -## -$x = "abcdef"; -$T="ok 640\n";if ($x =~ /cde/ and not defined $^N) {print $T} else {print "not $T"}; -$T="ok 641\n";if ($x =~ /(cde)/ and $^N eq "cde") {print $T} else {print "not $T"}; -$T="ok 642\n";if ($x =~ /(c)(d)(e)/ and $^N eq "e") {print $T} else {print "not $T"}; -$T="ok 643\n";if ($x =~ /(c(d)e)/ and $^N eq "cde") {print $T} else {print "not $T"}; -$T="ok 644\n";if ($x =~ /(foo)|(c(d)e)/ and $^N eq "cde") {print $T} else {print "not $T"}; -$T="ok 645\n";if ($x =~ /(c(d)e)|(foo)/ and $^N eq "cde") {print $T} else {print "not $T"}; -$T="ok 646\n";if ($x =~ /(c(d)e)|(abc)/ and $^N eq "abc") {print $T} else {print "not $T"}; -$T="ok 647\n";if ($x =~ /(c(d)e)|(abc)x/ and $^N eq "cde") {print $T} else {print "not $T"}; -$T="ok 648\n";if ($x =~ /(c(d)e)(abc)?/ and $^N eq "cde") {print $T} else {print "not $T"}; -$T="ok 649\n";if ($x =~ /(?:c(d)e)/ and $^N eq "d" ) {print $T} else {print "not $T"}; -$T="ok 650\n";if ($x =~ /(?:c(d)e)(?:f)/ and $^N eq "d" ) {print $T} else {print "not $T"}; -$T="ok 651\n";if ($x =~ /(?:([abc])|([def]))*/ and $^N eq "f" ){print $T} else {print "not $T"}; -$T="ok 652\n";if ($x =~ /(?:([ace])|([bdf]))*/ and $^N eq "f" ){print $T} else {print "not $T"}; -$T="ok 653\n";if ($x =~ /(([ace])|([bd]))*/ and $^N eq "e" ){print $T} else {print "not $T"}; -{ - $T="ok 654\n";if($x =~ /(([ace])|([bdf]))*/ and $^N eq "f" ){print $T} else {print "not $T"}; -} -## test to see if $^N is automatically localized -- it should now -## have the value set in test 653 -$T="ok 655\n";if ($^N eq "e" ){print $T} else {print "not $T"}; - -## -## Now test inside (?{...}) -## -$T="ok 656\n";if ($x =~ /a([abc])(?{$y=$^N})c/ and $y eq "b" ){print $T} else {print "not $T"}; -$T="ok 657\n";if ($x =~ /a([abc]+)(?{$y=$^N})d/ and $y eq "bc"){print $T} else {print "not $T"}; -$T="ok 658\n";if ($x =~ /a([abcdefg]+)(?{$y=$^N})d/ and $y eq "bc"){print $T} else {print "not $T"}; -$T="ok 659\n";if ($x =~ /(a([abcdefg]+)(?{$y=$^N})d)(?{$z=$^N})e/ and $y eq "bc" and $z eq "abcd") - {print $T} else {print "not $T"}; -$T="ok 660\n";if ($x =~ /(a([abcdefg]+)(?{$y=$^N})de)(?{$z=$^N})/ and $y eq "bc" and $z eq "abcde") - {print $T} else {print "not $T"}; - -# Test the Unicode script classes - -print "not " unless chr(0x100) =~ /\p{IsLatin}/; # outside Latin-1 -print "ok 661\n"; - -print "not " unless chr(0x212b) =~ /\p{IsLatin}/; # Angstrom sign, very outside -print "ok 662\n"; - -print "not " unless chr(0x5d0) =~ /\p{IsHebrew}/; # inside InHebrew -print "ok 663\n"; - -print "not " unless chr(0xfb4f) =~ /\p{IsHebrew}/; # outside InHebrew -print "ok 664\n"; - -# # singleton (not in a range, this test must be ignored on EBCDIC) -# print "not " unless chr(0xb5) =~ /\p{IsGreek}/ or ord("A") == 193; -# print "ok 665\n"; -print "ok 665 # 0xb5 moved from Greek to Common with Unicode 4.0.1\n"; - -print "not " unless chr(0x37a) =~ /\p{IsGreek}/; # singleton -print "ok 666\n"; - -print "not " unless chr(0x386) =~ /\p{IsGreek}/; # singleton -print "ok 667\n"; - -print "not " unless chr(0x387) =~ /\P{IsGreek}/; # not there -print "ok 668\n"; - -print "not " unless chr(0x388) =~ /\p{IsGreek}/; # range -print "ok 669\n"; - -print "not " unless chr(0x38a) =~ /\p{IsGreek}/; # range -print "ok 670\n"; - -print "not " unless chr(0x38b) =~ /\P{IsGreek}/; # not there -print "ok 671\n"; - -print "not " unless chr(0x38c) =~ /\p{IsGreek}/; # singleton -print "ok 672\n"; - -if (ord("A") == 65) { -## -## Test [:cntrl:]... -## -## Should probably put in tests for all the POSIX stuff, but not sure how to -## guarantee a specific locale...... -## - $AllBytes = join('', map { chr($_) } 0..255); - ($x = $AllBytes) =~ s/[[:cntrl:]]//g; - if ($x ne join('', map { chr($_) } 0x20..0x7E, 0x80..0xFF)) { - print "not "; - } - print "ok 673\n"; - - ($x = $AllBytes) =~ s/[^[:cntrl:]]//g; - if ($x ne join('', map { chr($_) } 0..0x1F, 0x7F)) { print "not " } - print "ok 674\n"; -} else { - print "ok $_ # Skip: EBCDIC\n" for 673..674; -} + { + $_ = "a-a\nxbb"; + pos = 1; + nok m/^-.*bb/mg, '$_ = "a-a\nxbb"; m/^-.*bb/mg'; + } -# With /s modifier UTF8 chars were interpreted as bytes -{ - my $a = "Hello \x{263A} World"; - - my @a = ($a =~ /./gs); - - print "not " unless $#a == 12; - print "ok 675\n"; -} -@a = ("foo\nbar" =~ /./g); -print "ok 676\n" if @a == 6 && "@a" eq "f o o b a r"; + { + local $Message = '\G anchor checks'; + my $text = "aaXbXcc"; + pos ($text) = 0; + ok $text !~ /\GXb*X/g; + } -@a = ("foo\nbar" =~ /./gs); -print "ok 677\n" if @a == 7 && "@a" eq "f o o \n b a r"; -@a = ("foo\nbar" =~ /\C/g); -print "ok 678\n" if @a == 7 && "@a" eq "f o o \n b a r"; + { + $_ = "xA\n" x 500; + nok /^\s*A/m, '$_ = "xA\n" x 500; /^\s*A/m"'; -@a = ("foo\nbar" =~ /\C/gs); -print "ok 679\n" if @a == 7 && "@a" eq "f o o \n b a r"; + my $text = "abc dbf"; + my @res = ($text =~ /.*?(b).*?\b/g); + iseq "@res", "b b", '\b is not special'; + } -@a = ("foo\n\x{100}bar" =~ /./g); -print "ok 680\n" if @a == 7 && "@a" eq "f o o \x{100} b a r"; -@a = ("foo\n\x{100}bar" =~ /./gs); -print "ok 681\n" if @a == 8 && "@a" eq "f o o \n \x{100} b a r"; + { + local $Message = '\S, [\S], \s, [\s]'; + my @a = map chr, 0 .. 255; + my @b = grep /\S/, @a; + my @c = grep /[^\s]/, @a; + iseq "@b", "@c"; + + @b = grep /\S/, @a; + @c = grep /[\S]/, @a; + iseq "@b", "@c"; + + @b = grep /\s/, @a; + @c = grep /[^\S]/, @a; + iseq "@b", "@c"; + + @b = grep /\s/, @a; + @c = grep /[\s]/, @a; + iseq "@b", "@c"; + } + { + local $Message = '\D, [\D], \d, [\d]'; + my @a = map chr, 0 .. 255; + my @b = grep /\D/, @a; + my @c = grep /[^\d]/, @a; + iseq "@b", "@c"; + + @b = grep /\D/, @a; + @c = grep /[\D]/, @a; + iseq "@b", "@c"; + + @b = grep /\d/, @a; + @c = grep /[^\D]/, @a; + iseq "@b", "@c"; + + @b = grep /\d/, @a; + @c = grep /[\d]/, @a; + iseq "@b", "@c"; + } + { + local $Message = '\W, [\W], \w, [\w]'; + my @a = map chr, 0 .. 255; + my @b = grep /\W/, @a; + my @c = grep /[^\w]/, @a; + iseq "@b", "@c"; + + @b = grep /\W/, @a; + @c = grep /[\W]/, @a; + iseq "@b", "@c"; + + @b = grep /\w/, @a; + @c = grep /[^\W]/, @a; + iseq "@b", "@c"; + + @b = grep /\w/, @a; + @c = grep /[\w]/, @a; + iseq "@b", "@c"; + } -($a, $b) = map { chr } ord('A') == 65 ? (0xc4, 0x80) : (0x8c, 0x41); -@a = ("foo\n\x{100}bar" =~ /\C/g); -print "ok 682\n" if @a == 9 && "@a" eq "f o o \n $a $b b a r"; + { + # see if backtracking optimization works correctly + local $Message = 'Backtrack optimization'; + ok "\n\n" =~ /\n $ \n/x; + ok "\n\n" =~ /\n* $ \n/x; + ok "\n\n" =~ /\n+ $ \n/x; + ok "\n\n" =~ /\n? $ \n/x; + ok "\n\n" =~ /\n*? $ \n/x; + ok "\n\n" =~ /\n+? $ \n/x; + ok "\n\n" =~ /\n?? $ \n/x; + ok "\n\n" !~ /\n*+ $ \n/x; + ok "\n\n" !~ /\n++ $ \n/x; + ok "\n\n" =~ /\n?+ $ \n/x; + } -@a = ("foo\n\x{100}bar" =~ /\C/gs); -print "ok 683\n" if @a == 9 && "@a" eq "f o o \n $a $b b a r"; -{ - # [ID 20010814.004] pos() doesn't work when using =~m// in list context - $_ = "ababacadaea"; - $a = join ":", /b./gc; - $b = join ":", /a./gc; - $c = pos; - print "$a $b $c" eq 'ba:ba ad:ae 10' ? "ok 684\n" : "not ok 684\t# $a $b $c\n"; -} + { + package S; + use overload '""' => sub {'Object S'}; + sub new {bless []} + + local $Message = "Ref stringification"; + ::ok do { \my $v} =~ /^SCALAR/, "Scalar ref stringification"; + ::ok do {\\my $v} =~ /^REF/, "Ref ref stringification"; + ::ok [] =~ /^ARRAY/, "Array ref stringification"; + ::ok {} =~ /^HASH/, "Hash ref stringification"; + ::ok 'S' -> new =~ /^Object S/, "Object stringification"; + } + -{ - # [ID 20010407.006] matching utf8 return values from functions does not work + { + local $Message = "Test result of match used as match"; + ok 'a1b' =~ ('xyz' =~ /y/); + iseq $`, 'a'; + ok 'a1b' =~ ('xyz' =~ /t/); + iseq $`, 'a'; + } - package ID_20010407_006; - sub x { - "a\x{1234}"; + { + local $Message = '"1" is not \s'; + may_not_warn sub {ok ("1\n" x 102) !~ /^\s*\n/m}; } - my $x = x; - my $y; - $x =~ /(..)/; $y = $1; - print "not " unless length($y) == 2 && $y eq $x; - print "ok 685\n"; + { + local $Message = '\s, [[:space:]] and [[:blank:]]'; + my %space = (spc => " ", + tab => "\t", + cr => "\r", + lf => "\n", + ff => "\f", + # There's no \v but the vertical tabulator seems miraculously + # be 11 both in ASCII and EBCDIC. + vt => chr(11), + false => "space"); + + my @space0 = sort grep {$space {$_} =~ /\s/ } keys %space; + my @space1 = sort grep {$space {$_} =~ /[[:space:]]/} keys %space; + my @space2 = sort grep {$space {$_} =~ /[[:blank:]]/} keys %space; + + iseq "@space0", "cr ff lf spc tab"; + iseq "@space1", "cr ff lf spc tab vt"; + iseq "@space2", "spc tab"; + } - x =~ /(..)/; $y = $1; - print "not " unless length($y) == 2 && $y eq $x; - print "ok 686\n"; -} + { + local $BugId = '20000731.001'; + ok "A \x{263a} B z C" =~ /A . B (??{ "z" }) C/, + "Match UTF-8 char in presense of (??{ })"; + } -$test = 687; -# Force scalar context on the patern match -sub ok ($;$) { - my($ok, $name) = @_; + { + local $BugId = '20001021.005'; + no warnings 'uninitialized'; + ok undef =~ /^([^\/]*)(.*)$/, "Used to cause a SEGV"; + } - printf "%sok %d - %s\n", ($ok ? "" : "not "), $test, - ($name||$Message)."\tLine ".((caller)[2]); - printf "# Failed test at line %d\n", (caller)[2] unless $ok; + SKIP: + { + local $Message = '\C matches octet'; + $_ = "a\x{100}b"; + ok /(.)(\C)(\C)(.)/ or skip q [\C doesn't match], 4; + iseq $1, "a"; + if ($IS_ASCII) { # ASCII (or equivalent), should be UTF-8 + iseq $2, "\xC4"; + iseq $3, "\x80"; + } + elsif ($IS_EBCDIC) { # EBCDIC (or equivalent), should be UTF-EBCDIC + iseq $2, "\x8C"; + iseq $3, "\x41"; + } + else { + SKIP: { + ok 0, "Unexpected platform", "ord ('A') = $ordA"; + skip "Unexpected platform"; + } + } + iseq $4, "b"; + } - $test++; - return $ok; -} -{ - # Check that \x## works. 5.6.1 and 5.005_03 fail some of these. - $x = "\x4e" . "E"; - ok ($x =~ /^\x4EE$/, "Check only 2 bytes of hex are matched."); + SKIP: + { + local $Message = '\C matches octet'; + $_ = "\x{100}"; + ok /(\C)/g or skip q [\C doesn't match], 2; + if ($IS_ASCII) { + iseq $1, "\xC4"; + } + elsif ($IS_EBCDIC) { + iseq $1, "\x8C"; + } + else { + ok 0, "Unexpected platform", "ord ('A') = $ordA"; + } + ok /(\C)/g or skip q [\C doesn't match]; + if ($IS_ASCII) { + iseq $1, "\x80"; + } + elsif ($IS_EBCDIC) { + iseq $1, "\x41"; + } + else { + ok 0, "Unexpected platform", "ord ('A') = $ordA"; + } + } - $x = "\x4e" . "i"; - ok ($x =~ /^\x4Ei$/, "Check that invalid hex digit stops it (2)"); - $x = "\x4" . "j"; - ok ($x =~ /^\x4j$/, "Check that invalid hex digit stops it (1)"); + { + # Japhy -- added 03/03/2001 + () = (my $str = "abc") =~ /(...)/; + $str = "def"; + iseq $1, "abc", 'Changing subject does not modify $1'; + } - $x = "\x0" . "k"; - ok ($x =~ /^\xk$/, "Check that invalid hex digit stops it (0)"); - $x = "\x0" . "x"; - ok ($x =~ /^\xx$/, "\\xx isn't to be treated as \\0"); + SKIP: + { + # The trick is that in EBCDIC the explicit numeric range should + # match (as also in non-EBCDIC) but the explicit alphabetic range + # should not match. + ok "\x8e" =~ /[\x89-\x91]/, '"\x8e" =~ /[\x89-\x91]/'; + ok "\xce" =~ /[\xc9-\xd1]/, '"\xce" =~ /[\xc9-\xd1]/'; + + skip "Not an EBCDIC platform", 2 unless ord ('i') == 0x89 && + ord ('J') == 0xd1; + + # In most places these tests would succeed since \x8e does not + # in most character sets match 'i' or 'j' nor would \xce match + # 'I' or 'J', but strictly speaking these tests are here for + # the good of EBCDIC, so let's test these only there. + nok "\x8e" !~ /[i-j]/, '"\x8e" !~ /[i-j]/'; + nok "\xce" !~ /[I-J]/, '"\xce" !~ /[I-J]/'; + } - $x = "\x0" . "xa"; - ok ($x =~ /^\xxa$/, "\\xxa isn't to be treated as \\xa"); - $x = "\x9" . "_b"; - ok ($x =~ /^\x9_b$/, "\\x9_b isn't to be treated as \\x9b"); + { + ok "\x{ab}" =~ /\x{ab}/, '"\x{ab}" =~ /\x{ab}/ '; + ok "\x{abcd}" =~ /\x{abcd}/, '"\x{abcd}" =~ /\x{abcd}/'; + } - print "# and now again in [] ranges\n"; - $x = "\x4e" . "E"; - ok ($x =~ /^[\x4EE]{2}$/, "Check only 2 bytes of hex are matched."); + { + local $Message = 'bug id 20001008.001'; + + my @x = ("stra\337e 138", "stra\337e 138"); + for (@x) { + ok s/(\d+)\s*([\w\-]+)/$1 . uc $2/e; + ok my ($latin) = /^(.+)(?:\s+\d)/; + iseq $latin, "stra\337e"; + ok $latin =~ s/stra\337e/straße/; + # + # Previous code follows, but outcommented - there were no tests. + # + # $latin =~ s/stra\337e/straße/; # \303\237 after the 2nd a + # use utf8; # needed for the raw UTF-8 + # $latin =~ s!(s)tr(?:aß|s+e)!$1tr.!; # \303\237 after the a + } + } - $x = "\x4e" . "i"; - ok ($x =~ /^[\x4Ei]{2}$/, "Check that invalid hex digit stops it (2)"); - $x = "\x4" . "j"; - ok ($x =~ /^[\x4j]{2}$/, "Check that invalid hex digit stops it (1)"); + { + local $Message = 'Test \x escapes'; + ok "ba\xd4c" =~ /([a\xd4]+)/ && $1 eq "a\xd4"; + ok "ba\xd4c" =~ /([a\xd4]+)/ && $1 eq "a\x{d4}"; + ok "ba\x{d4}c" =~ /([a\xd4]+)/ && $1 eq "a\x{d4}"; + ok "ba\x{d4}c" =~ /([a\xd4]+)/ && $1 eq "a\xd4"; + ok "ba\xd4c" =~ /([a\x{d4}]+)/ && $1 eq "a\xd4"; + ok "ba\xd4c" =~ /([a\x{d4}]+)/ && $1 eq "a\x{d4}"; + ok "ba\x{d4}c" =~ /([a\x{d4}]+)/ && $1 eq "a\x{d4}"; + ok "ba\x{d4}c" =~ /([a\x{d4}]+)/ && $1 eq "a\xd4"; + } - $x = "\x0" . "k"; - ok ($x =~ /^[\xk]{2}$/, "Check that invalid hex digit stops it (0)"); - $x = "\x0" . "x"; - ok ($x =~ /^[\xx]{2}$/, "\\xx isn't to be treated as \\0"); + { + local $BugId = '20001028.003'; + + # Fist half of the bug. + local $Message = 'HEBREW ACCENT QADMA matched by .*'; + my $X = chr (1448); + ok my ($Y) = $X =~ /(.*)/; + iseq $Y, v1448; + iseq length ($Y), 1; + + # Second half of the bug. + $Message = 'HEBREW ACCENT QADMA in replacement'; + $X = ''; + $X =~ s/^/chr(1488)/e; + iseq length $X, 1; + iseq ord ($X), 1488; + } - $x = "\x0" . "xa"; - ok ($x =~ /^[\xxa]{3}$/, "\\xxa isn't to be treated as \\xa"); - $x = "\x9" . "_b"; - ok ($x =~ /^[\x9_b]{3}$/, "\\x9_b isn't to be treated as \\x9b"); + { + local $BugId = '20001108.001'; + local $Message = 'Repeated s///'; + my $X = "Szab\x{f3},Bal\x{e1}zs"; + my $Y = $X; + $Y =~ s/(B)/$1/ for 0 .. 3; + iseq $Y, $X; + iseq $X, "Szab\x{f3},Bal\x{e1}zs"; + } -} -{ - # Check that \x{##} works. 5.6.1 fails quite a few of these. + { + local $BugId = '20000517.001'; + local $Message = 's/// on UTF-8 string'; + my $x = "\x{100}A"; + $x =~ s/A/B/; + iseq $x, "\x{100}B"; + iseq length $x, 2; + } - $x = "\x9b"; - ok ($x =~ /^\x{9_b}$/, "\\x{9_b} is to be treated as \\x9b"); - $x = "\x9b" . "y"; - ok ($x =~ /^\x{9_b}y$/, "\\x{9_b} is to be treated as \\x9b (again)"); + { + local $BugId = '20001230.002'; + local $Message = '\C and É'; + ok "École" =~ /^\C\C(.)/ && $1 eq 'c'; + ok "École" =~ /^\C\C(c)/; + } - $x = "\x9b" . "y"; - ok ($x =~ /^\x{9b_}y$/, "\\x{9b_} is to be treated as \\x9b"); - $x = "\x9b" . "y"; - ok ($x =~ /^\x{9_bq}y$/, "\\x{9_bc} is to be treated as \\x9b"); + SKIP: + { + local $Message = 'Match code points > 255'; + $_ = "abc\x{100}\x{200}\x{300}\x{380}\x{400}defg"; + ok /(.\x{300})./ or skip "No match", 4; + ok $` eq "abc\x{100}" && length ($`) == 4; + ok $& eq "\x{200}\x{300}\x{380}" && length ($&) == 3; + ok $' eq "\x{400}defg" && length ($') == 5; + ok $1 eq "\x{200}\x{300}" && length ($1) == 2; + } - $x = "\x0" . "y"; - ok ($x =~ /^\x{x9b}y$/, "\\x{x9b} is to be treated as \\x0"); - $x = "\x0" . "y"; - ok ($x =~ /^\x{0x9b}y$/, "\\x{0x9b} is to be treated as \\x0"); + { + # The original bug report had 'no utf8' here but that was irrelevant. + local $BugId = '20010306.008'; + local $Message = "Don't dump core"; + my $a = "a\x{1234}"; + ok $a =~ m/\w/; # used to core dump. + } - $x = "\x9b" . "y"; - ok ($x =~ /^\x{09b}y$/, "\\x{09b} is to be treated as \\x9b"); - print "# and now again in [] ranges\n"; + { + local $BugId = '20010410.006'; + local $Message = '/g in scalar context'; + for my $rx ('/(.*?)\{(.*?)\}/csg', + '/(.*?)\{(.*?)\}/cg', + '/(.*?)\{(.*?)\}/sg', + '/(.*?)\{(.*?)\}/g', + '/(.+?)\{(.+?)\}/csg',) { + my $i = 0; + my $input = "a{b}c{d}"; + eval <<" --"; + while (eval \$input =~ $rx) { + \$i ++; + } + -- + iseq $i, 2; + } + } - $x = "\x9b"; - ok ($x =~ /^[\x{9_b}]$/, "\\x{9_b} is to be treated as \\x9b"); - $x = "\x9b" . "y"; - ok ($x =~ /^[\x{9_b}y]{2}$/, "\\x{9_b} is to be treated as \\x9b (again)"); + { + my $x = "\x{10FFFD}"; + $x =~ s/(.)/$1/g; + ok ord($x) == 0x10FFFD && length($x) == 1, "From Robin Houston"; + } - $x = "\x9b" . "y"; - ok ($x =~ /^[\x{9b_}y]{2}$/, "\\x{9b_} is to be treated as \\x9b"); - $x = "\x9b" . "y"; - ok ($x =~ /^[\x{9_bq}y]{2}$/, "\\x{9_bc} is to be treated as \\x9b"); + { + my %d = ( + "7f" => [0, 0, 0], + "80" => [1, 1, 0], + "ff" => [1, 1, 0], + "100" => [0, 1, 1], + ); + SKIP: + while (my ($code, $match) = each %d) { + local $Message = "Properties of \\x$code"; + my $char = eval qq ["\\x{$code}"]; + my $i = 0; + ok (($char =~ /[\x80-\xff]/) xor !$$match [$i ++]); + ok (($char =~ /[\x80-\x{100}]/) xor !$$match [$i ++]); + ok (($char =~ /[\x{100}]/) xor !$$match [$i ++]); + } + } - $x = "\x0" . "y"; - ok ($x =~ /^[\x{x9b}y]{2}$/, "\\x{x9b} is to be treated as \\x0"); - $x = "\x0" . "y"; - ok ($x =~ /^[\x{0x9b}y]{2}$/, "\\x{0x9b} is to be treated as \\x0"); + { + # From Japhy + local $Message; + must_warn 'qr/(?c)/', '^Useless \(\?c\)'; + must_warn 'qr/(?-c)/', '^Useless \(\?-c\)'; + must_warn 'qr/(?g)/', '^Useless \(\?g\)'; + must_warn 'qr/(?-g)/', '^Useless \(\?-g\)'; + must_warn 'qr/(?o)/', '^Useless \(\?o\)'; + must_warn 'qr/(?-o)/', '^Useless \(\?-o\)'; + + # Now test multi-error regexes + must_warn 'qr/(?g-o)/', '^Useless \(\?g\).*\nUseless \(\?-o\)'; + must_warn 'qr/(?g-c)/', '^Useless \(\?g\).*\nUseless \(\?-c\)'; + # (?c) means (?g) error won't be thrown + must_warn 'qr/(?o-cg)/', '^Useless \(\?o\).*\nUseless \(\?-c\)'; + must_warn 'qr/(?ogc)/', '^Useless \(\?o\).*\nUseless \(\?g\).*\n' . + 'Useless \(\?c\)'; + } - $x = "\x9b" . "y"; - ok ($x =~ /^[\x{09b}y]{2}$/, "\\x{09b} is to be treated as \\x9b"); -} -{ - # high bit bug -- japhy - my $x = "ab\200d"; - $x =~ /.*?\200/ or print "not "; - print "ok 715\n"; -} + { + local $Message = "/x tests"; + $_ = "foo"; + eval_ok <<" --"; + /f + o\r + o + \$ + /x + -- + eval_ok <<" --"; + /f + o + o + \$\r + /x + -- + } -print "# some Unicode properties\n"; -{ - # Dashes, underbars, case. - print "not " unless "\x80" =~ /\p{in-latin1_SUPPLEMENT}/; - print "ok 716\n"; + { + local $Message = "/o feature"; + sub test_o {$_ [0] =~ /$_[1]/o; return $1} + iseq test_o ('abc', '(.)..'), 'a'; + iseq test_o ('abc', '..(.)'), 'a'; + } - # Complement, leading and trailing whitespace. - print "not " unless "\x80" =~ /\P{ ^ In Latin 1 Supplement }/; - print "ok 717\n"; - # No ^In, dashes, case, dash, any intervening (word-break) whitespace. - # (well, newlines don't work...) - print "not " unless "\x80" =~ /\p{latin-1 supplement}/; - print "ok 718\n"; -} + { + local $BugId = "20010619.003"; + # Amazingly vertical tabulator is the same in ASCII and EBCDIC. + for ("\n", "\t", "\014", "\r") { + ok !/[[:print:]]/, "'$_' not in [[:print:]]"; + } + for (" ") { + ok /[[:print:]]/, "'$_' in [[:print:]]"; + } + } -{ - print "not " unless "a" =~ /\pL/; - print "ok 719\n"; - print "not " unless "a" =~ /\p{IsLl}/; - print "ok 720\n"; + { + # Test basic $^N usage outside of a regex + local $Message = '$^N usage outside of a regex'; + my $x = "abcdef"; + ok ($x =~ /cde/ and !defined $^N); + ok ($x =~ /(cde)/ and $^N eq "cde"); + ok ($x =~ /(c)(d)(e)/ and $^N eq "e"); + ok ($x =~ /(c(d)e)/ and $^N eq "cde"); + ok ($x =~ /(foo)|(c(d)e)/ and $^N eq "cde"); + ok ($x =~ /(c(d)e)|(foo)/ and $^N eq "cde"); + ok ($x =~ /(c(d)e)|(abc)/ and $^N eq "abc"); + ok ($x =~ /(c(d)e)|(abc)x/ and $^N eq "cde"); + ok ($x =~ /(c(d)e)(abc)?/ and $^N eq "cde"); + ok ($x =~ /(?:c(d)e)/ and $^N eq "d"); + ok ($x =~ /(?:c(d)e)(?:f)/ and $^N eq "d"); + ok ($x =~ /(?:([abc])|([def]))*/ and $^N eq "f"); + ok ($x =~ /(?:([ace])|([bdf]))*/ and $^N eq "f"); + ok ($x =~ /(([ace])|([bd]))*/ and $^N eq "e"); + {ok ($x =~ /(([ace])|([bdf]))*/ and $^N eq "f");} + ## Test to see if $^N is automatically localized -- it should now + ## have the value set in the previous test. + iseq $^N, "e", '$^N is automatically localized'; + + # Now test inside (?{ ... }) + local $Message = '$^N usage inside (?{ ... })'; + our ($y, $z); + ok ($x =~ /a([abc])(?{$y=$^N})c/ and $y eq "b"); + ok ($x =~ /a([abc]+)(?{$y=$^N})d/ and $y eq "bc"); + ok ($x =~ /a([abcdefg]+)(?{$y=$^N})d/ and $y eq "bc"); + ok ($x =~ /(a([abcdefg]+)(?{$y=$^N})d)(?{$z=$^N})e/ and $y eq "bc" + and $z eq "abcd"); + ok ($x =~ /(a([abcdefg]+)(?{$y=$^N})de)(?{$z=$^N})/ and $y eq "bc" + and $z eq "abcde"); - print "not " if "a" =~ /\p{IsLu}/; - print "ok 721\n"; + } - print "not " unless "a" =~ /\p{Ll}/; - print "ok 722\n"; - print "not " if "a" =~ /\p{Lu}/; - print "ok 723\n"; + SKIP: + { + ## Should probably put in tests for all the POSIX stuff, + ## but not sure how to guarantee a specific locale...... - print "not " unless "A" =~ /\pL/; - print "ok 724\n"; + skip "Not an ASCII platform", 2 unless $IS_ASCII; + local $Message = 'Test [[:cntrl:]]'; + my $AllBytes = join "" => map {chr} 0 .. 255; + (my $x = $AllBytes) =~ s/[[:cntrl:]]//g; + iseq $x, join "", map {chr} 0x20 .. 0x7E, 0x80 .. 0xFF; - print "not " unless "A" =~ /\p{IsLu}/; - print "ok 725\n"; + ($x = $AllBytes) =~ s/[^[:cntrl:]]//g; + iseq $x, join "", map {chr} 0x00 .. 0x1F, 0x7F; + } - print "not " if "A" =~ /\p{IsLl}/; - print "ok 726\n"; - print "not " unless "A" =~ /\p{Lu}/; - print "ok 727\n"; + { + # With /s modifier UTF8 chars were interpreted as bytes + local $Message = "UTF-8 chars aren't bytes"; + my $a = "Hello \x{263A} World"; + my @a = ($a =~ /./gs); + iseq $#a, 12; + } - print "not " if "A" =~ /\p{Ll}/; - print "ok 728\n"; - print "not " if "a" =~ /\PL/; - print "ok 729\n"; + { + local $Message = '. matches \n with /s'; + my $str1 = "foo\nbar"; + my $str2 = "foo\n\x{100}bar"; + my ($a, $b) = map {chr} $IS_ASCII ? (0xc4, 0x80) : (0x8c, 0x41); + my @a; + @a = $str1 =~ /./g; iseq @a, 6; iseq "@a", "f o o b a r"; + @a = $str1 =~ /./gs; iseq @a, 7; iseq "@a", "f o o \n b a r"; + @a = $str1 =~ /\C/g; iseq @a, 7; iseq "@a", "f o o \n b a r"; + @a = $str1 =~ /\C/gs; iseq @a, 7; iseq "@a", "f o o \n b a r"; + @a = $str2 =~ /./g; iseq @a, 7; iseq "@a", "f o o \x{100} b a r"; + @a = $str2 =~ /./gs; iseq @a, 8; iseq "@a", "f o o \n \x{100} b a r"; + @a = $str2 =~ /\C/g; iseq @a, 9; iseq "@a", "f o o \n $a $b b a r"; + @a = $str2 =~ /\C/gs; iseq @a, 9; iseq "@a", "f o o \n $a $b b a r"; + } - print "not " if "a" =~ /\P{IsLl}/; - print "ok 730\n"; - print "not " unless "a" =~ /\P{IsLu}/; - print "ok 731\n"; + { + # [ID 20010814.004] pos() doesn't work when using =~m// in list context + local $BugId = '20010814.004'; + $_ = "ababacadaea"; + my $a = join ":", /b./gc; + my $b = join ":", /a./gc; + my $c = pos; + iseq "$a $b $c", 'ba:ba ad:ae 10', "pos() works with () = m//"; + } - print "not " if "a" =~ /\P{Ll}/; - print "ok 732\n"; - print "not " unless "a" =~ /\P{Lu}/; - print "ok 733\n"; + { + # [ID 20010407.006] matching utf8 return values from + # functions does not work + local $BugId = '20010407.006'; + local $Message = 'UTF-8 return values from functions'; + package ID_20010407_006; + sub x {"a\x{1234}"} + my $x = x; + my $y; + ::ok $x =~ /(..)/; + $y = $1; + ::ok length ($y) == 2 && $y eq $x; + ::ok x =~ /(..)/; + $y = $1; + ::ok length ($y) == 2 && $y eq $x; + } - print "not " if "A" =~ /\PL/; - print "ok 734\n"; - print "not " if "A" =~ /\P{IsLu}/; - print "ok 735\n"; + { + no warnings 'digit'; + # Check that \x## works. 5.6.1 and 5.005_03 fail some of these. + my $x; + $x = "\x4e" . "E"; + ok ($x =~ /^\x4EE$/, "Check only 2 bytes of hex are matched."); - print "not " unless "A" =~ /\P{IsLl}/; - print "ok 736\n"; + $x = "\x4e" . "i"; + ok ($x =~ /^\x4Ei$/, "Check that invalid hex digit stops it (2)"); - print "not " if "A" =~ /\P{Lu}/; - print "ok 737\n"; + $x = "\x4" . "j"; + ok ($x =~ /^\x4j$/, "Check that invalid hex digit stops it (1)"); - print "not " unless "A" =~ /\P{Ll}/; - print "ok 738\n"; + $x = "\x0" . "k"; + ok ($x =~ /^\xk$/, "Check that invalid hex digit stops it (0)"); -} + $x = "\x0" . "x"; + ok ($x =~ /^\xx$/, "\\xx isn't to be treated as \\0"); -{ - print "not " if "a" =~ /\p{Common}/; - print "ok 739\n"; + $x = "\x0" . "xa"; + ok ($x =~ /^\xxa$/, "\\xxa isn't to be treated as \\xa"); - print "not " unless "1" =~ /\p{Common}/; - print "ok 740\n"; -} + $x = "\x9" . "_b"; + ok ($x =~ /^\x9_b$/, "\\x9_b isn't to be treated as \\x9b"); -{ - print "not " if "a" =~ /\p{Inherited}/; - print "ok 741\n"; + # and now again in [] ranges - print "not " unless "\x{300}" =~ /\p{Inherited}/; - print "ok 742\n"; -} + $x = "\x4e" . "E"; + ok ($x =~ /^[\x4EE]{2}$/, "Check only 2 bytes of hex are matched."); -{ - # L& and LC are the same - print "not " unless "a" =~ /\p{LC}/ and "a" =~ /\p{L&}/; - print "ok 743\n"; + $x = "\x4e" . "i"; + ok ($x =~ /^[\x4Ei]{2}$/, "Check that invalid hex digit stops it (2)"); - print "not " if "1" =~ /\p{LC}/ or "1" =~ /\p{L&}/; - print "ok 744\n"; -} + $x = "\x4" . "j"; + ok ($x =~ /^[\x4j]{2}$/, "Check that invalid hex digit stops it (1)"); -{ - print "not " unless "a" =~ /\p{Lowercase Letter}/; - print "ok 745\n"; + $x = "\x0" . "k"; + ok ($x =~ /^[\xk]{2}$/, "Check that invalid hex digit stops it (0)"); - print "not " if "A" =~ /\p{lowercaseletter}/; - print "ok 746\n"; -} + $x = "\x0" . "x"; + ok ($x =~ /^[\xx]{2}$/, "\\xx isn't to be treated as \\0"); -{ - print "not " unless "\x{AC00}" =~ /\p{HangulSyllables}/; - print "ok 747\n"; -} + $x = "\x0" . "xa"; + ok ($x =~ /^[\xxa]{3}$/, "\\xxa isn't to be treated as \\xa"); -{ - # Script=, Block=, Category= + $x = "\x9" . "_b"; + ok ($x =~ /^[\x9_b]{3}$/, "\\x9_b isn't to be treated as \\x9b"); - print "not " unless "\x{0100}" =~ /\p{Script=Latin}/; - print "ok 748\n"; + # Check that \x{##} works. 5.6.1 fails quite a few of these. - print "not " unless "\x{0100}" =~ /\p{Block=LatinExtendedA}/; - print "ok 749\n"; + $x = "\x9b"; + ok ($x =~ /^\x{9_b}$/, "\\x{9_b} is to be treated as \\x9b"); - print "not " unless "\x{0100}" =~ /\p{Category=UppercaseLetter}/; - print "ok 750\n"; -} + $x = "\x9b" . "y"; + ok ($x =~ /^\x{9_b}y$/, "\\x{9_b} is to be treated as \\x9b (again)"); -{ - print "# the basic character classes and Unicode \n"; + $x = "\x9b" . "y"; + ok ($x =~ /^\x{9b_}y$/, "\\x{9b_} is to be treated as \\x9b"); - # 0100;LATIN CAPITAL LETTER A WITH MACRON;Lu;0;L;0041 0304;;;;N;LATIN CAPITAL LETTER A MACRON;;;0101; - print "not " unless "\x{0100}" =~ /\w/; - print "ok 751\n"; + $x = "\x9b" . "y"; + ok ($x =~ /^\x{9_bq}y$/, "\\x{9_bc} is to be treated as \\x9b"); - # 0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; - print "not " unless "\x{0660}" =~ /\d/; - print "ok 752\n"; + $x = "\x0" . "y"; + ok ($x =~ /^\x{x9b}y$/, "\\x{x9b} is to be treated as \\x0"); - # 1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;; - print "not " unless "\x{1680}" =~ /\s/; - print "ok 753\n"; -} + $x = "\x0" . "y"; + ok ($x =~ /^\x{0x9b}y$/, "\\x{0x9b} is to be treated as \\x0"); -{ - print "# folding matches and Unicode\n"; + $x = "\x9b" . "y"; + ok ($x =~ /^\x{09b}y$/, "\\x{09b} is to be treated as \\x9b"); - print "not " unless "a\x{100}" =~ /A/i; - print "ok 754\n"; + $x = "\x9b"; + ok ($x =~ /^[\x{9_b}]$/, "\\x{9_b} is to be treated as \\x9b"); - print "not " unless "A\x{100}" =~ /a/i; - print "ok 755\n"; + $x = "\x9b" . "y"; + ok ($x =~ /^[\x{9_b}y]{2}$/, + "\\x{9_b} is to be treated as \\x9b (again)"); - print "not " unless "a\x{100}" =~ /a/i; - print "ok 756\n"; + $x = "\x9b" . "y"; + ok ($x =~ /^[\x{9b_}y]{2}$/, "\\x{9b_} is to be treated as \\x9b"); - print "not " unless "A\x{100}" =~ /A/i; - print "ok 757\n"; + $x = "\x9b" . "y"; + ok ($x =~ /^[\x{9_bq}y]{2}$/, "\\x{9_bc} is to be treated as \\x9b"); - print "not " unless "\x{101}a" =~ /\x{100}/i; - print "ok 758\n"; + $x = "\x0" . "y"; + ok ($x =~ /^[\x{x9b}y]{2}$/, "\\x{x9b} is to be treated as \\x0"); - print "not " unless "\x{100}a" =~ /\x{100}/i; - print "ok 759\n"; + $x = "\x0" . "y"; + ok ($x =~ /^[\x{0x9b}y]{2}$/, "\\x{0x9b} is to be treated as \\x0"); - print "not " unless "\x{101}a" =~ /\x{101}/i; - print "ok 760\n"; + $x = "\x9b" . "y"; + ok ($x =~ /^[\x{09b}y]{2}$/, "\\x{09b} is to be treated as \\x9b"); - print "not " unless "\x{100}a" =~ /\x{101}/i; - print "ok 761\n"; + } - print "not " unless "a\x{100}" =~ /A\x{100}/i; - print "ok 762\n"; - print "not " unless "A\x{100}" =~ /a\x{100}/i; - print "ok 763\n"; + { + # High bit bug -- japhy + my $x = "ab\200d"; + ok $x =~ /.*?\200/, "High bit fine"; + } - print "not " unless "a\x{100}" =~ /a\x{100}/i; - print "ok 764\n"; - print "not " unless "A\x{100}" =~ /A\x{100}/i; - print "ok 765\n"; + { + # The basic character classes and Unicode + ok "\x{0100}" =~ /\w/, 'LATIN CAPITAL LETTER A WITH MACRON in /\w/'; + ok "\x{0660}" =~ /\d/, 'ARABIC-INDIC DIGIT ZERO in /\d/'; + ok "\x{1680}" =~ /\s/, 'OGHAM SPACE MARK in /\s/'; + } - print "not " unless "a\x{100}" =~ /[A]/i; - print "ok 766\n"; - print "not " unless "A\x{100}" =~ /[a]/i; - print "ok 767\n"; + { + local $Message = "Folding matches and Unicode"; + ok "a\x{100}" =~ /A/i; + ok "A\x{100}" =~ /a/i; + ok "a\x{100}" =~ /a/i; + ok "A\x{100}" =~ /A/i; + ok "\x{101}a" =~ /\x{100}/i; + ok "\x{100}a" =~ /\x{100}/i; + ok "\x{101}a" =~ /\x{101}/i; + ok "\x{100}a" =~ /\x{101}/i; + ok "a\x{100}" =~ /A\x{100}/i; + ok "A\x{100}" =~ /a\x{100}/i; + ok "a\x{100}" =~ /a\x{100}/i; + ok "A\x{100}" =~ /A\x{100}/i; + ok "a\x{100}" =~ /[A]/i; + ok "A\x{100}" =~ /[a]/i; + ok "a\x{100}" =~ /[a]/i; + ok "A\x{100}" =~ /[A]/i; + ok "\x{101}a" =~ /[\x{100}]/i; + ok "\x{100}a" =~ /[\x{100}]/i; + ok "\x{101}a" =~ /[\x{101}]/i; + ok "\x{100}a" =~ /[\x{101}]/i; + } - print "not " unless "a\x{100}" =~ /[a]/i; - print "ok 768\n"; - print "not " unless "A\x{100}" =~ /[A]/i; - print "ok 769\n"; + { + use charnames ':full'; + local $Message = "Folding 'LATIN LETTER A WITH GRAVE'"; - print "not " unless "\x{101}a" =~ /[\x{100}]/i; - print "ok 770\n"; + my $lower = "\N{LATIN SMALL LETTER A WITH GRAVE}"; + my $UPPER = "\N{LATIN CAPITAL LETTER A WITH GRAVE}"; + + ok $lower =~ m/$UPPER/i; + ok $UPPER =~ m/$lower/i; + ok $lower =~ m/[$UPPER]/i; + ok $UPPER =~ m/[$lower]/i; - print "not " unless "\x{100}a" =~ /[\x{100}]/i; - print "ok 771\n"; + local $Message = "Folding 'GREEK LETTER ALPHA WITH VRACHY'"; - print "not " unless "\x{101}a" =~ /[\x{101}]/i; - print "ok 772\n"; + $lower = "\N{GREEK CAPITAL LETTER ALPHA WITH VRACHY}"; + $UPPER = "\N{GREEK SMALL LETTER ALPHA WITH VRACHY}"; - print "not " unless "\x{100}a" =~ /[\x{101}]/i; - print "ok 773\n"; + ok $lower =~ m/$UPPER/i; + ok $UPPER =~ m/$lower/i; + ok $lower =~ m/[$UPPER]/i; + ok $UPPER =~ m/[$lower]/i; -} + local $Message = "Folding 'LATIN LETTER Y WITH DIAERESIS'"; -{ - use charnames ':full'; + $lower = "\N{LATIN SMALL LETTER Y WITH DIAERESIS}"; + $UPPER = "\N{LATIN CAPITAL LETTER Y WITH DIAERESIS}"; - print "# LATIN LETTER A WITH GRAVE\n"; - my $lower = "\N{LATIN SMALL LETTER A WITH GRAVE}"; - my $UPPER = "\N{LATIN CAPITAL LETTER A WITH GRAVE}"; + ok $lower =~ m/$UPPER/i; + ok $UPPER =~ m/$lower/i; + ok $lower =~ m/[$UPPER]/i; + ok $UPPER =~ m/[$lower]/i; + } - print $lower =~ m/$UPPER/i ? "ok 774\n" : "not ok 774\n"; - print $UPPER =~ m/$lower/i ? "ok 775\n" : "not ok 775\n"; - print $lower =~ m/[$UPPER]/i ? "ok 776\n" : "not ok 776\n"; - print $UPPER =~ m/[$lower]/i ? "ok 777\n" : "not ok 777\n"; - print "# GREEK LETTER ALPHA WITH VRACHY\n"; + { + use charnames ':full'; + local $PatchId = "13843"; + local $Message = "GREEK CAPITAL LETTER SIGMA vs " . + "COMBINING GREEK PERISPOMENI"; - $lower = "\N{GREEK CAPITAL LETTER ALPHA WITH VRACHY}"; - $UPPER = "\N{GREEK SMALL LETTER ALPHA WITH VRACHY}"; + my $SIGMA = "\N{GREEK CAPITAL LETTER SIGMA}"; + my $char = "\N{COMBINING GREEK PERISPOMENI}"; - print $lower =~ m/$UPPER/i ? "ok 778\n" : "not ok 778\n"; - print $UPPER =~ m/$lower/i ? "ok 779\n" : "not ok 779\n"; - print $lower =~ m/[$UPPER]/i ? "ok 780\n" : "not ok 780\n"; - print $UPPER =~ m/[$lower]/i ? "ok 781\n" : "not ok 781\n"; + may_not_warn sub {ok "_:$char:_" !~ m/_:$SIGMA:_/i}; + } - print "# LATIN LETTER Y WITH DIAERESIS\n"; - $lower = "\N{LATIN CAPITAL LETTER Y WITH DIAERESIS}"; - $UPPER = "\N{LATIN SMALL LETTER Y WITH DIAERESIS}"; - print $lower =~ m/$UPPER/i ? "ok 782\n" : "not ok 782\n"; - print $UPPER =~ m/$lower/i ? "ok 783\n" : "not ok 783\n"; - print $lower =~ m/[$UPPER]/i ? "ok 784\n" : "not ok 784\n"; - print $UPPER =~ m/[$lower]/i ? "ok 785\n" : "not ok 785\n"; -} + { + local $Message = '\X'; + use charnames ':full'; + + ok "a!" =~ /^(\X)!/ && $1 eq "a"; + ok "\xDF!" =~ /^(\X)!/ && $1 eq "\xDF"; + ok "\x{100}!" =~ /^(\X)!/ && $1 eq "\x{100}"; + ok "\x{100}\x{300}!" =~ /^(\X)!/ && $1 eq "\x{100}\x{300}"; + ok "\N{LATIN CAPITAL LETTER E}!" =~ /^(\X)!/ && + $1 eq "\N{LATIN CAPITAL LETTER E}"; + ok "\N{LATIN CAPITAL LETTER E}\N{COMBINING GRAVE ACCENT}!" + =~ /^(\X)!/ && + $1 eq "\N{LATIN CAPITAL LETTER E}\N{COMBINING GRAVE ACCENT}"; + + local $Message = '\C and \X'; + ok "!abc!" =~ /a\Cc/; + ok "!abc!" =~ /a\Xc/; + } -{ - use warnings; - use charnames ':full'; - - print "# GREEK CAPITAL LETTER SIGMA vs COMBINING GREEK PERISPOMENI\n"; - my $SIGMA = "\N{GREEK CAPITAL LETTER SIGMA}"; - my $char = "\N{COMBINING GREEK PERISPOMENI}"; + { + local $Message = "Final Sigma"; - # Before #13843 this was failing by matching falsely. - print "_:$char:_" =~ m/_:$SIGMA:_/i ? "not ok 786\n" : "ok 786\n"; -} + my $SIGMA = "\x{03A3}"; # CAPITAL + my $Sigma = "\x{03C2}"; # SMALL FINAL + my $sigma = "\x{03C3}"; # SMALL -{ - print "# \\X\n"; - - use charnames ':full'; - - print "a!" =~ /^(\X)!/ && $1 eq "a" ? - "ok 787\n" : "not ok 787 # $1\n"; - print "\xDF!" =~ /^(\X)!/ && $1 eq "\xDF" ? - "ok 788\n" : "not ok 788 # $1\n"; - print "\x{100}!" =~ /^(\X)!/ && $1 eq "\x{100}" ? - "ok 789\n" : "not ok 789 # $1\n"; - print "\x{100}\x{300}!" =~ /^(\X)!/ && $1 eq "\x{100}\x{300}" ? - "ok 790\n" : "not ok 790 # $1\n"; - print "\N{LATIN CAPITAL LETTER E}!" =~ /^(\X)!/ && - $1 eq "\N{LATIN CAPITAL LETTER E}" ? - "ok 791\n" : "not ok 791 # $1\n"; - print "\N{LATIN CAPITAL LETTER E}\N{COMBINING GRAVE ACCENT}!" =~ - /^(\X)!/ && - $1 eq "\N{LATIN CAPITAL LETTER E}\N{COMBINING GRAVE ACCENT}" ? - "ok 792\n" : "not ok 792 # $1\n"; -} + ok $SIGMA =~ /$SIGMA/i; + ok $SIGMA =~ /$Sigma/i; + ok $SIGMA =~ /$sigma/i; -{ - print "#\\C and \\X\n"; + ok $Sigma =~ /$SIGMA/i; + ok $Sigma =~ /$Sigma/i; + ok $Sigma =~ /$sigma/i; - print "!abc!" =~ /a\Cc/ ? "ok 793\n" : "not ok 793\n"; - print "!abc!" =~ /a\Xc/ ? "ok 794\n" : "not ok 794\n"; -} + ok $sigma =~ /$SIGMA/i; + ok $sigma =~ /$Sigma/i; + ok $sigma =~ /$sigma/i; + + ok $SIGMA =~ /[$SIGMA]/i; + ok $SIGMA =~ /[$Sigma]/i; + ok $SIGMA =~ /[$sigma]/i; -{ - print "# FINAL SIGMA\n"; + ok $Sigma =~ /[$SIGMA]/i; + ok $Sigma =~ /[$Sigma]/i; + ok $Sigma =~ /[$sigma]/i; - my $SIGMA = "\x{03A3}"; # CAPITAL - my $Sigma = "\x{03C2}"; # SMALL FINAL - my $sigma = "\x{03C3}"; # SMALL + ok $sigma =~ /[$SIGMA]/i; + ok $sigma =~ /[$Sigma]/i; + ok $sigma =~ /[$sigma]/i; - print $SIGMA =~ /$SIGMA/i ? "ok 795\n" : "not ok 795\n"; - print $SIGMA =~ /$Sigma/i ? "ok 796\n" : "not ok 796\n"; - print $SIGMA =~ /$sigma/i ? "ok 797\n" : "not ok 797\n"; + local $Message = "More final Sigma"; - print $Sigma =~ /$SIGMA/i ? "ok 798\n" : "not ok 798\n"; - print $Sigma =~ /$Sigma/i ? "ok 799\n" : "not ok 799\n"; - print $Sigma =~ /$sigma/i ? "ok 800\n" : "not ok 800\n"; + my $S3 = "$SIGMA$Sigma$sigma"; - print $sigma =~ /$SIGMA/i ? "ok 801\n" : "not ok 801\n"; - print $sigma =~ /$Sigma/i ? "ok 802\n" : "not ok 802\n"; - print $sigma =~ /$sigma/i ? "ok 803\n" : "not ok 803\n"; - - print $SIGMA =~ /[$SIGMA]/i ? "ok 804\n" : "not ok 804\n"; - print $SIGMA =~ /[$Sigma]/i ? "ok 805\n" : "not ok 805\n"; - print $SIGMA =~ /[$sigma]/i ? "ok 806\n" : "not ok 806\n"; + ok ":$S3:" =~ /:(($SIGMA)+):/i && $1 eq $S3 && $2 eq $sigma; + ok ":$S3:" =~ /:(($Sigma)+):/i && $1 eq $S3 && $2 eq $sigma; + ok ":$S3:" =~ /:(($sigma)+):/i && $1 eq $S3 && $2 eq $sigma; - print $Sigma =~ /[$SIGMA]/i ? "ok 807\n" : "not ok 807\n"; - print $Sigma =~ /[$Sigma]/i ? "ok 808\n" : "not ok 808\n"; - print $Sigma =~ /[$sigma]/i ? "ok 809\n" : "not ok 809\n"; + ok ":$S3:" =~ /:(([$SIGMA])+):/i && $1 eq $S3 && $2 eq $sigma; + ok ":$S3:" =~ /:(([$Sigma])+):/i && $1 eq $S3 && $2 eq $sigma; + ok ":$S3:" =~ /:(([$sigma])+):/i && $1 eq $S3 && $2 eq $sigma; + } - print $sigma =~ /[$SIGMA]/i ? "ok 810\n" : "not ok 810\n"; - print $sigma =~ /[$Sigma]/i ? "ok 811\n" : "not ok 811\n"; - print $sigma =~ /[$sigma]/i ? "ok 812\n" : "not ok 812\n"; -} -{ - print "# parlez-vous?\n"; - - use charnames ':full'; - - print "fran\N{LATIN SMALL LETTER C}ais" =~ - /fran.ais/ && - $& eq "francais" ? - "ok 813\n" : "not ok 813\n"; - - print "fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais" =~ - /fran.ais/ && - $& eq "fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais" ? - "ok 814\n" : "not ok 814\n"; - - print "fran\N{LATIN SMALL LETTER C}ais" =~ - /fran\Cais/ && - $& eq "francais" ? - "ok 815\n" : "not ok 815\n"; - - print "franc\N{COMBINING CEDILLA}ais" =~ - /franc\C\Cais/ ? # COMBINING CEDILLA is two bytes when encoded - "ok 816\n" : "not ok 816\n"; - - print "fran\N{LATIN SMALL LETTER C}ais" =~ - /fran\Xais/ && - $& eq "francais" ? - "ok 817\n" : "not ok 817\n"; - - print "fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais" =~ - /fran\Xais/ && - $& eq "fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais" ? - "ok 818\n" : "not ok 818\n"; - - print "franc\N{COMBINING CEDILLA}ais" =~ - /fran\Xais/ && - $& eq "franc\N{COMBINING CEDILLA}ais" ? - "ok 819\n" : "not ok 819\n"; - - print "fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais" =~ - /fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais/ && - $& eq "fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais" ? - "ok 820\n" : "not ok 820\n"; - - print "franc\N{COMBINING CEDILLA}ais" =~ - /franc\N{COMBINING CEDILLA}ais/ && - $& eq "franc\N{COMBINING CEDILLA}ais" ? - "ok 821\n" : "not ok 821\n"; - - print "fran\N{LATIN SMALL LETTER C}ais" =~ - /fran(?:c\N{COMBINING CEDILLA}?|\N{LATIN SMALL LETTER C WITH CEDILLA})ais/ && - $& eq "francais" ? - "ok 822\n" : "not ok 822\n"; - - print "fran\N{LATIN SMALL LETTER C}ais" =~ - /fran(?:c\N{COMBINING CEDILLA}?|\N{LATIN SMALL LETTER C WITH CEDILLA})ais/ && - $& eq "francais" ? - "ok 823\n" : "not ok 823\n"; - - print "fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais" =~ - /fran(?:c\N{COMBINING CEDILLA}?|\N{LATIN SMALL LETTER C WITH CEDILLA})ais/ && - $& eq "fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais" ? - "ok 824\n" : "not ok 824\n"; - - print "franc\N{COMBINING CEDILLA}ais" =~ - /fran(?:c\N{COMBINING CEDILLA}?|\N{LATIN SMALL LETTER C WITH CEDILLA})ais/ && - $& eq "franc\N{COMBINING CEDILLA}ais" ? - "ok 825\n" : "not ok 825\n"; -} + { + use charnames ':full'; + local $Message = "Parlez-Vous " . + "Fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais?"; + + ok "Fran\N{LATIN SMALL LETTER C}ais" =~ /Fran.ais/ && + $& eq "Francais"; + ok "Fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais" =~ /Fran.ais/ && + $& eq "Fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais"; + ok "Fran\N{LATIN SMALL LETTER C}ais" =~ /Fran\Cais/ && + $& eq "Francais"; + # COMBINING CEDILLA is two bytes when encoded + ok "Franc\N{COMBINING CEDILLA}ais" =~ /Franc\C\Cais/; + ok "Fran\N{LATIN SMALL LETTER C}ais" =~ /Fran\Xais/ && + $& eq "Francais"; + ok "Fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais" =~ /Fran\Xais/ && + $& eq "Fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais"; + ok "Franc\N{COMBINING CEDILLA}ais" =~ /Fran\Xais/ && + $& eq "Franc\N{COMBINING CEDILLA}ais"; + ok "Fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais" =~ + /Fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais/ && + $& eq "Fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais"; + ok "Franc\N{COMBINING CEDILLA}ais" =~ /Franc\N{COMBINING CEDILLA}ais/ && + $& eq "Franc\N{COMBINING CEDILLA}ais"; + + my @f = ( + ["Fran\N{LATIN SMALL LETTER C}ais", "Francais"], + ["Fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais", + "Fran\N{LATIN SMALL LETTER C WITH CEDILLA}ais"], + ["Franc\N{COMBINING CEDILLA}ais", "Franc\N{COMBINING CEDILLA}ais"], + ); + foreach my $entry (@f) { + my ($subject, $match) = @$entry; + ok $subject =~ /Fran(?:c\N{COMBINING CEDILLA}?| + \N{LATIN SMALL LETTER C WITH CEDILLA})ais/x && + $& eq $match; + } + } -{ - print "# Does lingering (and useless) UTF8 flag mess up /i matching?\n"; { - my $regex = "ABcde"; - my $string = "abcDE\x{100}"; - chop($string); - if ($string =~ m/$regex/i) { - print "ok 826\n"; - } else { - print "not ok 826\n"; - } + local $Message = "Lingering (and useless) UTF8 flag doesn't mess up /i"; + my $pat = "ABcde"; + my $str = "abcDE\x{100}"; + chop $str; + ok $str =~ /$pat/i; + + $pat = "ABcde\x{100}"; + $str = "abcDE"; + chop $pat; + ok $str =~ /$pat/i; + + $pat = "ABcde\x{100}"; + $str = "abcDE\x{100}"; + chop $pat; + chop $str; + ok $str =~ /$pat/i; } + { - my $regex = "ABcde\x{100}"; - my $string = "abcDE"; - chop($regex); - if ($string =~ m/$regex/i) { - print "ok 827\n"; - } else { - print "not ok 827\n"; - } + use charnames ':full'; + local $Message = "LATIN SMALL LETTER SHARP S " . + "(\N{LATIN SMALL LETTER SHARP S})"; + + ok "\N{LATIN SMALL LETTER SHARP S}" =~ + /\N{LATIN SMALL LETTER SHARP S}/; + ok "\N{LATIN SMALL LETTER SHARP S}" =~ + /\N{LATIN SMALL LETTER SHARP S}/i; + ok "\N{LATIN SMALL LETTER SHARP S}" =~ + /[\N{LATIN SMALL LETTER SHARP S}]/; + ok "\N{LATIN SMALL LETTER SHARP S}" =~ + /[\N{LATIN SMALL LETTER SHARP S}]/i; + + ok "ss" =~ /\N{LATIN SMALL LETTER SHARP S}/i; + ok "SS" =~ /\N{LATIN SMALL LETTER SHARP S}/i; + ok "ss" =~ /[\N{LATIN SMALL LETTER SHARP S}]/i; + ok "SS" =~ /[\N{LATIN SMALL LETTER SHARP S}]/i; + + ok "\N{LATIN SMALL LETTER SHARP S}" =~ /ss/i; + ok "\N{LATIN SMALL LETTER SHARP S}" =~ /SS/i; + + local $Message = "Unoptimized named sequence in class"; + ok "ss" =~ /[\N{LATIN SMALL LETTER SHARP S}x]/i; + ok "SS" =~ /[\N{LATIN SMALL LETTER SHARP S}x]/i; + ok "\N{LATIN SMALL LETTER SHARP S}" =~ + /[\N{LATIN SMALL LETTER SHARP S}x]/; + ok "\N{LATIN SMALL LETTER SHARP S}" =~ + /[\N{LATIN SMALL LETTER SHARP S}x]/i; } + { - my $regex = "ABcde\x{100}"; - my $string = "abcDE\x{100}"; - chop($regex); - chop($string); - if ($string =~ m/$regex/i) { - print "ok 828\n"; - } else { - print "not ok 828\n"; - } + # More whitespace: U+0085, U+2028, U+2029\n"; + + # U+0085, U+00A0 need to be forced to be Unicode, the \x{100} does that. + SKIP: { + skip "EBCDIC platform", 4 if $IS_EBCDIC; + # Do \x{0015} and \x{0041} match \s in EBCDIC? + ok "<\x{100}\x{0085}>" =~ /<\x{100}\s>/, '\x{0085} in \s'; + ok "<\x{0085}>" =~ /<\v>/, '\x{0085} in \v'; + ok "<\x{100}\x{00A0}>" =~ /<\x{100}\s>/, '\x{00A0} in \s'; + ok "<\x{00A0}>" =~ /<\h>/, '\x{00A0} in \h'; + } + my @h = map {sprintf "%05x" => $_} 0x01680, 0x0180E, 0x02000 .. 0x0200A, + 0x0202F, 0x0205F, 0x03000; + my @v = map {sprintf "%05x" => $_} 0x02028, 0x02029; + + my @H = map {sprintf "%05x" => $_} 0x01361, 0x0200B, 0x02408, 0x02420, + 0x0303F, 0xE0020; + my @V = map {sprintf "%05x" => $_} 0x0008A .. 0x0008D, 0x00348, 0x10100, + 0xE005F, 0xE007C; + + for my $hex (@h) { + my $str = eval qq ["<\\x{$hex}>"]; + ok $str =~ /<\s>/, "\\x{$hex} in \\s"; + ok $str =~ /<\h>/, "\\x{$hex} in \\h"; + ok $str !~ /<\v>/, "\\x{$hex} not in \\v"; + } + + for my $hex (@v) { + my $str = eval qq ["<\\x{$hex}>"]; + ok $str =~ /<\s>/, "\\x{$hex} in \\s"; + ok $str =~ /<\v>/, "\\x{$hex} in \\v"; + ok $str !~ /<\h>/, "\\x{$hex} not in \\h"; + } + + for my $hex (@H) { + my $str = eval qq ["<\\x{$hex}>"]; + ok $str =~ /<\S>/, "\\x{$hex} in \\S"; + ok $str =~ /<\H>/, "\\x{$hex} in \\H"; + } + + for my $hex (@V) { + my $str = eval qq ["<\\x{$hex}>"]; + ok $str =~ /<\S>/, "\\x{$hex} in \\S"; + ok $str =~ /<\V>/, "\\x{$hex} in \\V"; + } } -} -{ - print "# more SIGMAs\n"; - my $SIGMA = "\x{03A3}"; # CAPITAL - my $Sigma = "\x{03C2}"; # SMALL FINAL - my $sigma = "\x{03C3}"; # SMALL + { + # . with /s should work on characters, as opposed to bytes + local $Message = ". with /s works on characters, not bytes"; - my $S3 = "$SIGMA$Sigma$sigma"; + my $s = "\x{e4}\x{100}"; + # This is not expected to match: the point is that + # neither should we get "Malformed UTF-8" warnings. + may_not_warn sub {$s =~ /\G(.+?)\n/gcs}, "No 'Malformed UTF-8' warning"; - print ":$S3:" =~ /:(($SIGMA)+):/i && $1 eq $S3 && $2 eq $sigma ? - "ok 829\n" : "not ok 829\n"; - print ":$S3:" =~ /:(($Sigma)+):/i && $1 eq $S3 && $2 eq $sigma ? - "ok 830\n" : "not ok 830\n"; - print ":$S3:" =~ /:(($sigma)+):/i && $1 eq $S3 && $2 eq $sigma ? - "ok 831\n" : "not ok 831\n"; + my @c; + push @c => $1 while $s =~ /\G(.)/gs; - print ":$S3:" =~ /:(([$SIGMA])+):/i && $1 eq $S3 && $2 eq $sigma ? - "ok 832\n" : "not ok 832\n"; - print ":$S3:" =~ /:(([$Sigma])+):/i && $1 eq $S3 && $2 eq $sigma ? - "ok 833\n" : "not ok 833\n"; - print ":$S3:" =~ /:(([$sigma])+):/i && $1 eq $S3 && $2 eq $sigma ? - "ok 834\n" : "not ok 834\n"; -} + local $" = ""; + iseq "@c", $s; -{ - print "# LATIN SMALL LETTER SHARP S\n"; + # Test only chars < 256 + my $t1 = "Q003\n\n\x{e4}\x{f6}\n\nQ004\n\n\x{e7}"; + my $r1 = ""; + while ($t1 =~ / \G ( .+? ) \n\s+ ( .+? ) ( $ | \n\s+ ) /xgcs) { + $r1 .= $1 . $2; + } - use charnames ':full'; + my $t2 = $t1 . "\x{100}"; # Repeat with a larger char + my $r2 = ""; + while ($t2 =~ / \G ( .+? ) \n\s+ ( .+? ) ( $ | \n\s+ ) /xgcs) { + $r2 .= $1 . $2; + } + $r2 =~ s/\x{100}//; - $test= 835; + iseq $r1, $r2; + } - ok("\N{LATIN SMALL LETTER SHARP S}" =~ /\N{LATIN SMALL LETTER SHARP S}/); - ok("\N{LATIN SMALL LETTER SHARP S}" =~ /\N{LATIN SMALL LETTER SHARP S}/i); - ok("\N{LATIN SMALL LETTER SHARP S}" =~ /[\N{LATIN SMALL LETTER SHARP S}]/); - ok("\N{LATIN SMALL LETTER SHARP S}" =~ /[\N{LATIN SMALL LETTER SHARP S}]/i); + { + local $Message = "Unicode lookbehind"; + ok "A\x{100}B" =~ /(?<=A.)B/; + ok "A\x{200}\x{300}B" =~ /(?<=A..)B/; + ok "\x{400}AB" =~ /(?<=\x{400}.)B/; + ok "\x{500}\x{600}B" =~ /(?<=\x{500}.)B/; + + # Original code also contained: + # ok "\x{500\x{600}}B" =~ /(?<=\x{500}.)B/; + # but that looks like a typo. + } - ok("ss" =~ /\N{LATIN SMALL LETTER SHARP S}/i); - ok("SS" =~ /\N{LATIN SMALL LETTER SHARP S}/i); - ok("ss" =~ /[\N{LATIN SMALL LETTER SHARP S}]/i); - ok("SS" =~ /[\N{LATIN SMALL LETTER SHARP S}]/i); - ok("\N{LATIN SMALL LETTER SHARP S}" =~ /ss/i); - ok("\N{LATIN SMALL LETTER SHARP S}" =~ /SS/i); -} + { + local $Message = 'UTF-8 hash keys and /$/'; + # http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters + # /2002-01/msg01327.html + + my $u = "a\x{100}"; + my $v = substr ($u, 0, 1); + my $w = substr ($u, 1, 1); + my %u = ($u => $u, $v => $v, $w => $w); + for (keys %u) { + my $m1 = /^\w*$/ ? 1 : 0; + my $m2 = $u {$_} =~ /^\w*$/ ? 1 : 0; + iseq $m1, $m2; + } + } -{ - print "# more whitespace: U+0085, U+2028, U+2029\n"; - # U+0085 needs to be forced to be Unicode, the \x{100} does that. - if ($ordA == 193) { - print "<\x{100}\x{0085}>" =~ /<\x{100}e>/ ? "ok 845\n" : "not ok 845\n"; - } else { - print "<\x{100}\x{0085}>" =~ /<\x{100}\s>/ ? "ok 845\n" : "not ok 845\n"; + { + local $BugId = "20020124.005"; + local $PatchId = "14795"; + local $Message = "s///eg"; + + for my $char ("a", "\x{df}", "\x{100}") { + my $x = "$char b $char"; + $x =~ s{($char)}{ + "c" =~ /c/; + "x"; + }ge; + iseq substr ($x, 0, 1), substr ($x, -1, 1); + } } - print "<\x{2028}>" =~ /<\s>/ ? "ok 846\n" : "not ok 846\n"; - print "<\x{2029}>" =~ /<\s>/ ? "ok 847\n" : "not ok 847\n"; -} -{ - print "# . with /s should work on characters, as opposed to bytes\n"; - my $s = "\x{e4}\x{100}"; + { + local $Message = "No SEGV in s/// and UTF-8"; + my $s = "s#\x{100}" x 4; + ok $s =~ s/[^\w]/ /g; + if ($ENV {REAL_POSIX_CC}) { + iseq $s, "s " x 4; + } + else { + iseq $s, "s \x{100}" x 4; + } + } + - # This is not expected to match: the point is that - # neither should we get "Malformed UTF-8" warnings. - print $s =~ /\G(.+?)\n/gcs ? - "not ok 848\n" : "ok 848\n"; + { + local $Message = "UTF-8 bug (maybe already known?)"; + my $u = "foo"; + $u =~ s/./\x{100}/g; + iseq $u, "\x{100}\x{100}\x{100}"; - my @c; + $u = "foobar"; + $u =~ s/[ao]/\x{100}/g; + iseq $u, "f\x{100}\x{100}b\x{100}r"; - while ($s =~ /\G(.)/gs) { - push @c, $1; + $u =~ s/\x{100}/e/g; + iseq $u, "feeber"; } - print join("", @c) eq $s ? "ok 849\n" : "not ok 849\n"; - my $t1 = "Q003\n\n\x{e4}\x{f6}\n\nQ004\n\n\x{e7}"; # test only chars < 256 - my $r1 = ""; - while ($t1 =~ / \G ( .+? ) \n\s+ ( .+? ) ( $ | \n\s+ ) /xgcs) { - $r1 .= $1 . $2; + { + local $Message = "UTF-8 bug with s///"; + # check utf8/non-utf8 mixtures + # try to force all float/anchored check combinations + + my $c = "\x{100}"; + my $subst; + for my $re ("xx.*$c", "x.*$c$c", "$c.*xx", "$c$c.*x", + "xx.*(?=$c)", "(?=$c).*xx",) { + ok "xxx" !~ /$re/; + ok +($subst = "xxx") !~ s/$re//; + } + for my $re ("xx.*$c*", "$c*.*xx") { + ok "xxx" =~ /$re/; + ok +($subst = "xxx") =~ s/$re//; + iseq $subst, ""; + } + for my $re ("xxy*", "y*xx") { + ok "xx$c" =~ /$re/; + ok +($subst = "xx$c") =~ s/$re//; + iseq $subst, $c; + ok "xy$c" !~ /$re/; + ok +($subst = "xy$c") !~ s/$re//; + } + for my $re ("xy$c*z", "x$c*yz") { + ok "xyz" =~ /$re/; + ok +($subst = "xyz") =~ s/$re//; + iseq $subst, ""; + } } - my $t2 = $t1 . "\x{100}"; # repeat with a larger char - my $r2 = ""; - while ($t2 =~ / \G ( .+? ) \n\s+ ( .+? ) ( $ | \n\s+ ) /xgcs) { - $r2 .= $1 . $2; + + { + local $Message = "qr /.../x"; + my $R = qr / A B C # D E/x; + ok "ABCDE" =~ $R && $& eq "ABC"; + ok "ABCDE" =~ /$R/ && $& eq "ABC"; + ok "ABCDE" =~ m/$R/ && $& eq "ABC"; + ok "ABCDE" =~ /($R)/ && $1 eq "ABC"; + ok "ABCDE" =~ m/($R)/ && $1 eq "ABC"; } - $r2 =~ s/\x{100}//; - print $r1 eq $r2 ? "ok 850\n" : "not ok 850\n"; -} -{ - print "# Unicode lookbehind\n"; - print "A\x{100}B" =~ /(?<=A.)B/ ? "ok 851\n" : "not ok 851\n"; - print "A\x{200}\x{300}B" =~ /(?<=A..)B/ ? "ok 852\n" : "not ok 852\n"; - print "\x{400}AB" =~ /(?<=\x{400}.)B/ ? "ok 853\n" : "not ok 853\n"; - print "\x{500\x{600}}B" =~ /(?<=\x{500}.)B/ ? "ok 854\n" : "not ok 854\n"; -} + { + local $BugId = "20020412.005"; + local $Message = "Correct pmop flags checked when empty pattern"; + + # Requires reuse of last successful pattern. + my $num = 123; + $num =~ /\d/; + for (0 .. 1) { + my $match = ?? + 0; + ok $match != $_, $Message, + sprintf "'match one' %s on %s iteration" => + $match ? 'succeeded' : 'failed', + $_ ? 'second' : 'first'; + } + $num =~ /(\d)/; + my $result = join "" => $num =~ //g; + iseq $result, $num; + } -{ - print "# UTF-8 hash keys and /\$/\n"; - # http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2002-01/msg01327.html - - my $u = "a\x{100}"; - my $v = substr($u,0,1); - my $w = substr($u,1,1); - my %u = ( $u => $u, $v => $v, $w => $w ); - my $i = 855; - for (keys %u) { - my $m1 = /^\w*$/ ? 1 : 0; - my $m2 = $u{$_}=~/^\w*$/ ? 1 : 0; - print $m1 == $m2 ? "ok $i\n" : "not ok $i # $m1 $m2\n"; - $i++; + + { + local $BugId = '20020630.002'; + local $Message = 'UTF-8 regex matches above 32k'; + for (['byte', "\x{ff}"], ['utf8', "\x{1ff}"]) { + my ($type, $char) = @$_; + for my $len (32000, 32768, 33000) { + my $s = $char . "f" x $len; + my $r = $s =~ /$char([f]*)/gc; + ok $r, $Message, "<$type x $len>"; + ok !$r || pos ($s) == $len + 1, $Message, + "<$type x $len>; pos = @{[pos $s]}"; + } + } } -} -{ - print "# [ID 20020124.005]\n"; - # Fixed by #14795. - my $i = 858; - for my $char ("a", "\x{df}", "\x{100}"){ - $x = "$char b $char"; - $x =~ s{($char)}{ - "c" =~ /c/; - "x"; - }ge; - print substr($x,0,1) eq substr($x,-1,1) ? - "ok $i\n" : "not ok $i # debug: $x\n"; - $i++; - } -} -{ - print "# SEGV in s/// and UTF-8\n"; - $s = "s#\x{100}" x 4; - $s =~ s/[^\w]/ /g; - print $s eq "s \x{100}" x 4 ? "ok 861\n" : "not ok 861\n"; -} + { + our $a = bless qr /foo/ => 'Foo'; + ok 'goodfood' =~ $a, "Reblessed qr // matches"; + iseq $a, '(?-xism:foo)', "Reblessed qr // stringifies"; + my $x = "\x{3fe}"; + my $z = my $y = "\317\276"; # Byte representation of $x + $a = qr /$x/; + ok $x =~ $a, "UTF-8 interpolation in qr //"; + ok "a$a" =~ $x, "Stringified qr // preserves UTF-8"; + ok "a$x" =~ /^a$a\z/, "Interpolated qr // preserves UTF-8"; + ok "a$x" =~ /^a(??{$a})\z/, + "Postponed interpolation of qr // preserves UTF-8"; + { + local $BugId = '17776'; + iseq length qr /##/x, 12, "## in qr // doesn't corrupt memory"; + } + { + use re 'eval'; + ok "$x$x" =~ /^$x(??{$x})\z/, + "Postponed UTF-8 string in UTF-8 re matches UTF-8"; + ok "$y$x" =~ /^$y(??{$x})\z/, + "Postponed UTF-8 string in non-UTF-8 re matches UTF-8"; + ok "$y$x" !~ /^$y(??{$y})\z/, + "Postponed non-UTF-8 string in non-UTF-8 re doesn't match UTF-8"; + ok "$x$x" !~ /^$x(??{$y})\z/, + "Postponed non-UTF-8 string in UTF-8 re doesn't match UTF-8"; + ok "$y$y" =~ /^$y(??{$y})\z/, + "Postponed non-UTF-8 string in non-UTF-8 re matches non-UTF8"; + ok "$x$y" =~ /^$x(??{$y})\z/, + "Postponed non-UTF-8 string in UTF-8 re matches non-UTF8"; + + $y = $z; # Reset $y after upgrade. + ok "$x$y" !~ /^$x(??{$x})\z/, + "Postponed UTF-8 string in UTF-8 re doesn't match non-UTF-8"; + ok "$y$y" !~ /^$y(??{$x})\z/, + "Postponed UTF-8 string in non-UTF-8 re doesn't match non-UTF-8"; + } + } -{ - print "# UTF-8 bug (maybe alreayd known?)\n"; - my $u; - $u = "foo"; - $u =~ s/./\x{100}/g; - print $u eq "\x{100}\x{100}\x{100}" ? "ok 862\n" : "not ok 862\n"; + { + local $PatchId = '18179'; + my $s = "\x{100}" x 5; + my $ok = $s =~ /(\x{100}{4})/; + my ($ord, $len) = (ord $1, length $1); + ok $ok && $ord == 0x100 && $len == 4, "No panic: end_shift"; + } - $u = "foobar"; - $u =~ s/[ao]/\x{100}/g; - print $u eq "f\x{100}\x{100}b\x{100}r" ? "ok 863\n" : "not ok 863\n"; - $u =~ s/\x{100}/e/g; - print $u eq "feeber" ? "ok 864\n" : "not ok 864\n"; -} + { + local $BugId = '15763'; + our $a = "x\x{100}"; + chop $a; # Leaves the UTF-8 flag + $a .= "y"; # 1 byte before 'y'. -{ - print "# UTF-8 bug with s///\n"; - # check utf8/non-utf8 mixtures - # try to force all float/anchored check combinations - my $c = "\x{100}"; - $test = 865; - my $subst; - for my $re ( - "xx.*$c", "x.*$c$c", "$c.*xx", "$c$c.*x", "xx.*(?=$c)", "(?=$c).*xx", - ) { - print "xxx" =~ /$re/ ? "not ok $test\n" : "ok $test\n"; - ++$test; - print +($subst = "xxx") =~ s/$re// ? "not ok $test\n" : "ok $test\n"; - ++$test; - } - for my $re ("xx.*$c*", "$c*.*xx") { - print "xxx" =~ /$re/ ? "ok $test\n" : "not ok $test\n"; - ++$test; - ($subst = "xxx") =~ s/$re//; - print $subst eq '' ? "ok $test\n" : "not ok $test\t# $subst\n"; - ++$test; - } - for my $re ("xxy*", "y*xx") { - print "xx$c" =~ /$re/ ? "ok $test\n" : "not ok $test\n"; - ++$test; - ($subst = "xx$c") =~ s/$re//; - print $subst eq $c ? "ok $test\n" : "not ok $test\n"; - ++$test; - print "xy$c" =~ /$re/ ? "not ok $test\n" : "ok $test\n"; - ++$test; - print +($subst = "xy$c") =~ /$re/ ? "not ok $test\n" : "ok $test\n"; - ++$test; - } - for my $re ("xy$c*z", "x$c*yz") { - print "xyz" =~ /$re/ ? "ok $test\n" : "not ok $test\n"; - ++$test; - ($subst = "xyz") =~ s/$re//; - print $subst eq '' ? "ok $test\n" : "not ok $test\n"; - ++$test; - } -} + ok $a =~ /^\C/, 'match one \C on 1-byte UTF-8'; + ok $a =~ /^\C{1}/, 'match \C{1}'; -{ - print "# qr/.../x\n"; - $test = 893; + ok $a =~ /^\Cy/, 'match \Cy'; + ok $a =~ /^\C{1}y/, 'match \C{1}y'; - my $R = qr/ A B C # D E/x; + ok $a !~ /^\C\Cy/, q {don't match two \Cy}; + ok $a !~ /^\C{2}y/, q {don't match \C{2}y}; - print eval {"ABCDE" =~ $R} ? "ok $test\n" : "not ok $test\n"; - $test++; + $a = "\x{100}y"; # 2 bytes before "y" - print eval {"ABCDE" =~ m/$R/} ? "ok $test\n" : "not ok $test\n"; - $test++; + ok $a =~ /^\C/, 'match one \C on 2-byte UTF-8'; + ok $a =~ /^\C{1}/, 'match \C{1}'; + ok $a =~ /^\C\C/, 'match two \C'; + ok $a =~ /^\C{2}/, 'match \C{2}'; - print eval {"ABCDE" =~ m/($R)/} ? "ok $test\n" : "not ok $test\n"; - $test++; -} + ok $a =~ /^\C\C\C/, 'match three \C on 2-byte UTF-8 and a byte'; + ok $a =~ /^\C{3}/, 'match \C{3}'; -{ - print "# illegal Unicode properties\n"; - $test = 896; + ok $a =~ /^\C\Cy/, 'match two \C'; + ok $a =~ /^\C{2}y/, 'match \C{2}'; - print eval { "a" =~ /\pq / } ? "not ok $test\n" : "ok $test\n"; - $test++; + ok $a !~ /^\C\C\Cy/, q {don't match three \Cy}; + ok $a !~ /^\C{2}\Cy/, q {don't match \C{2}\Cy}; + ok $a !~ /^\C{3}y/, q {don't match \C{3}y}; - print eval { "a" =~ /\p{qrst} / } ? "not ok $test\n" : "ok $test\n"; - $test++; -} + $a = "\x{1000}y"; # 3 bytes before "y" -{ - print "# [ID 20020412.005] wrong pmop flags checked when empty pattern\n"; - # requires reuse of last successful pattern - $test = 898; - $test =~ /\d/; - for (0 .. 1) { - my $match = ?? + 0; - if ($match != $_) { - print "ok $test\n"; - } else { - printf "not ok %s\t# 'match once' %s on %s iteration\n", $test, - $match ? 'succeeded' : 'failed', $_ ? 'second' : 'first'; - } - ++$test; + ok $a =~ /^\C/, 'match one \C on three-byte UTF-8'; + ok $a =~ /^\C{1}/, 'match \C{1}'; + ok $a =~ /^\C\C/, 'match two \C'; + ok $a =~ /^\C{2}/, 'match \C{2}'; + ok $a =~ /^\C\C\C/, 'match three \C'; + ok $a =~ /^\C{3}/, 'match \C{3}'; + + ok $a =~ /^\C\C\C\C/, 'match four \C on three-byte UTF-8 and a byte'; + ok $a =~ /^\C{4}/, 'match \C{4}'; + + ok $a =~ /^\C\C\Cy/, 'match three \Cy'; + ok $a =~ /^\C{3}y/, 'match \C{3}y'; + + ok $a !~ /^\C\C\C\Cy/, q {don't match four \Cy}; + ok $a !~ /^\C{4}y/, q {don't match \C{4}y}; } - $test =~ /(\d)/; - my $result = join '', $test =~ //g; - if ($result eq $test) { - print "ok $test\n"; - } else { - printf "not ok %s\t# expected '%s', got '%s'\n", $test, $test, $result; + + + { + local $\; + $_ = 'aaaaaaaaaa'; + utf8::upgrade($_); chop $_; $\="\n"; + ok /[^\s]+/, 'm/[^\s]/ utf8'; + ok /[^\d]+/, 'm/[^\d]/ utf8'; + ok +($a = $_, $_ =~ s/[^\s]+/./g), 's/[^\s]/ utf8'; + ok +($a = $_, $a =~ s/[^\d]+/./g), 's/[^\s]/ utf8'; } - ++$test; -} -print "# user-defined character properties\n"; -sub InKana1 { - return <<'END'; -3040 309F -30A0 30FF -END -} + { + local $BugId = '15397'; + local $Message = 'UTF-8 matching'; + ok "\x{100}" =~ /\x{100}/; + ok "\x{100}" =~ /(\x{100})/; + ok "\x{100}" =~ /(\x{100}){1}/; + ok "\x{100}\x{100}" =~ /(\x{100}){2}/; + ok "\x{100}\x{100}" =~ /(\x{100})(\x{100})/; + } -sub InKana2 { - return <<'END'; -+utf8::InHiragana -+utf8::InKatakana -END -} -sub InKana3 { - return <<'END'; -+utf8::InHiragana -+utf8::InKatakana --utf8::IsCn -END -} + { + local $BugId = '7471'; + local $Message = 'Neither ()* nor ()*? sets $1 when matched 0 times'; + local $_ = 'CD'; + ok /(AB)*?CD/ && !defined $1; + ok /(AB)*CD/ && !defined $1; + } -sub InNotKana { - return <<'END'; -!utf8::InHiragana --utf8::InKatakana -+utf8::IsCn -END -} -$test = 901; + { + local $BugId = '3547'; + local $Message = "Caching shouldn't prevent match"; + my $pattern = "^(b+?|a){1,2}c"; + ok "bac" =~ /$pattern/ && $1 eq 'a'; + ok "bbac" =~ /$pattern/ && $1 eq 'a'; + ok "bbbac" =~ /$pattern/ && $1 eq 'a'; + ok "bbbbac" =~ /$pattern/ && $1 eq 'a'; + } -print "\x{3040}" =~ /\p{InKana1}/ ? "ok $test\n" : "not ok $test\n"; $test++; -print "\x{303F}" =~ /\P{InKana1}/ ? "ok $test\n" : "not ok $test\n"; $test++; -print "\x{3040}" =~ /\p{InKana2}/ ? "ok $test\n" : "not ok $test\n"; $test++; -print "\x{303F}" =~ /\P{InKana2}/ ? "ok $test\n" : "not ok $test\n"; $test++; -print "\x{3041}" =~ /\p{InKana3}/ ? "ok $test\n" : "not ok $test\n"; $test++; -print "\x{3040}" =~ /\P{InKana3}/ ? "ok $test\n" : "not ok $test\n"; $test++; + { + local $BugId = '18232'; + local $Message = '$1 should keep UTF-8 ness'; + ok "\x{100}" =~ /(.)/; + iseq $1, "\x{100}", '$1 is UTF-8'; + { 'a' =~ /./; } + iseq $1, "\x{100}", '$1 is still UTF-8'; + isneq $1, "\xC4\x80", '$1 is not non-UTF-8'; + } -print "\x{3040}" =~ /\p{InNotKana}/ ? "ok $test\n" : "not ok $test\n"; $test++; -print "\x{3041}" =~ /\P{InNotKana}/ ? "ok $test\n" : "not ok $test\n"; $test++; -sub InConsonant { # Not EBCDIC-aware. - return <<EOF; -0061 007f --0061 --0065 --0069 --006f --0075 -EOF -} + { + local $BugId = '19767'; + local $Message = "Optimizer doesn't prematurely reject match"; + use utf8; -print "d" =~ /\p{InConsonant}/ ? "ok $test\n" : "not ok $test\n"; $test++; -print "e" =~ /\P{InConsonant}/ ? "ok $test\n" : "not ok $test\n"; $test++; - -{ - print "# [ID 20020630.002] utf8 regex only matches 32k\n"; - $test = 911; - for ([ 'byte', "\x{ff}" ], [ 'utf8', "\x{1ff}" ]) { - my($type, $char) = @$_; - for my $len (32000, 32768, 33000) { - my $s = $char . "f" x $len; - my $r = $s =~ /$char([f]*)/gc; - print $r ? "ok $test\n" : "not ok $test\t# <$type x $len> fail\n"; - ++$test; - print +(!$r or pos($s) == $len + 1) ? "ok $test\n" - : "not ok $test\t# <$type x $len> pos @{[ pos($s) ]}\n"; - ++$test; - } + my $attr = 'Name-1'; + my $NormalChar = qr /[\p{IsDigit}\p{IsLower}\p{IsUpper}]/; + my $NormalWord = qr /${NormalChar}+?/; + my $PredNameHyphen = qr /^${NormalWord}(\-${NormalWord})*?$/; + + $attr =~ /^$/; + ok $attr =~ $PredNameHyphen; # Original test. + + "a" =~ m/[b]/; + ok "0" =~ /\p{N}+\z/; # Variant. } -} -$test = 923; -$a = bless qr/foo/, 'Foo'; -print(('goodfood' =~ $a ? '' : 'not '), - "ok $test\t# reblessed qr// matches\n"); -++$test; + { + local $BugId = '20683'; + local $Message = "(??{ }) doesn't return stale values"; + our $p = 1; + foreach (1, 2, 3, 4) { + $p ++ if /(??{ $p })/ + } + iseq $p, 5; -print(($a eq '(?-xism:foo)' ? '' : 'not '), - "ok $test\t# reblessed qr// stringizes\n"); -++$test; + { + package P; + $a = 1; + sub TIESCALAR {bless []} + sub FETCH {$a ++} + } + tie $p, "P"; + foreach (1, 2, 3, 4) { + /(??{ $p })/ + } + iseq $p, 5; + } -$x = "\x{3fe}"; -$z=$y = "\317\276"; # $y is byte representation of $x -$a = qr/$x/; -print(($x =~ $a ? '' : 'not '), "ok $test - utf8 interpolation in qr//\n"); -++$test; + { + # Subject: Odd regexp behavior + # From: Markus Kuhn <Markus.Kuhn@cl.cam.ac.uk> + # Date: Wed, 26 Feb 2003 16:53:12 +0000 + # Message-Id: <E18o4nw-0008Ly-00@wisbech.cl.cam.ac.uk> + # To: perl-unicode@perl.org -print(("a$a" =~ $x ? '' : 'not '), - "ok $test - stringifed qr// preserves utf8\n"); -++$test; + local $Message = 'Markus Kuhn 2003-02-26'; + + my $x = "\x{2019}\nk"; + ok $x =~ s/(\S)\n(\S)/$1 $2/sg; + ok $x eq "\x{2019} k"; -print(("a$x" =~ /^a$a\z/ ? '' : 'not '), - "ok $test - interpolated qr// preserves utf8\n"); -++$test; + $x = "b\nk"; + ok $x =~ s/(\S)\n(\S)/$1 $2/sg; + ok $x eq "b k"; -print(("a$x" =~ /^a(??{$a})\z/ ? '' : 'not '), - "ok $test - postponed interpolation of qr// preserves utf8\n"); -++$test; + ok "\x{2019}" =~ /\S/; + } -print((length(qr/##/x) == 12 ? '' : 'not '), - "ok $test - ## in qr// doesn't corrupt memory [perl #17776]\n"); -++$test; -{ use re 'eval'; + { + local $BugId = '21411'; + local $Message = "(??{ .. }) in split doesn't corrupt its stack"; + our $i; + ok '-1-3-5-' eq join '', split /((??{$i++}))/, '-1-3-5-'; + no warnings 'deprecated', 'syntax'; + split /(?{'WOW'})/, 'abc'; + local $" = "|"; + iseq "@_", "a|b|c"; + } -print(("$x$x" =~ /^$x(??{$x})\z/ ? '' : 'not '), - "ok $test - postponed utf8 string in utf8 re matches utf8\n"); -++$test; -print(("$y$x" =~ /^$y(??{$x})\z/ ? '' : 'not '), - "ok $test - postponed utf8 string in non-utf8 re matches utf8\n"); -++$test; + { + # XXX DAPM 13-Apr-06. Recursive split is still broken. It's only luck it + # hasn't been crashing. Disable this test until it is fixed properly. + # XXX also check what it returns rather than just doing ok(1,...) + # split /(?{ split "" })/, "abc"; + local $TODO = "Recursive split is still broken"; + ok 0, 'cache_re & "(?{": it dumps core in 5.6.1 & 5.8.0'; + } -print(("$y$x" !~ /^$y(??{$y})\z/ ? '' : 'not '), - "ok $test - postponed non-utf8 string in non-utf8 re doesn't match utf8\n"); -++$test; -print(("$x$x" !~ /^$x(??{$y})\z/ ? '' : 'not '), - "ok $test - postponed non-utf8 string in utf8 re doesn't match utf8\n"); -++$test; + { + ok "\x{100}\n" =~ /\x{100}\n$/, "UTF-8 length cache and fbm_compile"; + } -print(("$y$y" =~ /^$y(??{$y})\z/ ? '' : 'not '), - "ok $test - postponed non-utf8 string in non-utf8 re matches non-utf8\n"); -++$test; -print(("$x$y" =~ /^$x(??{$y})\z/ ? '' : 'not '), - "ok $test - postponed non-utf8 string in utf8 re matches non-utf8\n"); -++$test; -$y = $z; # reset $y after upgrade + { + package Str; + use overload q /""/ => sub {${$_ [0]};}; + sub new {my ($c, $v) = @_; bless \$v, $c;} -print(("$x$y" !~ /^$x(??{$x})\z/ ? '' : 'not '), - "ok $test - postponed utf8 string in utf8 re doesn't match non-utf8\n"); -++$test; -$y = $z; # reset $y after upgrade + package main; + $_ = Str -> new ("a\x{100}/\x{100}b"); + ok join (":", /\b(.)\x{100}/g) eq "a:/", "re_intuit_start and PL_bostr"; + } -print(("$y$y" !~ /^$y(??{$x})\z/ ? '' : 'not '), - "ok $test - postponed utf8 string in non-utf8 re doesn't match non-utf8\n"); -++$test; -} # no re 'eval' + { + local $BugId = '17757'; + $_ = "code: 'x' { '...' }\n"; study; + my @x; push @x, $& while m/'[^\']*'/gx; + local $" = ":"; + iseq "@x", "'x':'...'", "Parse::RecDescent triggered infinite loop"; + } -print "# more user-defined character properties\n"; -sub IsSyriac1 { - return <<'END'; -0712 072C -0730 074A -END -} + { + my $re = qq /^([^X]*)X/; + utf8::upgrade ($re); + ok "\x{100}X" =~ /$re/, "S_cl_and ANYOF_UNICODE & ANYOF_INVERTED"; + } -ok("\x{0712}" =~ /\p{IsSyriac1}/, '\x{0712}, \p{IsSyriac1}'); -ok("\x{072F}" =~ /\P{IsSyriac1}/, '\x{072F}, \P{IsSyriac1}'); -sub Syriac1 { - return <<'END'; -0712 072C -0730 074A -END -} + { + local $BugId = '22354'; + sub func ($) { + ok "a\nb" !~ /^b/, "Propagated modifier; $_[0]"; + ok "a\nb" =~ /^b/m, "Propagated modifier; $_[0] - with /m"; + } + func "standalone"; + $_ = "x"; s/x/func "in subst"/e; + $_ = "x"; s/x/func "in multiline subst"/em; + + # + # Next two give 'panic: malloc'. + # Outcommented, using two TODOs. + # + local $TODO = 'panic: malloc'; + local $Message = 'Postponed regexp and propaged modifier'; + # ok 0 for 1 .. 2; + SKIP: { + skip "panic: malloc", 2; + $_ = "x"; /x(?{func "in regexp"})/; + $_ = "x"; /x(?{func "in multiline regexp"})/m; + } + } -ok("\x{0712}" =~ /\p{Syriac1}/, '\x{0712}, \p{Syriac1}'); -ok("\x{072F}" =~ /\P{Syriac1}/, '\x{072F}, \p{Syriac1}'); -print "# user-defined character properties may lack \\n at the end\n"; -sub InGreekSmall { return "03B1\t03C9" } -sub InGreekCapital { return "0391\t03A9\n-03A2" } + { + local $BugId = '19049'; + $_ = "abcdef\n"; + my @x = m/./g; + iseq "abcde", $`, 'Global match sets $`'; + } -ok("\x{03C0}" =~ /\p{InGreekSmall}/, "Small pi"); -ok("\x{03C2}" =~ /\p{InGreekSmall}/, "Final sigma"); -ok("\x{03A0}" =~ /\p{InGreekCapital}/, "Capital PI"); -ok("\x{03A2}" =~ /\P{InGreekCapital}/, "Reserved"); -sub AsciiHexAndDash { - return <<'END'; -+utf8::ASCII_Hex_Digit -+utf8::Dash -END -} + { + ok "123\x{100}" =~ /^.*1.*23\x{100}$/, + 'UTF-8 + multiple floating substr'; + } -ok("-" =~ /\p{Dash}/, "'-' is Dash"); -ok("A" =~ /\p{ASCII_Hex_Digit}/, "'A' is ASCII_Hex_Digit"); -ok("-" =~ /\p{AsciiHexAndDash}/, "'-' is AsciiHexAndDash"); -ok("A" =~ /\p{AsciiHexAndDash}/, "'A' is AsciiHexAndDash"); - -{ - print "# Change #18179\n"; - # previously failed with "panic: end_shift - my $s = "\x{100}" x 5; - my $ok = $s =~ /(\x{100}{4})/; - my($ord, $len) = (ord $1, length $1); - print +($ok && $ord == 0x100 && $len == 4) - ? "ok $test\n" : "not ok $test\t# [#18179] $ok/$ord/$len\n"; - ++$test; -} -{ - print "# [perl #15763]\n"; + { + local $Message = '<20030808193656.5109.1@llama.ni-s.u-net.com>'; + + # LATIN SMALL/CAPITAL LETTER A WITH MACRON + ok " \x{101}" =~ qr/\x{100}/i; - $a = "x\x{100}"; - chop $a; # but leaves the UTF-8 flag - $a .= "y"; # 1 byte before "y" + # LATIN SMALL/CAPITAL LETTER A WITH RING BELOW + ok " \x{1E01}" =~ qr/\x{1E00}/i; - ok($a =~ /^\C/, 'match one \C on 1-byte UTF-8'); - ok($a =~ /^\C{1}/, 'match \C{1}'); + # DESERET SMALL/CAPITAL LETTER LONG I + ok " \x{10428}" =~ qr/\x{10400}/i; - ok($a =~ /^\Cy/, 'match \Cy'); - ok($a =~ /^\C{1}y/, 'match \C{1}y'); + # LATIN SMALL/CAPITAL LETTER A WITH RING BELOW + 'X' + ok " \x{1E01}x" =~ qr/\x{1E00}X/i; + } - $a = "\x{100}y"; # 2 bytes before "y" - ok($a =~ /^\C/, 'match one \C on 2-byte UTF-8'); - ok($a =~ /^\C{1}/, 'match \C{1}'); - ok($a =~ /^\C\C/, 'match two \C'); - ok($a =~ /^\C{2}/, 'match \C{2}'); + { + # [perl #23769] Unicode regex broken on simple example + # regrepeat() didn't handle UTF-8 EXACT case right. + local $BugId = '23769'; + my $Mess = 'regrepeat() handles UTF-8 EXACT case right'; + local $Message = $Mess; - ok($a =~ /^\C\C\C/, 'match three \C on 2-byte UTF-8 and a byte'); - ok($a =~ /^\C{3}/, 'match \C{3}'); + my $s = "\x{a0}\x{a0}\x{a0}\x{100}"; chop $s; - ok($a =~ /^\C\Cy/, 'match two \C'); - ok($a =~ /^\C{2}y/, 'match \C{2}'); + ok $s =~ /\x{a0}/; + ok $s =~ /\x{a0}+/; + ok $s =~ /\x{a0}\x{a0}/; - ok($a !~ /^\C\C\Cy/, q{don't match three \Cy}); - ok($a !~ /^\C{2}\Cy/, q{don't match \C{3}y}); + $Message = "$Mess (easy variant)"; + ok "aaa\x{100}" =~ /(a+)/; + iseq $1, "aaa"; - $a = "\x{1000}y"; # 3 bytes before "y" + $Message = "$Mess (easy invariant)"; + ok "aaa\x{100} " =~ /(a+?)/; + iseq $1, "a"; - ok($a =~ /^\C/, 'match one \C on three-byte UTF-8'); - ok($a =~ /^\C{1}/, 'match \C{1}'); - ok($a =~ /^\C\C/, 'match two \C'); - ok($a =~ /^\C{2}/, 'match \C{2}'); - ok($a =~ /^\C\C\C/, 'match three \C'); - ok($a =~ /^\C{3}/, 'match \C{3}'); + $Message = "$Mess (regrepeat variant)"; + ok "\xa0\xa0\xa0\x{100} " =~ /(\xa0+?)/; + iseq $1, "\xa0"; - ok($a =~ /^\C\C\C\C/, 'match four \C on three-byte UTF-8 and a byte'); - ok($a =~ /^\C{4}/, 'match \C{4}'); + $Message = "$Mess (regrepeat invariant)"; + ok "\xa0\xa0\xa0\x{100}" =~ /(\xa0+)/; + iseq $1, "\xa0\xa0\xa0"; - ok($a =~ /^\C\C\Cy/, 'match three \Cy'); - ok($a =~ /^\C{3}y/, 'match \C{3}y'); + $Message = "$Mess (hard variant)"; + ok "\xa0\xa1\xa0\xa1\xa0\xa1\x{100}" =~ /((?:\xa0\xa1)+?)/; + iseq $1, "\xa0\xa1"; - ok($a !~ /^\C\C\C\C\y/, q{don't match four \Cy}); - ok($a !~ /^\C{4}y/, q{don't match \C{4}y}); -} + $Message = "$Mess (hard invariant)"; + ok "ababab\x{100} " =~ /((?:ab)+)/; + iseq $1, 'ababab'; -$_ = 'aaaaaaaaaa'; -utf8::upgrade($_); chop $_; $\="\n"; -ok(/[^\s]+/, "m/[^\s]/ utf8"); -ok(/[^\d]+/, "m/[^\d]/ utf8"); -ok(($a = $_, $_ =~ s/[^\s]+/./g), "s/[^\s]/ utf8"); -ok(($a = $_, $a =~ s/[^\d]+/./g), "s/[^\s]/ utf8"); - -ok("\x{100}" =~ /\x{100}/, "[perl #15397]"); -ok("\x{100}" =~ /(\x{100})/, "[perl #15397]"); -ok("\x{100}" =~ /(\x{100}){1}/, "[perl #15397]"); -ok("\x{100}\x{100}" =~ /(\x{100}){2}/, "[perl #15397]"); -ok("\x{100}\x{100}" =~ /(\x{100})(\x{100})/, "[perl #15397]"); - -$x = "CD"; -$x =~ /(AB)*?CD/; -ok(!defined $1, "[perl #7471]"); - -$x = "CD"; -$x =~ /(AB)*CD/; -ok(!defined $1, "[perl #7471]"); - -$pattern = "^(b+?|a){1,2}c"; -ok("bac" =~ /$pattern/ && $1 eq 'a', "[perl #3547]"); -ok("bbac" =~ /$pattern/ && $1 eq 'a', "[perl #3547]"); -ok("bbbac" =~ /$pattern/ && $1 eq 'a', "[perl #3547]"); -ok("bbbbac" =~ /$pattern/ && $1 eq 'a', "[perl #3547]"); - -{ - # [perl #18232] - "\x{100}" =~ /(.)/; - ok( $1 eq "\x{100}", '$1 is utf-8 [perl #18232]' ); - { 'a' =~ /./; } - ok( $1 eq "\x{100}", '$1 is still utf-8' ); - ok( $1 ne "\xC4\x80", '$1 is not non-utf-8' ); -} + ok "\xa0\xa1\xa0\xa1\xa0\xa1\x{100}" =~ /((?:\xa0\xa1)+)/; + iseq $1, "\xa0\xa1\xa0\xa1\xa0\xa1"; -{ - use utf8; - my $attr = 'Name-1' ; + ok "ababab\x{100} " =~ /((?:ab)+?)/; + iseq $1, "ab"; - my $NormalChar = qr/[\p{IsDigit}\p{IsLower}\p{IsUpper}]/; - my $NormalWord = qr/${NormalChar}+?/; - my $PredNameHyphen = qr/^${NormalWord}(\-${NormalWord})*?$/; + $Message = "Don't match first byte of UTF-8 representation"; + ok "\xc4\xc4\xc4" !~ /(\x{100}+)/; + ok "\xc4\xc4\xc4" !~ /(\x{100}+?)/; + ok "\xc4\xc4\xc4" !~ /(\x{100}++)/; + } - $attr =~ /^$/; - ok( $attr =~ $PredNameHyphen, "[perl #19767] original test" ); -} -{ - use utf8; - "a" =~ m/[b]/; - ok ( "0" =~ /\p{N}+\z/, "[perl #19767] variant test" ); -} + { + for (120 .. 130) { + my $head = 'x' x $_; + local $Message = q [Don't misparse \x{...} in regexp ] . + q [near 127 char EXACT limit]; + for my $tail ('\x{0061}', '\x{1234}', '\x61') { + eval_ok qq ["$head$tail" =~ /$head$tail/]; + } + local $Message = q [Don't misparse \N{...} in regexp ] . + q [near 127 char EXACT limit]; + for my $tail ('\N{SNOWFLAKE}') { + eval_ok qq [use charnames ':full'; + "$head$tail" =~ /$head$tail/]; + } + } + } -{ - $p = 1; - foreach (1,2,3,4) { - $p++ if /(??{ $p })/ + { + # perl panic: pp_match start/end pointers + local $BugId = '25269'; + iseq "a-bc", eval {my ($x, $y) = "bca" =~ /^(?=.*(a)).*(bc)/; "$x-$y"}, + 'Captures can move backwards in string'; } - ok ($p == 5, "[perl #20683] (??{ }) returns stale values"); - { package P; $a=1; sub TIESCALAR { bless[] } sub FETCH { $a++ } } - tie $p, P; - foreach (1,2,3,4) { - /(??{ $p })/ + + + { + local $BugId = '27940'; # \cA not recognized in character classes + ok "a\cAb" =~ /\cA/, '\cA in pattern'; + ok "a\cAb" =~ /[\cA]/, '\cA in character class'; + ok "a\cAb" =~ /[\cA-\cB]/, '\cA in character class range'; + ok "abc" =~ /[^\cA-\cB]/, '\cA in negated character class range'; + ok "a\cBb" =~ /[\cA-\cC]/, '\cB in character class range'; + ok "a\cCbc" =~ /[^\cA-\cB]/, '\cC in negated character class range'; + ok "a\cAb" =~ /(??{"\cA"})/, '\cA in ??{} pattern'; + ok "ab" !~ /a\cIb/x, '\cI in pattern'; } - ok ( $p == 5, "(??{ }) returns stale values"); -} -{ - # Subject: Odd regexp behavior - # From: Markus Kuhn <Markus.Kuhn@cl.cam.ac.uk> - # Date: Wed, 26 Feb 2003 16:53:12 +0000 - # Message-Id: <E18o4nw-0008Ly-00@wisbech.cl.cam.ac.uk> - # To: perl-unicode@perl.org - - $x = "\x{2019}\nk"; $x =~ s/(\S)\n(\S)/$1 $2/sg; - ok($x eq "\x{2019} k", "Markus Kuhn 2003-02-26"); - $x = "b\nk"; $x =~ s/(\S)\n(\S)/$1 $2/sg; - ok($x eq "b k", "Markus Kuhn 2003-02-26"); + { + # perl #28532: optional zero-width match at end of string is ignored + local $BugId = '28532'; + ok "abc" =~ /^abc(\z)?/ && defined($1), + 'Optional zero-width match at end of string'; + ok "abc" =~ /^abc(\z)??/ && !defined($1), + 'Optional zero-width match at end of string'; + } - ok("\x{2019}" =~ /\S/, "Markus Kuhn 2003-02-26"); -} -{ - my $i; - ok('-1-3-5-' eq join('', split /((??{$i++}))/, '-1-3-5-'), - "[perl #21411] (??{ .. }) corrupts split's stack"); - split /(?{'WOW'})/, 'abc'; - ok('a|b|c' eq join ('|', @_), - "[perl #21411] (?{ .. }) version of the above"); -} -{ - # XXX DAPM 13-Apr-06. Recursive split is still broken. It's only luck it - # hasn't been crashing. Disable this test until it is fixed properly. - # XXX also check what it returns rather than just doing ok(1,...) - # split /(?{ split "" })/, "abc"; - ok(1,'cache_re & "(?{": it dumps core in 5.6.1 & 5.8.0'); -} + { # TRIE related + our @got = (); + "words" =~ /(word|word|word)(?{push @got, $1})s$/; + iseq @got, 1, "TRIE optimation"; -{ - ok("\x{100}\n" =~ /\x{100}\n$/, "UTF8 length cache and fbm_compile"); -} + @got = (); + "words" =~ /(word|word|word)(?{push @got,$1})s$/i; + iseq @got, 1,"TRIEF optimisation"; -{ - package Str; - use overload q/""/ => sub { ${$_[0]}; }; - sub new { my ($c, $v) = @_; bless \$v, $c; } + my @nums = map {int rand 1000} 1 .. 100; + my $re = "(" . (join "|", @nums) . ")"; + $re = qr/\b$re\b/; - package main; - $_ = Str->new("a\x{100}/\x{100}b"); - ok(join(":", /\b(.)\x{100}/g) eq "a:/", "re_intuit_start and PL_bostr"); -} + foreach (@nums) { + ok $_ =~ /$re/, "Trie nums"; + } -{ - $_ = "code: 'x' { '...' }\n"; study; - my @x; push @x, $& while m/'[^\']*'/gx; - ok(join(":", @x) eq "'x':'...'", - "[perl #17757] Parse::RecDescent triggers infinite loop"); -} + $_ = join " ", @nums; + @got = (); + push @got, $1 while /$re/g; -{ - my $re = qq/^([^X]*)X/; - utf8::upgrade($re); - ok("\x{100}X" =~ /$re/, "S_cl_and ANYOF_UNICODE & ANYOF_INVERTED"); -} + my %count; + $count {$_} ++ for @got; + my $ok = 1; + for (@nums) { + $ok = 0 if --$count {$_} < 0; + } + ok $ok, "Trie min count matches"; + } -# bug #22354 -sub func ($) { - ok( "a\nb" !~ /^b/, $_[0] ); - ok( "a\nb" =~ /^b/m, "$_[0] - with /m" ); -} -func "standalone"; -$_ = "x"; s/x/func "in subst"/e; -$_ = "x"; s/x/func "in multiline subst"/em; -#$_ = "x"; /x(?{func "in regexp"})/; -#$_ = "x"; /x(?{func "in multiline regexp"})/m; -# bug RT#19049 -$_="abcdef\n"; -@x = m/./g; -ok("abcde" eq "$`", 'RT#19049 - global match not setting $`'); + { + # TRIE related + # LATIN SMALL/CAPITAL LETTER A WITH MACRON + ok "foba \x{101}foo" =~ qr/(foo|\x{100}foo|bar)/i && + $1 eq "\x{101}foo", + "TRIEF + LATIN SMALL/CAPITAL LETTER A WITH MACRON"; + + # LATIN SMALL/CAPITAL LETTER A WITH RING BELOW + ok "foba \x{1E01}foo" =~ qr/(foo|\x{1E00}foo|bar)/i && + $1 eq "\x{1E01}foo", + "TRIEF + LATIN SMALL/CAPITAL LETTER A WITH RING BELOW"; + + # DESERET SMALL/CAPITAL LETTER LONG I + ok "foba \x{10428}foo" =~ qr/(foo|\x{10400}foo|bar)/i && + $1 eq "\x{10428}foo", + "TRIEF + DESERET SMALL/CAPITAL LETTER LONG I"; + + # LATIN SMALL/CAPITAL LETTER A WITH RING BELOW + 'X' + ok "foba \x{1E01}xfoo" =~ qr/(foo|\x{1E00}Xfoo|bar)/i && + $1 eq "\x{1E01}xfoo", + "TRIEF + LATIN SMALL/CAPITAL LETTER A WITH RING BELOW + 'X'"; + + use charnames ':full'; + + my $s = "\N{LATIN SMALL LETTER SHARP S}"; + ok "foba ba$s" =~ qr/(foo|Ba$s|bar)/i && $1 eq "ba$s", + "TRIEF + LATIN SMALL LETTER SHARP S =~ ss"; + ok "foba ba$s" =~ qr/(Ba$s|foo|bar)/i && $1 eq "ba$s", + "TRIEF + LATIN SMALL LETTER SHARP S =~ ss"; + ok "foba ba$s" =~ qr/(foo|bar|Ba$s)/i && $1 eq "ba$s", + "TRIEF + LATIN SMALL LETTER SHARP S =~ ss"; + + ok "foba ba$s" =~ qr/(foo|Bass|bar)/i && $1 eq "ba$s", + "TRIEF + LATIN SMALL LETTER SHARP S =~ ss"; + + ok "foba ba$s" =~ qr/(foo|BaSS|bar)/i && $1 eq "ba$s", + "TRIEF + LATIN SMALL LETTER SHARP S =~ SS"; + + ok "foba ba${s}pxySS$s$s" =~ qr/(b(?:a${s}t|a${s}f|a${s}p)[xy]+$s*)/i + && $1 eq "ba${s}pxySS$s$s", + "COMMON PREFIX TRIEF + LATIN SMALL LETTER SHARP S"; + } -ok("123\x{100}" =~ /^.*1.*23\x{100}$/, 'uft8 + multiple floating substr'); -# LATIN SMALL/CAPITAL LETTER A WITH MACRON -ok(" \x{101}" =~ qr/\x{100}/i, - "<20030808193656.5109.1@llama.ni-s.u-net.com>"); + SKIP: + { + print "# Set PERL_SKIP_PSYCHO_TEST to skip this test\n"; + my @normal = qw [the are some normal words]; -# LATIN SMALL/CAPITAL LETTER A WITH RING BELOW -ok(" \x{1E01}" =~ qr/\x{1E00}/i, - "<20030808193656.5109.1@llama.ni-s.u-net.com>"); + skip "Skipped Psycho", 2 * @normal if $ENV {PERL_SKIP_PSYCHO_TEST}; -# DESERET SMALL/CAPITAL LETTER LONG I -ok(" \x{10428}" =~ qr/\x{10400}/i, - "<20030808193656.5109.1@llama.ni-s.u-net.com>"); + local $" = "|"; -# LATIN SMALL/CAPITAL LETTER A WITH RING BELOW + 'X' -ok(" \x{1E01}x" =~ qr/\x{1E00}X/i, - "<20030808193656.5109.1@llama.ni-s.u-net.com>"); + my @psycho = (@normal, map chr $_, 255 .. 20000); + my $psycho1 = "@psycho"; + for (my $i = @psycho; -- $i;) { + my $j = int rand (1 + $i); + @psycho [$i, $j] = @psycho [$j, $i]; + } + my $psycho2 = "@psycho"; -{ - # [perl #23769] Unicode regex broken on simple example - # regrepeat() didn't handle UTF-8 EXACT case right. + foreach my $word (@normal) { + ok $word =~ /($psycho1)/ && $1 eq $word, 'Psycho'; + ok $word =~ /($psycho2)/ && $1 eq $word, 'Psycho'; + } + } - my $s = "\x{a0}\x{a0}\x{a0}\x{100}"; chop $s; - ok($s =~ /\x{a0}/, "[perl #23769]"); - ok($s =~ /\x{a0}+/, "[perl #23769]"); - ok($s =~ /\x{a0}\x{a0}/, "[perl #23769]"); + { + local $BugId = '36207'; + my $utf8 = "\xe9\x{100}"; chop $utf8; + my $latin1 = "\xe9"; + + ok $utf8 =~ /\xe9/i, "utf8/latin"; + ok $utf8 =~ /$latin1/i, "utf8/latin runtime"; + ok $utf8 =~ /(abc|\xe9)/i, "utf8/latin trie"; + ok $utf8 =~ /(abc|$latin1)/i, "utf8/latin trie runtime"; + + ok "\xe9" =~ /$utf8/i, "latin/utf8"; + ok "\xe9" =~ /(abc|$utf8)/i, "latin/utf8 trie"; + ok $latin1 =~ /$utf8/i, "latin/utf8 runtime"; + ok $latin1 =~ /(abc|$utf8)/i, "latin/utf8 trie runtime"; + } - ok("aaa\x{100}" =~ /(a+)/, "[perl #23769] easy invariant"); - ok($1 eq "aaa", "[perl #23769]"); - ok("\xa0\xa0\xa0\x{100}" =~ /(\xa0+)/, "[perl #23769] regrepeat invariant"); - ok($1 eq "\xa0\xa0\xa0", "[perl #23769]"); + { + local $BugId = '37038'; + my $s = "abcd"; + $s =~ /(..)(..)/g; + $s = $1; + $s = $2; + iseq $2, 'cd', + "Assigning to original string does not corrupt match vars"; + } - ok("ababab\x{100} " =~ /((?:ab)+)/, "[perl #23769] hard invariant"); - ok($1 eq "ababab", "[perl #23769]"); - ok("\xa0\xa1\xa0\xa1\xa0\xa1\x{100}" =~ /((?:\xa0\xa1)+)/, "[perl #23769] hard variant"); - ok($1 eq "\xa0\xa1\xa0\xa1\xa0\xa1", "[perl #23769]"); + { + { + package wooosh; + sub gloople {"!"} + } + my $aeek = bless {} => 'wooosh'; + eval_ok sub {$aeek -> gloople () =~ /(.)/g}, + "//g match against return value of sub"; - ok("aaa\x{100} " =~ /(a+?)/, "[perl #23769] easy invariant"); - ok($1 eq "a", "[perl #23769]"); + sub gloople {"!"} + eval_ok sub {gloople () =~ /(.)/g}, + "26410 didn't affect sub calls for some reason"; + } - ok("\xa0\xa0\xa0\x{100} " =~ /(\xa0+?)/, "[perl #23769] regrepeat variant"); - ok($1 eq "\xa0", "[perl #23769]"); - ok("ababab\x{100} " =~ /((?:ab)+?)/, "[perl #23769] hard invariant"); - ok($1 eq "ab", "[perl #23769]"); + { + local $TODO = "See changes 26925-26928, which reverted change 26410"; + { + package lv; + our $var = "abc"; + sub variable : lvalue {$var} + } + my $o = bless [] => 'lv'; + my $f = ""; + my $r = eval { + for (1 .. 2) { + $f .= $1 if $o -> variable =~ /(.)/g; + } + 1; + }; + if ($r) { + iseq $f, "ab", "pos() retained between calls"; + } + else { + local $TODO; + ok 0, "Code failed: $@"; + } - ok("\xa0\xa1\xa0\xa1\xa0\xa1\x{100}" =~ /((?:\xa0\xa1)+?)/, "[perl #23769] hard variant"); - ok($1 eq "\xa0\xa1", "[perl #23769]"); + our $var = "abc"; + sub variable : lvalue {$var} + my $g = ""; + my $s = eval { + for (1 .. 2) { + $g .= $1 if variable =~ /(.)/g; + } + 1; + }; + if ($s) { + iseq $g, "ab", "pos() retained between calls"; + } + else { + local $TODO; + ok 0, "Code failed: $@"; + } + } - ok("\xc4\xc4\xc4" !~ /(\x{100}+)/, "[perl #23769] don't match first byte of utf8 representation"); - ok("\xc4\xc4\xc4" !~ /(\x{100}+?)/, "[perl #23769] don't match first byte of utf8 representation"); -} -for (120 .. 130) { - my $head = 'x' x $_; - for my $tail ('\x{0061}', '\x{1234}') { - ok( - eval qq{ "$head$tail" =~ /$head$tail/ }, - '\x{...} misparsed in regexp near 127 char EXACT limit' - ); + SKIP: + { + local $BugId = '37836'; + skip "In EBCDIC" if $IS_EBCDIC; + no warnings 'utf8'; + $_ = pack 'U0C2', 0xa2, 0xf8; # Ill-formed UTF-8 + my $ret = 0; + eval_ok sub {!($ret = s/[\0]+//g)}, + "Ill-formed UTF-8 doesn't match NUL in class"; } -} -# perl #25269: panic: pp_match start/end pointers -ok("a-bc" eq eval { - my($x, $y) = "bca" =~ /^(?=.*(a)).*(bc)/; - "$x-$y"; -}, 'captures can move backwards in string'); - -# perl #27940: \cA not recognized in character classes -ok("a\cAb" =~ /\cA/, '\cA in pattern'); -ok("a\cAb" =~ /[\cA]/, '\cA in character class'); -ok("a\cAb" =~ /[\cA-\cB]/, '\cA in character class range'); -ok("abc" =~ /[^\cA-\cB]/, '\cA in negated character class range'); -ok("a\cBb" =~ /[\cA-\cC]/, '\cB in character class range'); -ok("a\cCbc" =~ /[^\cA-\cB]/, '\cC in negated character class range'); -ok("a\cAb" =~ /(??{"\cA"})/, '\cA in ??{} pattern'); -ok("ab" !~ /a\cIb/x, '\cI in pattern'); - -# perl #28532: optional zero-width match at end of string is ignored -ok(("abc" =~ /^abc(\z)?/) && defined($1), - 'optional zero-width match at end of string'); -ok(("abc" =~ /^abc(\z)??/) && !defined($1), - 'optional zero-width match at end of string'); - - - -{ # TRIE related - my @got=(); - "words"=~/(word|word|word)(?{push @got,$1})s$/; - ok(@got==1,"TRIE optimation is working") or warn "# @got"; - @got=(); - "words"=~/(word|word|word)(?{push @got,$1})s$/i; - ok(@got==1,"TRIEF optimisation is working") or warn "# @got"; - - my @nums=map {int rand 1000} 1..100; - my $re="(".(join "|",@nums).")"; - $re=qr/\b$re\b/; - - foreach (@nums) { - ok($_=~/$re/,"Trie nums"); - } - $_=join " ", @nums; - @got=(); - push @got,$1 while /$re/g; - - my %count; - $count{$_}++ for @got; - my $ok=1; - for (@nums) { - $ok=0 if --$count{$_}<0; - } - ok($ok,"Trie min count matches"); -} + { + # chr(65535) should be allowed in regexes + local $BugId = '38293'; + no warnings 'utf8'; # To allow non-characters + my ($c, $r, $s); + + $c = chr 0xffff; + $c =~ s/$c//g; + ok $c eq "", "U+FFFF, parsed as atom"; + + $c = chr 0xffff; + $r = "\\$c"; + $c =~ s/$r//g; + ok $c eq "", "U+FFFF backslashed, parsed as atom"; + + $c = chr 0xffff; + $c =~ s/[$c]//g; + ok $c eq "", "U+FFFF, parsed in class"; + + $c = chr 0xffff; + $r = "[\\$c]"; + $c =~ s/$r//g; + ok $c eq "", "U+FFFF backslashed, parsed in class"; + + $s = "A\x{ffff}B"; + $s =~ s/\x{ffff}//i; + ok $s eq "AB", "U+FFFF, EXACTF"; + + $s = "\x{ffff}A"; + $s =~ s/\bA//; + ok $s eq "\x{ffff}", "U+FFFF, BOUND"; + + $s = "\x{ffff}!"; + $s =~ s/\B!//; + ok $s eq "\x{ffff}", "U+FFFF, NBOUND"; + } -# TRIE related -# LATIN SMALL/CAPITAL LETTER A WITH MACRON -ok(("foba \x{101}foo" =~ qr/(foo|\x{100}foo|bar)/i) && $1 eq "\x{101}foo", - "TRIEF + LATIN SMALL/CAPITAL LETTER A WITH MACRON"); -# LATIN SMALL/CAPITAL LETTER A WITH RING BELOW -ok(("foba \x{1E01}foo" =~ qr/(foo|\x{1E00}foo|bar)/i) && $1 eq "\x{1E01}foo", - "TRIEF + LATIN SMALL/CAPITAL LETTER A WITH RING BELOW"); + { + local $BugId = '39583'; + + # The printing characters + my @chars = ("A" .. "Z"); + my $delim = ","; + my $size = 32771 - 4; + my $str = ''; + + # Create some random junk. Inefficient, but it works. + for (my $i = 0; $i < $size; $ i++) { + $str .= $chars [rand @chars]; + } -# DESERET SMALL/CAPITAL LETTER LONG I -ok(("foba \x{10428}foo" =~ qr/(foo|\x{10400}foo|bar)/i) && $1 eq "\x{10428}foo", - "TRIEF + DESERET SMALL/CAPITAL LETTER LONG I"); + $str .= ($delim x 4); + my $res; + my $matched; + ok $str =~ s/^(.*?)${delim}{4}//s, "Pattern matches"; + iseq $str, "", "Empty string"; + ok defined $1 && length ($1) == $size, '$1 is correct size'; + } -# LATIN SMALL/CAPITAL LETTER A WITH RING BELOW + 'X' -ok(("foba \x{1E01}xfoo" =~ qr/(foo|\x{1E00}Xfoo|bar)/i) && $1 eq "\x{1E01}xfoo", - "TRIEF + LATIN SMALL/CAPITAL LETTER A WITH RING BELOW + 'X'"); -{# TRIE related + { + local $BugId = '27940'; + ok "\0-A" =~ /\c@-A/, '@- should not be interpolated in a pattern'; + ok "\0\0A" =~ /\c@+A/, '@+ should not be interpolated in a pattern'; + ok "X\@-A" =~ /X@-A/, '@- should not be interpolated in a pattern'; + ok "X\@\@A" =~ /X@+A/, '@+ should not be interpolated in a pattern'; + + ok "X\0A" =~ /X\c@?A/, '\c@?'; + ok "X\0A" =~ /X\c@*A/, '\c@*'; + ok "X\0A" =~ /X\c@(A)/, '\c@('; + ok "X\0A" =~ /X(\c@)A/, '\c@)'; + ok "X\0A" =~ /X\c@|ZA/, '\c@|'; + + ok "X\@A" =~ /X@?A/, '@?'; + ok "X\@A" =~ /X@*A/, '@*'; + ok "X\@A" =~ /X@(A)/, '@('; + ok "X\@A" =~ /X(@)A/, '@)'; + ok "X\@A" =~ /X@|ZA/, '@|'; + + local $" = ','; # non-whitespace and non-RE-specific + ok 'abc' =~ /(.)(.)(.)/, 'The last successful match is bogus'; + ok "A@+B" =~ /A@{+}B/, 'Interpolation of @+ in /@{+}/'; + ok "A@-B" =~ /A@{-}B/, 'Interpolation of @- in /@{-}/'; + ok "A@+B" =~ /A@{+}B/x, 'Interpolation of @+ in /@{+}/x'; + ok "A@-B" =~ /A@{-}B/x, 'Interpolation of @- in /@{-}/x'; + } -use charnames ':full'; -$s="\N{LATIN SMALL LETTER SHARP S}"; -ok(("foba ba$s" =~ qr/(foo|Ba$s|bar)/i) - && $1 eq "ba$s", - "TRIEF + LATIN SMALL LETTER SHARP S =~ ss"); -ok(("foba ba$s" =~ qr/(Ba$s|foo|bar)/i) - && $1 eq "ba$s", - "TRIEF + LATIN SMALL LETTER SHARP S =~ ss"); -ok(("foba ba$s" =~ qr/(foo|bar|Ba$s)/i) - && $1 eq "ba$s", - "TRIEF + LATIN SMALL LETTER SHARP S =~ ss"); + { + use lib 'lib'; + use Cname; + + ok 'fooB' =~ /\N{foo}[\N{B}\N{b}]/, "Passthrough charname"; + my $test = 1233; + # + # Why doesn't must_warn work here? + # + my $w; + local $SIG {__WARN__} = sub {$w .= "@_"}; + eval 'q(xxWxx) =~ /[\N{WARN}]/'; + ok $w && $w =~ /^Ignoring excess chars from/, + "Ignoring excess chars warning"; + + undef $w; + eval q [ok "\0" !~ /[\N{EMPTY-STR}XY]/, + "Zerolength charname in charclass doesn't match \\0"]; + ok $w && $w =~ /^Ignoring zero length/, + 'Ignoring zero length \N{%} in character class warning'; + + ok 'AB' =~ /(\N{EVIL})/ && $1 eq 'A', 'Charname caching $1'; + ok 'ABC' =~ /(\N{EVIL})/, 'Charname caching $1'; + ok 'xy' =~ /x\N{EMPTY-STR}y/, + 'Empty string charname produces NOTHING node'; + ok '' =~ /\N{EMPTY-STR}/, + 'Empty string charname produces NOTHING node'; + + } -ok(("foba ba$s" =~ qr/(foo|Bass|bar)/i) - && $1 eq "ba$s", - "TRIEF + LATIN SMALL LETTER SHARP S =~ ss"); -ok(("foba ba$s" =~ qr/(foo|BaSS|bar)/i) - && $1 eq "ba$s", - "TRIEF + LATIN SMALL LETTER SHARP S =~ SS"); + { + use charnames ':full'; + + ok 'aabc' !~ /a\N{PLUS SIGN}b/, '/a\N{PLUS SIGN}b/ against aabc'; + ok 'a+bc' =~ /a\N{PLUS SIGN}b/, '/a\N{PLUS SIGN}b/ against a+bc'; + + ok ' A B' =~ /\N{SPACE}\N{U+0041}\N{SPACE}\N{U+0042}/, + 'Intermixed named and unicode escapes'; + ok "\N{SPACE}\N{U+0041}\N{SPACE}\N{U+0042}" =~ + /\N{SPACE}\N{U+0041}\N{SPACE}\N{U+0042}/, + 'Intermixed named and unicode escapes'; + ok "\N{SPACE}\N{U+0041}\N{SPACE}\N{U+0042}" =~ + /[\N{SPACE}\N{U+0041}][\N{SPACE}\N{U+0042}]/, + 'Intermixed named and unicode escapes'; + } -ok(("foba ba${s}pxySS$s$s" =~ qr/(b(?:a${s}t|a${s}f|a${s}p)[xy]+$s*)/i) - && $1 eq "ba${s}pxySS$s$s", - "COMMON PREFIX TRIEF + LATIN SMALL LETTER SHARP S"); - -} + { + our $brackets; + $brackets = qr{ + { (?> [^{}]+ | (??{ $brackets }) )* } + }x; + + ok "{b{c}d" !~ m/^((??{ $brackets }))/, "Bracket mismatch"; + + SKIP: { + our @stack = (); + my @expect = qw( + stuff1 + stuff2 + <stuff1>and<stuff2> + right + <right> + <<right>> + <<<right>>> + <<stuff1>and<stuff2>><<<<right>>>> + ); + + local $_ = '<<<stuff1>and<stuff2>><<<<right>>>>>'; + ok /^(<((?:(?>[^<>]+)|(?1))*)>(?{push @stack, $2 }))$/, + "Recursion matches"; + iseq @stack, @expect, "Right amount of matches" + or skip "Won't test individual results as count isn't equal", + 0 + @expect; + my $idx = 0; + foreach my $expect (@expect) { + iseq $stack [$idx], $expect, + "Expecting '$expect' at stack pos #$idx"; + $idx ++; + } + } + } -print "# set PERL_SKIP_PSYCHO_TEST to skip this test\n"; -if (!$ENV{PERL_SKIP_PSYCHO_TEST}){ - my @normal=qw(these are some normal words); - my $psycho=join "|",@normal,map chr $_,255..20000; - ok(('these'=~/($psycho)/) && $1 eq 'these','Pyscho'); -} else { - ok(1,'Skipped Psycho'); -} + { + my $s = '123453456'; + $s =~ s/(?<digits>\d+)\k<digits>/$+{digits}/; + ok $s eq '123456', 'Named capture (angle brackets) s///'; + $s = '123453456'; + $s =~ s/(?'digits'\d+)\k'digits'/$+{digits}/; + ok $s eq '123456', 'Named capture (single quotes) s///'; + } -# [perl #36207] mixed utf8 / latin-1 and case folding -{ - my $utf8 = "\xe9\x{100}"; chop $utf8; - my $latin1 = "\xe9"; + { + my @ary = ( + pack('U', 0x00F1), # n-tilde + '_'.pack('U', 0x00F1), # _ + n-tilde + 'c'.pack('U', 0x0327), # c + cedilla + pack('U*', 0x00F1, 0x0327), # n-tilde + cedilla + 'a'.pack('U', 0x00B2), # a + superscript two + pack('U', 0x0391), # ALPHA + pack('U', 0x0391).'2', # ALPHA + 2 + pack('U', 0x0391).'_', # ALPHA + _ + ); + + for my $uni (@ary) { + my ($r1, $c1, $r2, $c2) = eval qq { + use utf8; + scalar ("..foo foo.." =~ /(?'${uni}'foo) \\k'${uni}'/), + \$+{${uni}}, + scalar ("..bar bar.." =~ /(?<${uni}>bar) \\k<${uni}>/), + \$+{${uni}}; + }; + ok $r1, "Named capture UTF (?'')"; + ok defined $c1 && $c1 eq 'foo', "Named capture UTF \%+"; + ok $r2, "Named capture UTF (?<>)"; + ok defined $c2 && $c2 eq 'bar', "Named capture UTF \%+"; + } + } - ok($utf8 =~ /\xe9/i, "utf8/latin"); - ok($utf8 =~ /$latin1/i, "utf8/latin runtime"); - ok($utf8 =~ /(abc|\xe9)/i, "utf8/latin trie"); - ok($utf8 =~ /(abc|$latin1)/i, "utf8/latin trie runtime"); - ok("\xe9" =~ /$utf8/i, "# latin/utf8"); - ok("\xe9" =~ /(abc|$utf8)/i, "# latin/utf8 trie"); - ok($latin1 =~ /$utf8/i, "# latin/utf8 runtime"); - ok($latin1 =~ /(abc|$utf8)/i, "# latin/utf8 trie runtime"); -} + { + my $s = 'foo bar baz'; + my (@k, @v, @fetch, $res); + my $count = 0; + my @names = qw ($+{A} $+{B} $+{C}); + if ($s =~ /(?<A>foo)\s+(?<B>bar)?\s+(?<C>baz)/) { + while (my ($k, $v) = each (%+)) { + $count++; + } + @k = sort keys (%+); + @v = sort values (%+); + $res = 1; + push @fetch, + ["$+{A}", "$1"], + ["$+{B}", "$2"], + ["$+{C}", "$3"], + ; + } + foreach (0 .. 2) { + if ($fetch [$_]) { + iseq $fetch [$_] [0], $fetch [$_] [1], $names [$_]; + } else { + ok 0, $names[$_]; + } + } + iseq $res, 1, "'$s' =~ /(?<A>foo)\\s+(?<B>bar)?\\s+(?<C>baz)/"; + iseq $count, 3, "Got 3 keys in %+ via each"; + iseq 0 + @k, 3, 'Got 3 keys in %+ via keys'; + iseq "@k", "A B C", "Got expected keys"; + iseq "@v", "bar baz foo", "Got expected values"; + eval ' + no warnings "uninitialized"; + print for $+ {this_key_doesnt_exist}; + '; + ok !$@, 'lvalue $+ {...} should not throw an exception'; + } -# [perl #37038] Global regular matches generate invalid pointers -{ - my $s = "abcd"; - $s =~ /(..)(..)/g; - $s = $1; - $s = $2; - ok($s eq 'cd', - "# assigning to original string should not corrupt match vars"); -} + { + # + # Almost the same as the block above, except that the capture is nested. + # + local $BugId = '50496'; + my $s = 'foo bar baz'; + my (@k, @v, @fetch, $res); + my $count = 0; + my @names = qw ($+{A} $+{B} $+{C} $+{D}); + if ($s =~ /(?<D>(?<A>foo)\s+(?<B>bar)?\s+(?<C>baz))/) { + while (my ($k,$v) = each(%+)) { + $count++; + } + @k = sort keys (%+); + @v = sort values (%+); + $res = 1; + push @fetch, + ["$+{A}", "$2"], + ["$+{B}", "$3"], + ["$+{C}", "$4"], + ["$+{D}", "$1"], + ; + } + foreach (0 .. 3) { + if ($fetch [$_]) { + iseq $fetch [$_] [0], $fetch [$_] [1], $names [$_]; + } else { + ok 0, $names [$_]; + } + } + iseq $res, 1, "'$s' =~ /(?<D>(?<A>foo)\\s+(?<B>bar)?\\s+(?<C>baz))/"; + iseq $count, 4, "Got 4 keys in %+ via each"; + iseq @k, 4, 'Got 4 keys in %+ via keys'; + iseq "@k", "A B C D", "Got expected keys"; + iseq "@v", "bar baz foo foo bar baz", "Got expected values"; + eval ' + no warnings "uninitialized"; + print for $+ {this_key_doesnt_exist}; + '; + ok !$@,'lvalue $+ {...} should not throw an exception'; + } + -{ - package wooosh; - sub gloople { - "!"; + { + my $s = 'foo bar baz'; + my @res; + if ('1234' =~ /(?<A>1)(?<B>2)(?<A>3)(?<B>4)/) { + foreach my $name (sort keys(%-)) { + my $ary = $- {$name}; + foreach my $idx (0 .. $#$ary) { + push @res, "$name:$idx:$ary->[$idx]"; + } + } + } + my @expect = qw (A:0:1 A:1:3 B:0:2 B:1:4); + iseq "@res", "@expect", "Check %-"; + eval' + no warnings "uninitialized"; + print for $- {this_key_doesnt_exist}; + '; + ok !$@,'lvalue $- {...} should not throw an exception'; } - package main; - - my $aeek = bless {}, 'wooosh'; - eval {$aeek->gloople() =~ /(.)/g;}; - ok($@ eq "", "//g match against return value of sub") or print "# $@\n"; -} -{ - sub gloople { - "!"; + + SKIP: + { + # stress test CURLYX/WHILEM. + # + # This test includes varying levels of nesting, and according to + # profiling done against build 28905, exercises every code line in the + # CURLYX and WHILEM blocks, except those related to LONGJMP, the + # super-linear cache and warnings. It executes about 0.5M regexes + + skip "No psycho tests" if $ENV {PERL_SKIP_PSYCHO_TEST}; + print "# Set PERL_SKIP_PSYCHO_TEST to skip this test\n"; + my $r = qr/^ + (?: + ( (?:a|z+)+ ) + (?: + ( (?:b|z+){3,}? ) + ( + (?: + (?: + (?:c|z+){1,1}?z + )? + (?:c|z+){1,1} + )* + ) + (?:z*){2,} + ( (?:z+|d)+ ) + (?: + ( (?:e|z+)+ ) + )* + ( (?:f|z+)+ ) + )* + ( (?:z+|g)+ ) + (?: + ( (?:h|z+)+ ) + )* + ( (?:i|z+)+ ) + )+ + ( (?:j|z+)+ ) + (?: + ( (?:k|z+)+ ) + )* + ( (?:l|z+)+ ) + $/x; + + my $ok = 1; + my $msg = "CURLYX stress test"; + OUTER: + for my $a ("x","a","aa") { + for my $b ("x","bbb","bbbb") { + my $bs = $a.$b; + for my $c ("x","c","cc") { + my $cs = $bs.$c; + for my $d ("x","d","dd") { + my $ds = $cs.$d; + for my $e ("x","e","ee") { + my $es = $ds.$e; + for my $f ("x","f","ff") { + my $fs = $es.$f; + for my $g ("x","g","gg") { + my $gs = $fs.$g; + for my $h ("x","h","hh") { + my $hs = $gs.$h; + for my $i ("x","i","ii") { + my $is = $hs.$i; + for my $j ("x","j","jj") { + my $js = $is.$j; + for my $k ("x","k","kk") { + my $ks = $js.$k; + for my $l ("x","l","ll") { + my $ls = $ks.$l; + if ($ls =~ $r) { + if ($ls =~ /x/) { + $msg .= ": unexpected match for [$ls]"; + $ok = 0; + last OUTER; + } + my $cap = "$1$2$3$4$5$6$7$8$9$10$11$12"; + unless ($ls eq $cap) { + $msg .= ": capture: [$ls], got [$cap]"; + $ok = 0; + last OUTER; + } + } + else { + unless ($ls =~ /x/) { + $msg = ": failed for [$ls]"; + $ok = 0; + last OUTER; + } + } + } + } + } + } + } + } + } + } + } + } + } + } + ok($ok, $msg); } - eval {gloople() =~ /(.)/g;}; - ok($@ eq "", "# 26410 didn't affect sub calls for some reason") - or print "# $@\n"; -} -{ - package lv; - $var = "abc"; - sub variable : lvalue { $var } - package main; - my $o = bless [], "lv"; - my $f = ""; - eval { for (1..2) { $f .= $1 if $o->variable =~ /(.)/g } }; - ok($f eq "ab", "pos retained between calls # TODO") or print "# $@\n"; -} + { + # \, breaks {3,4} + ok "xaaay" !~ /xa{3\,4}y/, '\, in a pattern'; + ok "xa{3,4}y" =~ /xa{3\,4}y/, '\, in a pattern'; + + # \c\ followed by _ + ok "x\c_y" !~ /x\c\_y/, '\_ in a pattern'; + ok "x\c\_y" =~ /x\c\_y/, '\_ in a pattern'; + + # \c\ followed by other characters + for my $c ("z", "\0", "!", chr(254), chr(256)) { + my $targ = "a\034$c"; + my $reg = "a\\c\\$c"; + ok eval ("qq/$targ/ =~ /$reg/"), "\\c\\ in pattern"; + } + } -{ - $var = "abc"; - sub variable : lvalue { $var } - my $f = ""; - eval { for (1..2) { $f .= $1 if variable() =~ /(.)/g } }; - ok($f eq "ab", "pos retained between calls # TODO") or print "# $@\n"; -} + { + local $BugId = '36046'; + my $str = 'abc'; + my $count = 0; + my $mval = 0; + my $pval = 0; + while ($str =~ /b/g) {$mval = $#-; $pval = $#+; $count ++} + iseq $mval, 0, '@- should be empty'; + iseq $pval, 0, '@+ should be empty'; + iseq $count, 1, 'Should have matched once only'; + } -# [perl #37836] Simple Regex causes SEGV when run on specific data -if ($ordA == 193) { - print "ok $test # Skip: in EBCDIC\n"; $test++; -} else { - no warnings 'utf8'; - $_ = pack('U0C2', 0xa2, 0xf8); # ill-formed UTF-8 - my $ret = 0; - eval { $ret = s/[\0]+//g }; - ok($ret == 0, "ill-formed UTF-8 doesn't match NUL in class"); -} -{ # [perl #38293] chr(65535) should be allowed in regexes - no warnings 'utf8'; # to allow non-characters - my($c, $r, $s); + { # Test the (*PRUNE) pattern + our $count = 0; + 'aaab' =~ /a+b?(?{$count++})(*FAIL)/; + iseq $count, 9, "Expect 9 for no (*PRUNE)"; + $count = 0; + 'aaab' =~ /a+b?(*PRUNE)(?{$count++})(*FAIL)/; + iseq $count, 3, "Expect 3 with (*PRUNE)"; + local $_ = 'aaab'; + $count = 0; + 1 while /.(*PRUNE)(?{$count++})(*FAIL)/g; + iseq $count, 4, "/.(*PRUNE)/"; + $count = 0; + 'aaab' =~ /a+b?(??{'(*PRUNE)'})(?{$count++})(*FAIL)/; + iseq $count, 3, "Expect 3 with (*PRUNE)"; + local $_ = 'aaab'; + $count = 0; + 1 while /.(??{'(*PRUNE)'})(?{$count++})(*FAIL)/g; + iseq $count, 4, "/.(*PRUNE)/"; + } - $c = chr 0xffff; - $c =~ s/$c//g; - ok($c eq "", "U+FFFF, parsed as atom"); - $c = chr 0xffff; - $r = "\\$c"; - $c =~ s/$r//g; - ok($c eq "", "U+FFFF backslashed, parsed as atom"); + { # Test the (*SKIP) pattern + our $count = 0; + 'aaab' =~ /a+b?(*SKIP)(?{$count++})(*FAIL)/; + iseq $count, 1, "Expect 1 with (*SKIP)"; + local $_ = 'aaab'; + $count = 0; + 1 while /.(*SKIP)(?{$count++})(*FAIL)/g; + iseq $count, 4, "/.(*SKIP)/"; + $_ = 'aaabaaab'; + $count = 0; + our @res = (); + 1 while /(a+b?)(*SKIP)(?{$count++; push @res,$1})(*FAIL)/g; + iseq $count, 2, "Expect 2 with (*SKIP)"; + iseq "@res", "aaab aaab", "Adjacent (*SKIP) works as expected"; + } - $c = chr 0xffff; - $c =~ s/[$c]//g; - ok($c eq "", "U+FFFF, parsed in class"); - $c = chr 0xffff; - $r = "[\\$c]"; - $c =~ s/$r//g; - ok($c eq "", "U+FFFF backslashed, parsed in class"); + { # Test the (*SKIP) pattern + our $count = 0; + 'aaab' =~ /a+b?(*MARK:foo)(*SKIP)(?{$count++})(*FAIL)/; + iseq $count, 1, "Expect 1 with (*SKIP)"; + local $_ = 'aaab'; + $count = 0; + 1 while /.(*MARK:foo)(*SKIP)(?{$count++})(*FAIL)/g; + iseq $count, 4, "/.(*SKIP)/"; + $_ = 'aaabaaab'; + $count = 0; + our @res = (); + 1 while /(a+b?)(*MARK:foo)(*SKIP)(?{$count++; push @res,$1})(*FAIL)/g; + iseq $count, 2, "Expect 2 with (*SKIP)"; + iseq "@res", "aaab aaab", "Adjacent (*SKIP) works as expected"; + } - $s = "A\x{ffff}B"; - $s =~ s/\x{ffff}//i; - ok($s eq "AB", "U+FFFF, EXACTF"); - $s = "\x{ffff}A"; - $s =~ s/\bA//; - ok($s eq "\x{ffff}", "U+FFFF, BOUND"); + { # Test the (*SKIP) pattern + our $count = 0; + 'aaab' =~ /a*(*MARK:a)b?(*MARK:b)(*SKIP:a)(?{$count++})(*FAIL)/; + iseq $count, 3, "Expect 3 with *MARK:a)b?(*MARK:b)(*SKIP:a)"; + local $_ = 'aaabaaab'; + $count = 0; + our @res = (); + 1 while + /(a*(*MARK:a)b?)(*MARK:x)(*SKIP:a)(?{$count++; push @res,$1})(*FAIL)/g; + iseq $count, 5, "Expect 5 with (*MARK:a)b?)(*MARK:x)(*SKIP:a)"; + iseq "@res", "aaab b aaab b ", + "Adjacent (*MARK:a)b?)(*MARK:x)(*SKIP:a) works as expected"; + } - $s = "\x{ffff}!"; - $s =~ s/\B!//; - ok($s eq "\x{ffff}", "U+FFFF, NBOUND"); -} # non-characters end -{ - # https://rt.perl.org/rt3/Ticket/Display.html?id=39583 - - # The printing characters - my @chars = ("A".."Z"); - my $delim = ","; - my $size = 32771 - 4; - my $str = ''; - - # create some random junk. Inefficient, but it works. - for ($i = 0 ; $i < $size ; $i++) { - $str .= $chars[int(rand(@chars))]; - } - - $str .= ($delim x 4); - my $res; - my $matched; - if ($str =~ s/^(.*?)${delim}{4}//s) { - $res = $1; - $matched=1; - } - ok($matched,'pattern matches'); - ok(length($str)==0,"Empty string"); - ok(defined($res) && length($res)==$size,"\$1 is correct size"); -} + { # Test the (*COMMIT) pattern + our $count = 0; + 'aaabaaab' =~ /a+b?(*COMMIT)(?{$count++})(*FAIL)/; + iseq $count, 1, "Expect 1 with (*COMMIT)"; + local $_ = 'aaab'; + $count = 0; + 1 while /.(*COMMIT)(?{$count++})(*FAIL)/g; + iseq $count, 1, "/.(*COMMIT)/"; + $_ = 'aaabaaab'; + $count = 0; + our @res = (); + 1 while /(a+b?)(*COMMIT)(?{$count++; push @res,$1})(*FAIL)/g; + iseq $count, 1, "Expect 1 with (*COMMIT)"; + iseq "@res", "aaab", "Adjacent (*COMMIT) works as expected"; + } -{ # related to [perl #27940] - ok("\0-A" =~ /\c@-A/, '@- should not be interpolated in a pattern'); - ok("\0\0A" =~ /\c@+A/, '@+ should not be interpolated in a pattern'); - ok("X\@-A" =~ /X@-A/, '@- should not be interpolated in a pattern'); - ok("X\@\@A" =~ /X@+A/, '@+ should not be interpolated in a pattern'); - - ok("X\0A" =~ /X\c@?A/, '\c@?'); - ok("X\0A" =~ /X\c@*A/, '\c@*'); - ok("X\0A" =~ /X\c@(A)/, '\c@('); - ok("X\0A" =~ /X(\c@)A/, '\c@)'); - ok("X\0A" =~ /X\c@|ZA/, '\c@|'); - - ok("X\@A" =~ /X@?A/, '@?'); - ok("X\@A" =~ /X@*A/, '@*'); - ok("X\@A" =~ /X@(A)/, '@('); - ok("X\@A" =~ /X(@)A/, '@)'); - ok("X\@A" =~ /X@|ZA/, '@|'); - - local $" = ','; # non-whitespace and non-RE-specific - ok('abc' =~ /(.)(.)(.)/, 'the last successful match is bogus'); - ok("A@+B" =~ /A@{+}B/, 'interpolation of @+ in /@{+}/'); - ok("A@-B" =~ /A@{-}B/, 'interpolation of @- in /@{-}/'); - ok("A@+B" =~ /A@{+}B/x, 'interpolation of @+ in /@{+}/x'); - ok("A@-B" =~ /A@{-}B/x, 'interpolation of @- in /@{-}/x'); -} -{ - use lib 'lib'; - use Cname; - - ok('fooB'=~/\N{foo}[\N{B}\N{b}]/,"Passthrough charname"); - $test=1233; my $handle=make_must_warn('Ignoring excess chars from'); - $handle->('q(xxWxx) =~ /[\N{WARN}]/'); - { - my $code; - my $w=""; - local $SIG{__WARN__} = sub { $w.=shift }; - eval($code=<<'EOFTEST') or die "$@\n$code\n"; - { - use warnings; - - #1234 - ok("\0" !~ /[\N{EMPTY-STR}XY]/, - "Zerolength charname in charclass doesnt match \0"); - 1; + { + # Test named commits and the $REGERROR var + our $REGERROR; + for my $name ('', ':foo') { + for my $pat ("(*PRUNE$name)", + ($name ? "(*MARK$name)" : "") . "(*SKIP$name)", + "(*COMMIT$name)") { + for my $suffix ('(*FAIL)', '') { + 'aaaab' =~ /a+b$pat$suffix/; + iseq $REGERROR, + ($suffix ? ($name ? 'foo' : "1") : ""), + "Test $pat and \$REGERROR $suffix"; + } + } } -EOFTEST - ok($w=~/Ignoring zero length/, - "Got expected zero length warning"); - warn $code; - } - $handle= make_must_warn('Ignoring zero length'); - $handle->('qq(\\0) =~ /[\N{EMPTY-STR}XY]/'); - ok('AB'=~/(\N{EVIL})/ && $1 eq 'A',"Charname caching $1"); - ok('ABC'=~/(\N{EVIL})/,"Charname caching $1"); - ok('xy'=~/x\N{EMPTY-STR}y/, 'Empty string charname produces NOTHING node'); - ok(''=~/\N{EMPTY-STR}/, 'Empty string charname produces NOTHING node 2'); - -} -{ - print "# MORE LATIN SMALL LETTER SHARP S\n"; - - use charnames ':full'; - - #see also test #835 - ok("ss" =~ /[\N{LATIN SMALL LETTER SHARP S}x]/i, - "unoptimized named sequence in class 1"); - ok("SS" =~ /[\N{LATIN SMALL LETTER SHARP S}x]/i, - "unoptimized named sequence in class 2"); - ok("\N{LATIN SMALL LETTER SHARP S}" =~ /[\N{LATIN SMALL LETTER SHARP S}x]/, - "unoptimized named sequence in class 3"); - ok("\N{LATIN SMALL LETTER SHARP S}" =~ /[\N{LATIN SMALL LETTER SHARP S}x]/i, - "unoptimized named sequence in class 4"); - - ok('aabc' !~ /a\N{PLUS SIGN}b/,'/a\N{PLUS SIGN}b/ against aabc'); - ok('a+bc' =~ /a\N{PLUS SIGN}b/,'/a\N{PLUS SIGN}b/ against a+bc'); - ok('a+bc' =~ /a\N{PLUS SIGN}b/,'/a\N{PLUS SIGN}b/ against a+bc'); - - ok(' A B'=~/\N{SPACE}\N{U+0041}\N{SPACE}\N{U+0042}/, - 'Intermixed named and unicode escapes 1'); - ok("\N{SPACE}\N{U+0041}\N{SPACE}\N{U+0042}"=~ - /\N{SPACE}\N{U+0041}\N{SPACE}\N{U+0042}/, - 'Intermixed named and unicode escapes 2'); - ok("\N{SPACE}\N{U+0041}\N{SPACE}\N{U+0042} 3"=~ - /[\N{SPACE}\N{U+0041}][\N{SPACE}\N{U+0042}]/, - 'Intermixed named and unicode escapes'); -} -$brackets = qr{ - { (?> [^{}]+ | (??{ $brackets }) )* } - }x; -ok("{b{c}d" !~ m/^((??{ $brackets }))/, "bracket mismatch"); - -SKIP:{ - our @stack=(); - my @expect=qw( - stuff1 - stuff2 - <stuff1>and<stuff2> - right - <right> - <<right>> - <<<right>>> - <<stuff1>and<stuff2>><<<<right>>>> - ); - - local $_='<<<stuff1>and<stuff2>><<<<right>>>>>'; - ok(/^(<((?:(?>[^<>]+)|(?1))*)>(?{push @stack, $2 }))$/, - "Recursion should match"); - ok(@stack==@expect) - or skip("Won't test individual results as count isn't equal", - 0+@expect); - foreach my $idx (@expect) { - ok($expect[$idx] eq $stack[$idx], - "Expecting '$expect' at stack pos #$idx"); + + + { + # Test named commits and the $REGERROR var + package Fnorble; + our $REGERROR; + for my $name ('', ':foo') { + for my $pat ("(*PRUNE$name)", + ($name ? "(*MARK$name)" : "") . "(*SKIP$name)", + "(*COMMIT$name)") { + for my $suffix ('(*FAIL)','') { + 'aaaab' =~ /a+b$pat$suffix/; + ::iseq $REGERROR, + ($suffix ? ($name ? 'foo' : "1") : ""), + "Test $pat and \$REGERROR $suffix"; + } + } + } + } + + + { + # Test named commits and the $REGERROR var + local $Message = '$REGERROR'; + our $REGERROR; + for my $word (qw (bar baz bop)) { + $REGERROR = ""; + "aaaaa$word" =~ + /a+(?:bar(*COMMIT:bar)|baz(*COMMIT:baz)|bop(*COMMIT:bop))(*FAIL)/; + iseq $REGERROR, $word; + } } - -} -{ - my $s='123453456'; - $s=~s/(?<digits>\d+)\k<digits>/$+{digits}/; - ok($s eq '123456','Named capture (angle brackets) s///'); - $s='123453456'; - $s=~s/(?'digits'\d+)\k'digits'/$+{digits}/; - ok($s eq '123456','Named capture (single quotes) s///'); -} -{ - my @ary = ( - pack('U', 0x00F1), # n-tilde - '_'.pack('U', 0x00F1), # _ + n-tilde - 'c'.pack('U', 0x0327), # c + cedilla - pack('U*', 0x00F1, 0x0327), # n-tilde + cedilla - 'a'.pack('U', 0x00B2), # a + superscript two - pack('U', 0x0391), # ALPHA - pack('U', 0x0391).'2', # ALPHA + 2 - pack('U', 0x0391).'_', # ALPHA + _ - ); - for my $uni (@ary) { - my ($r1, $c1, $r2, $c2) = eval qq{ - use utf8; - scalar("..foo foo.." =~ /(?'${uni}'foo) \\k'${uni}'/), - \$+{${uni}}, - scalar("..bar bar.." =~ /(?<${uni}>bar) \\k<${uni}>/), - \$+{${uni}}; - }; - ok($r1, "Named capture UTF (?'')"); - ok(defined $c1 && $c1 eq 'foo', "Named capture UTF \%+"); - ok($r2, "Named capture UTF (?<>)"); - ok(defined $c2 && $c2 eq 'bar', "Named capture UTF \%+"); + + { + local $BugId = '40684'; + local $Message = '/m in precompiled regexp'; + my $s = "abc\ndef"; + my $rex = qr'^abc$'m; + ok $s =~ m/$rex/; + ok $s =~ m/^abc$/m; } -} -sub iseq($$;$) { - my ( $got, $expect, $name)=@_; - - $_=defined($_) ? "'$_'" : "undef" - for $got, $expect; - - my $ok= $got eq $expect; - - printf "%sok %d - %s\n", ($ok ? "" : "not "), $test, - ($name||$Message)."\tLine ".((caller)[2]); - printf "# Failed test at line %d\n". - "# expected: %s\n". - "# result: %s\n", - (caller)[2], $expect, $got - unless $ok; + { + #Mindnumbingly simple test of (*THEN) + for ("ABC","BAX") { + ok /A (*THEN) X | B (*THEN) C/x, "Simple (*THEN) test"; + } + } - $test++; - return $ok; -} -{ - my $s='foo bar baz'; - my (@k,@v,@fetch,$res); - my $count= 0; - my @names=qw($+{A} $+{B} $+{C}); - if ($s=~/(?<A>foo)\s+(?<B>bar)?\s+(?<C>baz)/) { - while (my ($k,$v)=each(%+)) { - $count++; + + { + local $Message = "Relative Recursion"; + my $parens = qr/(\((?:[^()]++|(?-1))*+\))/; + local $_ = 'foo((2*3)+4-3) + bar(2*(3+4)-1*(2-3))'; + my ($all, $one, $two) = ('', '', ''); + ok /foo $parens \s* \+ \s* bar $parens/x; + iseq $1, '((2*3)+4-3)'; + iseq $2, '(2*(3+4)-1*(2-3))'; + iseq $&, 'foo((2*3)+4-3) + bar(2*(3+4)-1*(2-3))'; + iseq $&, $_; + } + + { + my $spaces=" "; + local $_ = join 'bar', $spaces, $spaces; + our $count = 0; + s/(?>\s+bar)(?{$count++})//g; + iseq $_, $spaces, "SUSPEND final string"; + iseq $count, 1, "Optimiser should have prevented more than one match"; + } + + { + local $BugId = '36909'; + local $Message = '(?: ... )? should not lose $^R'; + $^R = 'Nothing'; + { + local $^R = "Bad"; + ok 'x foofoo y' =~ m { + (foo) # $^R correctly set + (?{ "last regexp code result" }) + }x; + iseq $^R, 'last regexp code result'; } - @k=sort keys(%+); - @v=sort values(%+); - $res=1; - push @fetch, - [ "$+{A}", "$1" ], - [ "$+{B}", "$2" ], - [ "$+{C}", "$3" ], - ; - } - foreach (0..2) { - if ($fetch[$_]) { - iseq($fetch[$_][0],$fetch[$_][1],$names[$_]); - } else { - ok(0, $names[$_]); + iseq $^R, 'Nothing'; + + { + local $^R = "Bad"; + + ok 'x foofoo y' =~ m { + (?:foo|bar)+ # $^R correctly set + (?{ "last regexp code result" }) + }x; + iseq $^R, 'last regexp code result'; + } + iseq $^R, 'Nothing'; + + { + local $^R = "Bad"; + ok 'x foofoo y' =~ m { + (foo|bar)\1+ # $^R undefined + (?{ "last regexp code result" }) + }x; + iseq $^R, 'last regexp code result'; + } + iseq $^R, 'Nothing'; + + { + local $^R = "Bad"; + ok 'x foofoo y' =~ m { + (foo|bar)\1 # This time without the + + (?{"last regexp code result"}) + }x; + iseq $^R, 'last regexp code result'; } + iseq $^R, 'Nothing'; } - iseq($res,1,"$s~=/(?<A>foo)\s+(?<B>bar)?\s+(?<C>baz)/"); - iseq($count,3,"Got 3 keys in %+ via each"); - iseq(0+@k, 3, 'Got 3 keys in %+ via keys'); - iseq("@k","A B C", "Got expected keys"); - iseq("@v","bar baz foo", "Got expected values"); - eval' - print for $+{this_key_doesnt_exist}; - '; - ok(!$@,'lvalue $+{...} should not throw an exception'); -} -{ - my $s='foo bar baz'; - my @res; - if ('1234'=~/(?<A>1)(?<B>2)(?<A>3)(?<B>4)/) { - foreach my $name (sort keys(%-)) { - my $ary = $-{$name}; - foreach my $idx (0..$#$ary) { - push @res,"$name:$idx:$ary->[$idx]"; + + + { + local $BugId = '22395'; + local $Message = 'Match is linear, not quadratic'; + our $count; + for my $l (10, 100, 1000) { + $count = 0; + ('a' x $l) =~ /(.*)(?{$count++})[bc]/; + local $TODO = "Should be L+1 not L*(L+3)/2 (L=$l)"; + iseq $count, $l + 1; + } + } + + + { + local $BugId = '22614'; + local $Message = '@-/@+ should not have undefined values'; + local $_ = 'ab'; + our @len = (); + /(.){1,}(?{push @len,0+@-})(.){1,}(?{})^/; + iseq "@len", "2 2 2"; + } + + + { + local $BugId = '18209'; + local $Message = '$& set on s///'; + my $text = ' word1 word2 word3 word4 word5 word6 '; + + my @words = ('word1', 'word3', 'word5'); + my $count; + foreach my $word (@words) { + $text =~ s/$word\s//gi; # Leave a space to seperate words + # in the resultant str. + # The following block is not working. + if ($&) { + $count ++; } + # End bad block } + iseq $count, 3; + iseq $text, ' word2 word4 word6 '; } - my @expect=qw(A:0:1 A:1:3 B:0:2 B:1:4); - iseq("@res","@expect","Check %-"); - eval' - print for $-{this_key_doesnt_exist}; - '; - ok(!$@,'lvalue $-{...} should not throw an exception'); -} -# stress test CURLYX/WHILEM. -# -# This test includes varying levels of nesting, and according to -# profiling done against build 28905, exercises every code line in the -# CURLYX and WHILEM blocks, except those related to LONGJMP, the -# super-linear cache and warnings. It executes about 0.5M regexes - -if ($ENV{PERL_SKIP_PSYCHO_TEST}){ - printf "ok %d Skip: No psycho tests\n", $test++; -} else { - print "# set PERL_SKIP_PSYCHO_TEST to skip this test\n"; - my $r = qr/^ - (?: - ( (?:a|z+)+ ) - (?: - ( (?:b|z+){3,}? ) - ( - (?: - (?: - (?:c|z+){1,1}?z - )? - (?:c|z+){1,1} - )* - ) - (?:z*){2,} - ( (?:z+|d)+ ) - (?: - ( (?:e|z+)+ ) - )* - ( (?:f|z+)+ ) - )* - ( (?:z+|g)+ ) - (?: - ( (?:h|z+)+ ) - )* - ( (?:i|z+)+ ) - )+ - ( (?:j|z+)+ ) - (?: - ( (?:k|z+)+ ) - )* - ( (?:l|z+)+ ) - $/x; - - - my $ok = 1; - my $msg = "CURLYX stress test"; - OUTER: - for my $a ("x","a","aa") { - for my $b ("x","bbb","bbbb") { - my $bs = $a.$b; - for my $c ("x","c","cc") { - my $cs = $bs.$c; - for my $d ("x","d","dd") { - my $ds = $cs.$d; - for my $e ("x","e","ee") { - my $es = $ds.$e; - for my $f ("x","f","ff") { - my $fs = $es.$f; - for my $g ("x","g","gg") { - my $gs = $fs.$g; - for my $h ("x","h","hh") { - my $hs = $gs.$h; - for my $i ("x","i","ii") { - my $is = $hs.$i; - for my $j ("x","j","jj") { - my $js = $is.$j; - for my $k ("x","k","kk") { - my $ks = $js.$k; - for my $l ("x","l","ll") { - my $ls = $ks.$l; - if ($ls =~ $r) { - if ($ls =~ /x/) { - $msg .= ": unexpected match for [$ls]"; - $ok = 0; - last OUTER; - } - my $cap = "$1$2$3$4$5$6$7$8$9$10$11$12"; - unless ($ls eq $cap) { - $msg .= ": capture: [$ls], got [$cap]"; - $ok = 0; - last OUTER; - } - } - else { - unless ($ls =~ /x/) { - $msg = ": failed for [$ls]"; - $ok = 0; - last OUTER; - } - } + + + { + # RT#6893 + local $BugId = '6893'; + local $_ = qq (A\nB\nC\n); + my @res; + while (m#(\G|\n)([^\n]*)\n#gsx) { + push @res, "$2"; + last if @res > 3; + } + iseq "@res", "A B C", "/g pattern shouldn't infinite loop"; + } + + + { + # From Message-ID: <877ixs6oa6.fsf@k75.linux.bogus> + my $dow_name = "nada"; + my $parser = "(\$dow_name) = \$time_string =~ /(D\x{e9}\\ " . + "C\x{e9}adaoin|D\x{e9}\\ Sathairn|\\w+|\x{100})/"; + my $time_string = "D\x{e9} C\x{e9}adaoin"; + eval $parser; + ok !$@, "Test Eval worked"; + iseq $dow_name, $time_string, "UTF-8 trie common prefix extraction"; + } + + + { + my $v; + ($v = 'bar') =~ /(\w+)/g; + $v = 'foo'; + iseq "$1", 'bar', '$1 is safe after /g - may fail due ' . + 'to specialized config in pp_hot.c' + } + + + { + local $Message = "http://nntp.perl.org/group/perl.perl5.porters/118663"; + my $qr_barR1 = qr/(bar)\g-1/; + ok "foobarbarxyz" =~ $qr_barR1; + ok "foobarbarxyz" =~ qr/foo${qr_barR1}xyz/; + ok "foobarbarxyz" =~ qr/(foo)${qr_barR1}xyz/; + ok "foobarbarxyz" =~ qr/(foo)(bar)\g{-1}xyz/; + ok "foobarbarxyz" =~ qr/(foo${qr_barR1})xyz/; + ok "foobarbarxyz" =~ qr/(foo(bar)\g{-1})xyz/; + } + + + { + local $BugId = '41010'; + local $Message = 'No optimizer bug'; + my @tails = ('', '(?(1))', '(|)', '()?'); + my @quants = ('*','+'); + my $doit = sub { + my $pats = shift; + for (@_) { + for my $pat (@$pats) { + for my $quant (@quants) { + for my $tail (@tails) { + my $re = "($pat$quant\$)$tail"; + ok /$re/ && $1 eq $_, "'$_' =~ /$re/"; + ok /$re/m && $1 eq $_, "'$_' =~ /$re/m"; } - } } - } } - } } - } + }; + + my @dpats = ('\d', + '[1234567890]', + '(1|[23]|4|[56]|[78]|[90])', + '(?:1|[23]|4|[56]|[78]|[90])', + '(1|2|3|4|5|6|7|8|9|0)', + '(?:1|2|3|4|5|6|7|8|9|0)'); + my @spats = ('[ ]', ' ', '( |\t)', '(?: |\t)', '[ \t]', '\s'); + my @sstrs = (' '); + my @dstrs = ('12345'); + $doit -> (\@spats, @sstrs); + $doit -> (\@dpats, @dstrs); + } + + + { + local $Message = '$REGMARK'; + our @r = (); + our ($REGMARK, $REGERROR); + ok 'foofoo' =~ /foo (*MARK:foo) (?{push @r,$REGMARK}) /x; + iseq "@r","foo"; + iseq $REGMARK, "foo"; + ok 'foofoo' !~ /foo (*MARK:foo) (*FAIL) /x; + ok !$REGMARK; + iseq $REGERROR, 'foo'; + } + + + { + local $Message = '\K test'; + my $x; + $x = "abc.def.ghi.jkl"; + $x =~ s/.*\K\..*//; + iseq $x, "abc.def.ghi"; + + $x = "one two three four"; + $x =~ s/o+ \Kthree//g; + iseq $x, "one two four"; + + $x = "abcde"; + $x =~ s/(.)\K/$1/g; + iseq $x, "aabbccddee"; + } + + + { + sub kt { + return '4' if $_[0] eq '09028623'; } - } + # Nested EVAL using PL_curpm (via $1 or friends) + my $re; + our $grabit = qr/ ([0-6][0-9]{7}) (??{ kt $1 }) [890] /x; + $re = qr/^ ( (??{ $grabit }) ) $ /x; + my @res = '0902862349' =~ $re; + iseq join ("-", @res), "0902862349", + 'PL_curpm is set properly on nested eval'; + + our $qr = qr/ (o) (??{ $1 }) /x; + ok 'boob'=~/( b (??{ $qr }) b )/x && 1, "PL_curpm, nested eval"; } - } - ok($ok, $msg); -} -# \, breaks {3,4} -ok("xaaay" !~ /xa{3\,4}y/, "\, in a pattern"); -ok("xa{3,4}y" =~ /xa{3\,4}y/, "\, in a pattern"); -# \c\ followed by _ -ok("x\c_y" !~ /x\c\_y/, "\_ in a pattern"); -ok("x\c\_y" =~ /x\c\_y/, "\_ in a pattern"); + { + use charnames ":full"; + ok "\N{ROMAN NUMERAL ONE}" =~ /\p{Alphabetic}/, "I =~ Alphabetic"; + ok "\N{ROMAN NUMERAL ONE}" =~ /\p{Uppercase}/, "I =~ Uppercase"; + ok "\N{ROMAN NUMERAL ONE}" !~ /\p{Lowercase}/, "I !~ Lowercase"; + ok "\N{ROMAN NUMERAL ONE}" =~ /\p{IDStart}/, "I =~ ID_Start"; + ok "\N{ROMAN NUMERAL ONE}" =~ /\p{IDContinue}/, "I =~ ID_Continue"; + ok "\N{SMALL ROMAN NUMERAL ONE}" =~ /\p{Alphabetic}/, "i =~ Alphabetic"; + ok "\N{SMALL ROMAN NUMERAL ONE}" !~ /\p{Uppercase}/, "i !~ Uppercase"; + ok "\N{SMALL ROMAN NUMERAL ONE}" =~ /\p{Lowercase}/, "i =~ Lowercase"; + ok "\N{SMALL ROMAN NUMERAL ONE}" =~ /\p{IDStart}/, "i =~ ID_Start"; + ok "\N{SMALL ROMAN NUMERAL ONE}" =~ /\p{IDContinue}/, "i =~ ID_Continue" + } -# \c\ followed by other characters -for my $c ("z", "\0", "!", chr(254), chr(256)) { - my $targ = "a\034$c"; - my $reg = "a\\c\\$c"; - ok(eval("qq/$targ/ =~ /$reg/"), "\\c\\ in pattern"); -} -{ - my $str='abc'; - my $count=0; - my $mval=0; - my $pval=0; - while ($str=~/b/g) { $mval=$#-; $pval=$#+; $count++ } - iseq($mval,0,"\@- should be empty [RT#36046]"); - iseq($pval,0,"\@+ should be empty [RT#36046]"); - iseq($count,1,"should have matched once only [RT#36046]"); -} + { + # requirement of Unicode Technical Standard #18, 1.7 Code Points + # cf. http://www.unicode.org/reports/tr18/#Supplementary_Characters + for my $u (0x7FF, 0x800, 0xFFFF, 0x10000) { + no warnings 'utf8'; # oops + my $c = chr $u; + my $x = sprintf '%04X', $u; + ok "A${c}B" =~ /A[\0-\x{10000}]B/, "Unicode range - $x"; + } + } -{ # Test the (*PRUNE) pattern - our $count = 0; - 'aaab'=~/a+b?(?{$count++})(*FAIL)/; - iseq($count,9,"expect 9 for no (*PRUNE)"); - $count = 0; - 'aaab'=~/a+b?(*PRUNE)(?{$count++})(*FAIL)/; - iseq($count,3,"expect 3 with (*PRUNE)"); - local $_='aaab'; - $count=0; - 1 while /.(*PRUNE)(?{$count++})(*FAIL)/g; - iseq($count,4,"/.(*PRUNE)/"); - $count = 0; - 'aaab'=~/a+b?(??{'(*PRUNE)'})(?{$count++})(*FAIL)/; - iseq($count,3,"expect 3 with (*PRUNE)"); - local $_='aaab'; - $count=0; - 1 while /.(??{'(*PRUNE)'})(?{$count++})(*FAIL)/g; - iseq($count,4,"/.(*PRUNE)/"); -} -{ # Test the (*SKIP) pattern - our $count = 0; - 'aaab'=~/a+b?(*SKIP)(?{$count++})(*FAIL)/; - iseq($count,1,"expect 1 with (*SKIP)"); - local $_='aaab'; - $count=0; - 1 while /.(*SKIP)(?{$count++})(*FAIL)/g; - iseq($count,4,"/.(*SKIP)/"); - $_='aaabaaab'; - $count=0; - our @res=(); - 1 while /(a+b?)(*SKIP)(?{$count++; push @res,$1})(*FAIL)/g; - iseq($count,2,"Expect 2 with (*SKIP)" ); - iseq("@res","aaab aaab","adjacent (*SKIP) works as expected" ); -} -{ # Test the (*SKIP) pattern - our $count = 0; - 'aaab'=~/a+b?(*MARK:foo)(*SKIP)(?{$count++})(*FAIL)/; - iseq($count,1,"expect 1 with (*SKIP)"); - local $_='aaab'; - $count=0; - 1 while /.(*MARK:foo)(*SKIP)(?{$count++})(*FAIL)/g; - iseq($count,4,"/.(*SKIP)/"); - $_='aaabaaab'; - $count=0; - our @res=(); - 1 while /(a+b?)(*MARK:foo)(*SKIP)(?{$count++; push @res,$1})(*FAIL)/g; - iseq($count,2,"Expect 2 with (*SKIP)" ); - iseq("@res","aaab aaab","adjacent (*SKIP) works as expected" ); -} -{ # Test the (*SKIP) pattern - our $count = 0; - 'aaab'=~/a*(*MARK:a)b?(*MARK:b)(*SKIP:a)(?{$count++})(*FAIL)/; - iseq($count,3,"expect 3 with *MARK:a)b?(*MARK:b)(*SKIP:a)"); - local $_='aaabaaab'; - $count=0; - our @res=(); - 1 while /(a*(*MARK:a)b?)(*MARK:x)(*SKIP:a)(?{$count++; push @res,$1})(*FAIL)/g; - iseq($count,5,"Expect 5 with (*MARK:a)b?)(*MARK:x)(*SKIP:a)" ); - iseq("@res","aaab b aaab b ","adjacent (*MARK:a)b?)(*MARK:x)(*SKIP:a) works as expected" ); -} -{ # Test the (*COMMIT) pattern - our $count = 0; - 'aaabaaab'=~/a+b?(*COMMIT)(?{$count++})(*FAIL)/; - iseq($count,1,"expect 1 with (*COMMIT)"); - local $_='aaab'; - $count=0; - 1 while /.(*COMMIT)(?{$count++})(*FAIL)/g; - iseq($count,1,"/.(*COMMIT)/"); - $_='aaabaaab'; - $count=0; - our @res=(); - 1 while /(a+b?)(*COMMIT)(?{$count++; push @res,$1})(*FAIL)/g; - iseq($count,1,"Expect 1 with (*COMMIT)" ); - iseq("@res","aaab","adjacent (*COMMIT) works as expected" ); -} -{ - # Test named commits and the $REGERROR var - our $REGERROR; - for my $name ('',':foo') - { - for my $pat ("(*PRUNE$name)", - ($name? "(*MARK$name)" : "") - . "(*SKIP$name)", - "(*COMMIT$name)") - { - for my $suffix ('(*FAIL)','') - { - 'aaaab'=~/a+b$pat$suffix/; - iseq( - $REGERROR, - ($suffix ? ($name ? 'foo' : "1") : ""), - "Test $pat and \$REGERROR $suffix" - ); - } + + { + my $res=""; + + if ('1' =~ /(?|(?<digit>1)|(?<digit>2))/) { + $res = "@{$- {digit}}"; } - } -} -{ - # Test named commits and the $REGERROR var - package Fnorble; - our $REGERROR; - for my $name ('',':foo') - { - for my $pat ("(*PRUNE$name)", - ($name? "(*MARK$name)" : "") - . "(*SKIP$name)", - "(*COMMIT$name)") - { - for my $suffix ('(*FAIL)','') - { - 'aaaab'=~/a+b$pat$suffix/; - ::iseq( - $REGERROR, - ($suffix ? ($name ? 'foo' : "1") : ""), - "Test $pat and \$REGERROR $suffix" - ); - } + iseq $res, "1", + "Check that (?|...) doesnt cause dupe entries in the names array"; + + $res = ""; + if ('11' =~ /(?|(?<digit>1)|(?<digit>2))(?&digit)/) { + $res = "@{$- {digit}}"; } - } -} -{ - # Test named commits and the $REGERROR var - local $Message = "\$REGERROR"; - our $REGERROR; - for $word (qw(bar baz bop)) { - $REGERROR=""; - "aaaaa$word"=~/a+(?:bar(*COMMIT:bar)|baz(*COMMIT:baz)|bop(*COMMIT:bop))(*FAIL)/; - iseq($REGERROR,$word); + iseq $res, "1", "Check that (?&..) to a buffer inside " . + "a (?|...) goes to the leftmost"; + } + + + { + use warnings; + local $Message = "ASCII pattern that really is UTF-8"; + my @w; + local $SIG {__WARN__} = sub {push @w, "@_"}; + my $c = qq (\x{DF}); + ok $c =~ /${c}|\x{100}/; + ok @w == 0; } -} -{ #Regression test for perlbug 40684 - local $Message = "RT#40684 tests:"; - my $s = "abc\ndef"; - my $rex = qr'^abc$'m; - ok($s =~ m/$rex/); - ok($s =~ m/^abc$/m); -} -{ - #Mindnumbingly simple test of (*THEN) - for ("ABC","BAX") { - ok(/A (*THEN) X | B (*THEN) C/x,"Simple (*THEN) test"); + + + { + local $Message = "Corruption of match results of qr// across scopes"; + my $qr = qr/(fo+)(ba+r)/; + 'foobar' =~ /$qr/; + iseq "$1$2", "foobar"; + { + 'foooooobaaaaar' =~ /$qr/; + iseq "$1$2", 'foooooobaaaaar'; + } + iseq "$1$2", "foobar"; } -} -{ - local $Message = "Relative Recursion"; - my $parens=qr/(\((?:[^()]++|(?-1))*+\))/; - local $_='foo((2*3)+4-3) + bar(2*(3+4)-1*(2-3))'; - my ($all,$one,$two)=('','',''); - if (/foo $parens \s* \+ \s* bar $parens/x) { - $all=$&; - $one=$1; - $two=$2; - } - iseq($one, '((2*3)+4-3)'); - iseq($two, '(2*(3+4)-1*(2-3))'); - iseq($all, 'foo((2*3)+4-3) + bar(2*(3+4)-1*(2-3))'); - iseq($all, $_); -} -{ - my $spaces=" "; - local $_=join 'bar',$spaces,$spaces; - our $count=0; - s/(?>\s+bar)(?{$count++})//g; - iseq($_,$spaces,"SUSPEND final string"); - iseq($count,1,"Optimiser should have prevented more than one match"); -} -{ - local $Message = "RT#36909 test"; - $^R = 'Nothing'; + { - local $^R = "Bad"; - ok('x foofoo y' =~ m{ - (foo) # $^R correctly set - (?{ "last regexp code result" }) - }x); - iseq($^R,'last regexp code result'); + local $Message = "HORIZWS"; + local $_ = "\t \r\n \n \t".chr(11)."\n"; + s/\H/H/g; + s/\h/h/g; + iseq $_, "hhHHhHhhHH"; + $_ = "\t \r\n \n \t" . chr (11) . "\n"; + utf8::upgrade ($_); + s/\H/H/g; + s/\h/h/g; + iseq $_, "hhHHhHhhHH"; + } + + + { + local $Message = "Various whitespace special patterns"; + my @h = map {chr $_} 0x09, 0x20, 0xa0, 0x1680, 0x180e, 0x2000, + 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, + 0x2007, 0x2008, 0x2009, 0x200a, 0x202f, 0x205f, + 0x3000; + my @v = map {chr $_} 0x0a, 0x0b, 0x0c, 0x0d, 0x85, 0x2028, + 0x2029; + my @lb = ("\x0D\x0A", map {chr $_} 0x0A .. 0x0D, 0x85, 0x2028, 0x2029); + foreach my $t ([\@h, qr/\h/, qr/\h+/], + [\@v, qr/\v/, qr/\v+/], + [\@lb, qr/\R/, qr/\R+/],) { + my $ary = shift @$t; + foreach my $pat (@$t) { + foreach my $str (@$ary) { + ok $str =~ /($pat)/, $pat; + iseq $1, $str, $pat; + utf8::upgrade ($str); + ok $str =~ /($pat)/, "Upgraded string - $pat"; + iseq $1, $str, "Upgraded string - $pat"; + } + } + } } - iseq($^R,'Nothing'); + + { - local $^R = "Bad"; + local $Message = "Check that \\xDF match properly in its various forms"; + # Test that \xDF matches properly. this is pretty hacky stuff, + # but its actually needed. The malarky with '-' is to prevent + # compilation caching from playing any role in the test. + my @df = (chr (0xDF), '-', chr (0xDF)); + utf8::upgrade ($df [2]); + my @strs = ('ss', 'sS', 'Ss', 'SS', chr (0xDF)); + my @ss = map {("$_", "$_")} @strs; + utf8::upgrade ($ss [$_ * 2 + 1]) for 0 .. $#strs; + + for my $ssi (0 .. $#ss) { + for my $dfi (0 .. $#df) { + my $pat = $df [$dfi]; + my $str = $ss [$ssi]; + my $utf_df = ($dfi > 1) ? 'utf8' : ''; + my $utf_ss = ($ssi % 2) ? 'utf8' : ''; + (my $sstr = $str) =~ s/\xDF/\\xDF/; + + if ($utf_df || $utf_ss || length ($ss [$ssi]) == 1) { + my $ret = $str =~ /$pat/i; + next if $pat eq '-'; + ok $ret, "\"$sstr\" =~ /\\xDF/i " . + "(str is @{[$utf_ss||'latin']}, pat is " . + "@{[$utf_df||'latin']})"; + } + else { + my $ret = $str !~ /$pat/i; + next if $pat eq '-'; + ok $ret, "\"$sstr\" !~ /\\xDF/i " . + "(str is @{[$utf_ss||'latin']}, pat is " . + "@{[$utf_df||'latin']})"; + } + } + } + } + + + { + local $Message = "BBC(Bleadperl Breaks CPAN) Today: String::Multibyte"; + my $re = qr/(?:[\x00-\xFF]{4})/; + my $hyp = "\0\0\0-"; + my $esc = "\0\0\0\\"; + + my $str = "$esc$hyp$hyp$esc$esc"; + my @a = ($str =~ /\G(?:\Q$esc$esc\E|\Q$esc$hyp\E|$re)/g); + + iseq @a,3; + local $" = "="; + iseq "@a","$esc$hyp=$hyp=$esc$esc"; + } + - ok('x foofoo y' =~ m{ - (?:foo|bar)+ # $^R correctly set - (?{"last regexp code result"}) - }x); - iseq($^R,'last regexp code result'); + { + # Test for keys in %+ and %- + local $Message = 'Test keys in %+ and %-'; + no warnings 'uninitialized'; + my $_ = "abcdef"; + /(?<foo>a)|(?<foo>b)/; + iseq ((join ",", sort keys %+), "foo"); + iseq ((join ",", sort keys %-), "foo"); + iseq ((join ",", sort values %+), "a"); + iseq ((join ",", sort map "@$_", values %-), "a "); + /(?<bar>a)(?<bar>b)(?<quux>.)/; + iseq ((join ",", sort keys %+), "bar,quux"); + iseq ((join ",", sort keys %-), "bar,quux"); + iseq ((join ",", sort values %+), "a,c"); # leftmost + iseq ((join ",", sort map "@$_", values %-), "a b,c"); + /(?<un>a)(?<deux>c)?/; # second buffer won't capture + iseq ((join ",", sort keys %+), "un"); + iseq ((join ",", sort keys %-), "deux,un"); + iseq ((join ",", sort values %+), "a"); + iseq ((join ",", sort map "@$_", values %-), ",a"); } - iseq($^R,'Nothing'); + { - local $^R = "Bad"; - ok('x foofoo y' =~ m{ - (foo|bar)\1+ # $^R undefined - (?{"last regexp code result"}) - }x); - iseq($^R,'last regexp code result'); + # length() on captures, the numbered ones end up in Perl_magic_len + my $_ = "aoeu \xe6var ook"; + /^ \w+ \s (?<eek>\S+)/x; + + iseq length ($`), 0, q[length $`]; + iseq length ($'), 4, q[length $']; + iseq length ($&), 9, q[length $&]; + iseq length ($1), 4, q[length $1]; + iseq length ($+{eek}), 4, q[length $+{eek} == length $1]; } - iseq($^R,'Nothing'); + { - local $^R = "Bad"; - ok('x foofoo y' =~ m{ - (foo|bar)\1 # this time without the + - (?{"last regexp code result"}) - }x); - iseq($^R,'last regexp code result'); + my $ok = -1; + + $ok = exists ($-{x}) ? 1 : 0 if 'bar' =~ /(?<x>foo)|bar/; + iseq $ok, 1, '$-{x} exists after "bar"=~/(?<x>foo)|bar/'; + iseq scalar (%+), 0, 'scalar %+ == 0 after "bar"=~/(?<x>foo)|bar/'; + iseq scalar (%-), 1, 'scalar %- == 1 after "bar"=~/(?<x>foo)|bar/'; + + $ok = -1; + $ok = exists ($+{x}) ? 1 : 0 if 'bar' =~ /(?<x>foo)|bar/; + iseq $ok, 0, '$+{x} not exists after "bar"=~/(?<x>foo)|bar/'; + iseq scalar (%+), 0, 'scalar %+ == 0 after "bar"=~/(?<x>foo)|bar/'; + iseq scalar (%-), 1, 'scalar %- == 1 after "bar"=~/(?<x>foo)|bar/'; + + $ok = -1; + $ok = exists ($-{x}) ? 1 : 0 if 'foo' =~ /(?<x>foo)|bar/; + iseq $ok, 1, '$-{x} exists after "foo"=~/(?<x>foo)|bar/'; + iseq scalar (%+), 1, 'scalar %+ == 1 after "foo"=~/(?<x>foo)|bar/'; + iseq scalar (%-), 1, 'scalar %- == 1 after "foo"=~/(?<x>foo)|bar/'; + + $ok = -1; + $ok = exists ($+{x}) ? 1 : 0 if 'foo'=~/(?<x>foo)|bar/; + iseq $ok, 1, '$+{x} exists after "foo"=~/(?<x>foo)|bar/'; } - iseq($^R,'Nothing'); -} -{ - local $Message="RT#22395"; - our $count; - for my $l (10,100,1000) { - $count=0; - ('a' x $l) =~ /(.*)(?{$count++})[bc]/; - iseq( $count, $l + 1, "# TODO Should be L+1 not L*(L+3)/2 (L=$l)"); + + + { + local $_; + ($_ = 'abc') =~ /(abc)/g; + $_ = '123'; + iseq "$1", 'abc', "/g leads to unsafe match vars: $1"; } -} -{ - local $Message = "RT#22614"; - local $_='ab'; - our @len=(); - /(.){1,}(?{push @len,0+@-})(.){1,}(?{})^/; - iseq("@len","2 2 2"); -} -{ - local $Message = "RT#18209"; - my $text = ' word1 word2 word3 word4 word5 word6 '; - - my @words = ('word1', 'word3', 'word5'); - my $count; - foreach my $word (@words){ - $text =~ s/$word\s//gi; # Leave a space to seperate words in the resultant str. - # The following block is not working. - if($&){ - $count++; + + + { + local $Message = 'Message-ID: <20070818091501.7eff4831@r2d2>'; + my $str = ""; + for (0 .. 5) { + my @x; + $str .= "@x"; # this should ALWAYS be the empty string + 'a' =~ /(a|)/; + push @x, 1; } - # End bad block + iseq length ($str), 0, "Trie scope error, string should be empty"; + $str = ""; + my @foo = ('a') x 5; + for (@foo) { + my @bar; + $str .= "@bar"; + s/a|/push @bar, 1/e; + } + iseq length ($str), 0, "Trie scope error, string should be empty"; } - iseq($count,3); - iseq($text,' word2 word4 word6 '); -} -{ - # RT#6893 - local $_= qq(A\nB\nC\n); - my @res; - while (m#(\G|\n)([^\n]*)\n#gsx) - { - push @res,"$2"; - last if @res>3; - } - iseq("@res","A B C","RT#6893: /g pattern shouldn't infinite loop"); -} -{ - # From Message-ID: <877ixs6oa6.fsf@k75.linux.bogus> - my $dow_name= "nada"; - my $parser = "(\$dow_name) = \$time_string =~ /(D\x{e9}\\ C\x{e9}adaoin|D\x{e9}\\ Sathairn|\\w+|\x{100})/"; - my $time_string = "D\x{e9} C\x{e9}adaoin"; - eval $parser; - ok(!$@,"Test Eval worked"); - iseq($dow_name,$time_string,"UTF8 trie common prefix extraction"); -} -{ - my $v; - ($v='bar')=~/(\w+)/g; - $v='foo'; - iseq("$1",'bar','$1 is safe after /g - may fail due to specialized config in pp_hot.c') -} -{ - local $Message = "http://nntp.perl.org/group/perl.perl5.porters/118663"; - my $qr_barR1 = qr/(bar)\g-1/; - ok("foobarbarxyz" =~ $qr_barR1); - ok("foobarbarxyz" =~ qr/foo${qr_barR1}xyz/); - ok("foobarbarxyz" =~ qr/(foo)${qr_barR1}xyz/); - ok("foobarbarxyz" =~ qr/(foo)(bar)\g{-1}xyz/); - ok("foobarbarxyz" =~ qr/(foo${qr_barR1})xyz/); - ok("foobarbarxyz" =~ qr/(foo(bar)\g{-1})xyz/); -} -{ - local $Message = "RT#41010"; - my @tails=('','(?(1))','(|)','()?'); - my @quants=('*','+'); - my $doit=sub { - my $pats= shift; - for (@_) { - for my $pat (@$pats) { - for my $quant (@quants) { - for my $tail (@tails) { - my $re = "($pat$quant\$)$tail"; - ok(/$re/ && $1 eq $_,"'$_'=~/$re/"); - ok(/$re/m && $1 eq $_,"'$_'=~/$re/m"); - } + { + local $BugId = '45605'; + # [perl #45605] Regexp failure with utf8-flagged and byte-flagged string + + my $utf_8 = "\xd6schel"; + utf8::upgrade ($utf_8); + $utf_8 =~ m {(\xd6|Ö)schel}; + iseq $1, "\xd6", "Upgrade error"; + } + + { +# more TRIE/AHOCORASICK problems with mixed utf8 / latin-1 and case folding + for my $chr (160 .. 255) { + my $chr_byte = chr($chr); + my $chr_utf8 = chr($chr); utf8::upgrade($chr_utf8); + my $rx = qr{$chr_byte|X}i; + ok($chr_utf8 =~ $rx, "utf8/latin, codepoint $chr"); + } + } + + { + # Regardless of utf8ness any character matches itself when + # doing a case insensitive match. See also [perl #36207] + local $BugId = '36207'; + for my $o (0 .. 255) { + my @ch = (chr ($o), chr ($o)); + utf8::upgrade ($ch [1]); + for my $u_str (0, 1) { + for my $u_pat (0, 1) { + ok $ch [$u_str] =~ /\Q$ch[$u_pat]\E/i, + "\$c =~ /\$c/i : chr ($o) : u_str = $u_str u_pat = $u_pat"; + ok $ch [$u_str] =~ /\Q$ch[$u_pat]\E|xyz/i, + "\$c=~/\$c|xyz/i : chr($o) : u_str = $u_str u_pat = $u_pat"; } } - } - }; - - my @dpats=( - '\d', - '[1234567890]', - '(1|[23]|4|[56]|[78]|[90])', - '(?:1|[23]|4|[56]|[78]|[90])', - '(1|2|3|4|5|6|7|8|9|0)', - '(?:1|2|3|4|5|6|7|8|9|0)', - ); - my @spats=('[ ]',' ','( |\t)','(?: |\t)','[ \t]','\s'); - my @sstrs=(' '); - my @dstrs=('12345'); - $doit->(\@spats,@sstrs); - $doit->(\@dpats,@dstrs); -} -{ - local $Message = "\$REGMARK"; - our @r=(); - ok('foofoo' =~ /foo (*MARK:foo) (?{push @r,$REGMARK}) /x); - iseq("@r","foo"); - iseq($REGMARK,"foo"); - ok('foofoo' !~ /foo (*MARK:foo) (*FAIL) /x); - ok(!$REGMARK); - iseq($REGERROR,'foo'); -} -{ - my $x; - $x = "abc.def.ghi.jkl"; - $x =~ s/.*\K\..*//; - ok($x eq "abc.def.ghi"); - - $x = "one two three four"; - $x =~ s/o+ \Kthree//g; - ok($x eq "one two four"); - - $x = "abcde"; - $x =~ s/(.)\K/$1/g; - ok($x eq "aabbccddee"); -} -sub kt -{ - return '4' if $_[0] eq '09028623'; -} + } + } -{ # Nested EVAL using PL_curpm (via $1 or friends) - my $re; - our $grabit = qr/ ([0-6][0-9]{7}) (??{ kt $1 }) [890] /x; - $re = qr/^ ( (??{ $grabit }) ) $ /x; - my @res = '0902862349' =~ $re; - iseq(join("-",@res),"0902862349", - 'PL_curpm is set properly on nested eval'); - - our $qr = qr/ (o) (??{ $1 }) /x; - ok( 'boob'=~/( b (??{ $qr }) b )/x && 1, - "PL_curpm, nested eval"); -} -{ - use charnames ":full"; - ok("\N{ROMAN NUMERAL ONE}" =~ /\p{Alphabetic}/, "I =~ Alphabetic"); - ok("\N{ROMAN NUMERAL ONE}" =~ /\p{Uppercase}/, "I =~ Uppercase"); - ok("\N{ROMAN NUMERAL ONE}" !~ /\p{Lowercase}/, "I !~ Lowercase"); - ok("\N{ROMAN NUMERAL ONE}" =~ /\p{IDStart}/, "I =~ ID_Start"); - ok("\N{ROMAN NUMERAL ONE}" =~ /\p{IDContinue}/, "I =~ ID_Continue"); - ok("\N{SMALL ROMAN NUMERAL ONE}" =~ /\p{Alphabetic}/, "i =~ Alphabetic"); - ok("\N{SMALL ROMAN NUMERAL ONE}" !~ /\p{Uppercase}/, "i !~ Uppercase"); - ok("\N{SMALL ROMAN NUMERAL ONE}" =~ /\p{Lowercase}/, "i =~ Lowercase"); - ok("\N{SMALL ROMAN NUMERAL ONE}" =~ /\p{IDStart}/, "i =~ ID_Start"); - ok("\N{SMALL ROMAN NUMERAL ONE}" =~ /\p{IDContinue}/, "i =~ ID_Continue"); -} + { + our $a = 3; "" =~ /(??{ $a })/; + our $b = $a; + iseq $b, $a, "Copy of scalar used for postponed subexpression"; + } + -{ -# requirement of Unicode Technical Standard #18, 1.7 Code Points -# cf. http://www.unicode.org/reports/tr18/#Supplementary_Characters - for my $u (0x7FF, 0x800, 0xFFFF, 0x10000) { - no warnings 'utf8'; # oops - my $c = chr $u; - my $x = sprintf '%04X', $u; - ok( "A${c}B" =~ /A[\0-\x{10000}]B/, "unicode range - $x"); + { + local $BugId = '49190'; + local $Message = '$REGMARK in replacement'; + our $REGMARK; + my $_ = "A"; + ok s/(*:B)A/$REGMARK/; + iseq $_, "B"; + $_ = "CCCCBAA"; + ok s/(*:X)A+|(*:Y)B+|(*:Z)C+/$REGMARK/g; + iseq $_, "ZYX"; + } + + + { + our @ctl_n = (); + our @plus = (); + our $nested_tags; + $nested_tags = qr{ + < + (\w+) + (?{ + push @ctl_n,$^N; + push @plus,$+; + }) + > + (??{$nested_tags})* + </\s* \w+ \s*> + }x; + + my $match = '<bla><blubb></blubb></bla>' =~ m/^$nested_tags$/; + ok $match, 'nested construct matches'; + iseq "@ctl_n", "bla blubb", '$^N inside of (?{}) works as expected'; + iseq "@plus", "bla blubb", '$+ inside of (?{}) works as expected'; } -} -{ - my $res=""; - if ('1' =~ /(?|(?<digit>1)|(?<digit>2))/) { - $res = "@{$- {digit}}"; + { + local $BugId = '52658'; + local $Message = 'Substitution evaluation in list context'; + my $reg = '../xxx/'; + my @te = ($reg =~ m{^(/?(?:\.\./)*)}, + $reg =~ s/(x)/'b'/eg > 1 ? '##' : '++'); + iseq $reg, '../bbb/'; + iseq $te [0], '../'; } - iseq($res,"1", - "Check that (?|...) doesnt cause dupe entries in the names array"); - #--- - $res=""; - if ('11' =~ /(?|(?<digit>1)|(?<digit>2))(?&digit)/) { - $res = "@{$- {digit}}"; + + # This currently has to come before any "use encoding" in this file. + { + local $Message; + local $BugId = '59342'; + # for 5.10.x, add a dummy test indead + #must_warn 'qr/\400/', '^Use of octal value above 377'; + $Message=""; ok 1; } - iseq($res, "1", - "Check that (?&..) to a buffer inside a (?|...) goes to the leftmost"); -} -{ - use warnings; - local $Message = "ASCII pattern that really is utf8"; - my @w; - local $SIG{__WARN__}=sub{push @w,"@_"}; - my $c=qq(\x{DF}); - ok($c=~/${c}|\x{100}/); - ok(@w==0); -} -{ - local $Message = "corruption of match results of qr// across scopes"; - my $qr=qr/(fo+)(ba+r)/; - 'foobar'=~/$qr/; - iseq("$1$2","foobar"); - { - 'foooooobaaaaar'=~/$qr/; - iseq("$1$2",'foooooobaaaaar'); - } - iseq("$1$2","foobar"); -} -{ - local $Message = "HORIZWS"; - local $_="\t \r\n \n \t".chr(11)."\n"; - s/\H/H/g; - s/\h/h/g; - iseq($_,"hhHHhHhhHH"); - $_="\t \r\n \n \t".chr(11)."\n"; - utf8::upgrade($_); - s/\H/H/g; - s/\h/h/g; - iseq($_,"hhHHhHhhHH"); -} -{ - local $Message = "Various whitespace special patterns"; - my @h=map { chr( $_ ) } ( - 0x09, 0x20, 0xa0, 0x1680, 0x180e, 0x2000, 0x2001, 0x2002, - 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200a, - 0x202f, 0x205f, 0x3000 - ); - my @v=map { chr( $_ ) } ( 0x0a, 0x0b, 0x0c, 0x0d, 0x85, 0x2028, 0x2029 ); - my @lb=( "\x0D\x0A", - map { chr( $_ ) } ( 0x0A..0x0D,0x85,0x2028,0x2029 )); - foreach my $t ([\@h,qr/\h/,qr/\h+/],[\@v,qr/\v/,qr/\v+/],[\@lb,qr/\R/,qr/\R+/],){ - my $ary=shift @$t; - foreach my $pat (@$t) { - foreach my $str (@$ary) { - ok($str=~/($pat)/,$pat); - iseq($1,$str,$pat); - utf8::upgrade($str); - ok($str=~/($pat)/,"Upgraded string - $pat"); - iseq($1,$str,"Upgraded string - $pat"); - } + + SKIP: { + # XXX: This set of tests is essentially broken, POSIX character classes + # should not have differing definitions under Unicode. + # There are property names for that. + skip "Tests assume ASCII", 4 unless $IS_ASCII; + + my @notIsPunct = grep {/[[:punct:]]/ and not /\p{IsPunct}/} + map {chr} 0x20 .. 0x7f; + iseq join ('', @notIsPunct), '$+<=>^`|~', + '[:punct:] disagress with IsPunct on Symbols'; + + my @isPrint = grep {not /[[:print:]]/ and /\p{IsPrint}/} + map {chr} 0 .. 0x1f, 0x7f .. 0x9f; + iseq join ('', @isPrint), "\x09\x0a\x0b\x0c\x0d\x85", + 'IsPrint disagrees with [:print:] on control characters'; + + my @isPunct = grep {/[[:punct:]]/ != /\p{IsPunct}/} + map {chr} 0x80 .. 0xff; + iseq join ('', @isPunct), "\xa1\xab\xb7\xbb\xbf", # ¡ « · » ¿ + 'IsPunct disagrees with [:punct:] outside ASCII'; + + my @isPunctLatin1 = eval q { + use encoding 'latin1'; + grep {/[[:punct:]]/ != /\p{IsPunct}/} map {chr} 0x80 .. 0xff; + }; + skip "Eval failed ($@)", 1 if $@; + skip "PERL_LEGACY_UNICODE_CHARCLASS_MAPPINGS set to 0", 1 + if $ENV {REAL_POSIX_CC}; + iseq join ('', @isPunctLatin1), '', + 'IsPunct agrees with [:punct:] with explicit Latin1'; + } + + + { + local $BugId = '60034'; + my $a = "xyzt" x 8192; + ok $a =~ /\A(?>[a-z])*\z/, + '(?>) does not cause wrongness on long string'; + my $b = $a . chr 256; + chop $b; + { + iseq $a, $b; } + ok $b =~ /\A(?>[a-z])*\z/, + '(?>) does not cause wrongness on long string with UTF-8'; } -} -{ - local $Message = "Check that \\xDF match properly in its various forms"; - # test that \xDF matches properly. this is pretty hacky stuff, - # but its actually needed. the malarky with '-' is to prevent - # compilation caching from playing any role in the test. - my @df= (chr(0xDF),'-',chr(0xDF)); - utf8::upgrade($df[2]); - my @strs= ('ss','sS','Ss','SS',chr(0xDF)); - my @ss= map { ("$_", "$_") } @strs; - utf8::upgrade($ss[$_*2+1]) for 0..$#strs; - - for my $ssi (0..$#ss) { - for my $dfi (0..$#df) { - my $pat= $df[$dfi]; - my $str= $ss[$ssi]; - my $utf_df= ($dfi > 1) ? 'utf8' : ''; - my $utf_ss= ($ssi % 2) ? 'utf8' : ''; - (my $sstr=$str)=~s/\xDF/\\xDF/; - - if ($utf_df || $utf_ss || length($ss[$ssi])==1) { - my $ret= $str=~/$pat/i; - next if $pat eq '-'; - ok($ret, - "\"$sstr\"=~/\\xDF/i (str is @{[$utf_ss||'latin']}, pat is @{[$utf_df||'latin']})"); - } else { - my $ret= $str !~ /$pat/i; - next if $pat eq '-'; - ok($ret, - "\"$sstr\"!~/\\xDF/i (str is @{[$utf_ss||'latin']}, pat is @{[$utf_df||'latin']})"); - } + + + # + # Keep the following tests last -- they may crash perl + # + print "# Tests that follow may crash perl\n"; + { + local $BugId = '19049/38869'; + local $Message = 'Pattern in a loop, failure should not ' . + 'affect previous success'; + my @list = ( + 'ab cdef', # Matches regex + ('e' x 40000 ) .'ab c' # Matches not, but 'ab c' matches part of it + ); + my $y; + my $x; + foreach (@list) { + m/ab(.+)cd/i; # The ignore-case seems to be important + $y = $1; # Use $1, which might not be from the last match! + $x = substr ($list [0], $- [0], $+ [0] - $- [0]); } + iseq $y, ' '; + iseq $x, 'ab cd'; } -} -{ - local $Message = "BBC(Bleadperl Breaks CPAN) Today: String::Multibyte"; - my $re = qr/(?:[\x00-\xFF]{4})/; - my $hyp = "\0\0\0-"; - my $esc = "\0\0\0\\"; - my $str = "$esc$hyp$hyp$esc$esc"; - my @a = ($str =~ /\G(?:\Q$esc$esc\E|\Q$esc$hyp\E|$re)/g); - iseq(0+@a,3); - iseq(join('=', @a),"$esc$hyp=$hyp=$esc$esc"); -} -# test for keys in %+ and %- -{ - my $_ = "abcdef"; - /(?<foo>a)|(?<foo>b)/; - iseq( (join ",", sort keys %+), "foo" ); - iseq( (join ",", sort keys %-), "foo" ); - iseq( (join ",", sort values %+), "a" ); - iseq( (join ",", sort map "@$_", values %-), "a " ); - /(?<bar>a)(?<bar>b)(?<quux>.)/; - iseq( (join ",", sort keys %+), "bar,quux" ); - iseq( (join ",", sort keys %-), "bar,quux" ); - iseq( (join ",", sort values %+), "a,c" ); # leftmost - iseq( (join ",", sort map "@$_", values %-), "a b,c" ); - /(?<un>a)(?<deux>c)?/; # second buffer won't capture - iseq( (join ",", sort keys %+), "un" ); - iseq( (join ",", sort keys %-), "deux,un" ); - iseq( (join ",", sort values %+), "a" ); - iseq( (join ",", sort map "@$_", values %-), ",a" ); -} + { + local $BugId = '24274'; -# length() on captures, the numbered ones end up in Perl_magic_len -{ - my $_ = "aoeu \xe6var ook"; - /^ \w+ \s (?<eek>\S+)/x; + ok (("a" x (2 ** 15 - 10)) =~ /^()(a|bb)*$/, "Recursive stack cracker"); + ok ((q(a)x 100) =~ /^(??{'(.)'x 100})/, + "Regexp /^(??{'(.)'x 100})/ crashes older perls"); + } - iseq( length($`), 0, 'length $`' ); - iseq( length($'), 4, q[length $'] ); - iseq( length($&), 9, 'length $&' ); - iseq( length($1), 4, 'length $1' ); - iseq( length($+{eek}), 4, 'length $+{eek} == length $1' ); -} -{ - my $ok=-1; - - $ok=exists($-{x}) ? 1 : 0 - if 'bar'=~/(?<x>foo)|bar/; - iseq($ok,1,'$-{x} exists after "bar"=~/(?<x>foo)|bar/'); - iseq(scalar(%+), 0, 'scalar %+ == 0 after "bar"=~/(?<x>foo)|bar/'); - iseq(scalar(%-), 1, 'scalar %- == 1 after "bar"=~/(?<x>foo)|bar/'); - - $ok=-1; - $ok=exists($+{x}) ? 1 : 0 - if 'bar'=~/(?<x>foo)|bar/; - iseq($ok,0,'$+{x} not exists after "bar"=~/(?<x>foo)|bar/'); - iseq(scalar(%+), 0, 'scalar %+ == 0 after "bar"=~/(?<x>foo)|bar/'); - iseq(scalar(%-), 1, 'scalar %- == 1 after "bar"=~/(?<x>foo)|bar/'); - - $ok=-1; - $ok=exists($-{x}) ? 1 : 0 - if 'foo'=~/(?<x>foo)|bar/; - iseq($ok,1,'$-{x} exists after "foo"=~/(?<x>foo)|bar/'); - iseq(scalar(%+), 1, 'scalar %+ == 1 after "foo"=~/(?<x>foo)|bar/'); - iseq(scalar(%-), 1, 'scalar %- == 1 after "foo"=~/(?<x>foo)|bar/'); - - $ok=-1; - $ok=exists($+{x}) ? 1 : 0 - if 'foo'=~/(?<x>foo)|bar/; - iseq($ok,1,'$+{x} exists after "foo"=~/(?<x>foo)|bar/'); -} -{ - local $_; - ($_ = 'abc')=~/(abc)/g; - $_ = '123'; - iseq("$1",'abc',"/g leads to unsafe match vars: $1"); -} -{ - local $Message="Message-ID: <20070818091501.7eff4831@r2d2>"; - my $str= ""; - for(0..5){ - my @x; - $str .= "@x"; # this should ALWAYS be the empty string - 'a'=~/(a|)/; - push @x,1; - } - iseq(length($str),"0","Trie scope error, string should be empty"); - $str=""; - my @foo = ('a')x5; - for (@foo) { - my @bar; - $str .= "@bar"; - s/a|/push @bar, 1/e; - } - iseq(length($str),"0","Trie scope error, string should be empty"); -} -{ -# [perl #45605] Regexp failure with utf8-flagged and byte-flagged string + { + eval '/\k/'; + ok $@ =~ /\QSequence \k... not terminated in regex;\E/, + 'Lone \k not allowed'; + } - my $utf_8 = "\xd6schel"; - utf8::upgrade($utf_8); - $utf_8 =~ m{(\xd6|Ö)schel}; - iseq($1,"\xd6","#45605"); -} -{ - # Regardless of utf8ness any character matches itself when - # doing a case insensitive match. See also [perl #36207] - for my $o (0..255) { - my @ch=(chr($o),chr($o)); - utf8::upgrade($ch[1]); - for my $u_str (0,1) { - for my $u_pat (0,1) { - ok( $ch[$u_str]=~/\Q$ch[$u_pat]\E/i, - "\$c=~/\$c/i : chr($o) : u_str=$u_str u_pat=$u_pat"); - ok( $ch[$u_str]=~/\Q$ch[$u_pat]\E|xyz/i, - "# \$c=~/\$c|xyz/i : chr($o) : u_str=$u_str u_pat=$u_pat"); + { + local $Message = "Substitution with lookahead (possible segv)"; + $_ = "ns1ns1ns1"; + s/ns(?=\d)/ns_/g; + iseq $_, "ns_1ns_1ns_1"; + $_ = "ns1"; + s/ns(?=\d)/ns_/; + iseq $_, "ns_1"; + $_ = "123"; + s/(?=\d+)|(?<=\d)/!Bang!/g; + iseq $_, "!Bang!1!Bang!2!Bang!3!Bang!"; + } + + + { + # [perl #45337] utf8 + "[a]a{2}" + /$.../ = panic: sv_len_utf8 cache + local $BugId = '45337'; + local ${^UTF8CACHE} = -1; + local $Message = "Shouldn't panic"; + my $s = "[a]a{2}"; + utf8::upgrade $s; + ok "aaa" =~ /$s/; + } + { + local $BugId = '57042'; + local $Message = "Check if tree logic breaks \$^R"; + my $cond_re = qr/\s* + \s* (?: + \( \s* A (?{1}) + | \( \s* B (?{2}) + ) + /x; + my @res; + for my $line ("(A)","(B)") { + if ($line =~ m/$cond_re/) { + push @res, $^R ? "#$^R" : "UNDEF"; + } + } + iseq "@res","#1 #2"; + } + { + no warnings 'closure'; + my $re = qr/A(??{"1"})/; + ok "A1B" =~ m/^((??{ $re }))((??{"B"}))$/; + ok $1 eq "A1"; + ok $2 eq "B"; + } + + + { + use re 'eval'; + local $Message = 'Test if $^N and $+ work in (?{{})'; + our @ctl_n = (); + our @plus = (); + our $nested_tags; + $nested_tags = qr{ + < + ((\w)+) + (?{ + push @ctl_n, (defined $^N ? $^N : "undef"); + push @plus, (defined $+ ? $+ : "undef"); + }) + > + (??{$nested_tags})* + </\s* \w+ \s*> + }x; + + + my $c = 0; + for my $test ( + # Test structure: + # [ Expected result, Regex, Expected value(s) of $^N, Expected value(s) of $+ ] + [ 1, qr#^$nested_tags$#, "bla blubb bla", "a b a" ], + [ 1, qr#^($nested_tags)$#, "bla blubb <bla><blubb></blubb></bla>", "a b a" ], + [ 1, qr#^(|)$nested_tags$#, "bla blubb bla", "a b a" ], + [ 1, qr#^(?:|)$nested_tags$#, "bla blubb bla", "a b a" ], + [ 1, qr#^<(bl|bla)>$nested_tags<(/\1)>$#, "blubb /bla", "b /bla" ], + [ 1, qr#(??{"(|)"})$nested_tags$#, "bla blubb bla", "a b a" ], + [ 1, qr#^(??{"(bla|)"})$nested_tags$#, "bla blubb bla", "a b a" ], + [ 1, qr#^(??{"(|)"})(??{$nested_tags})$#, "bla blubb undef", "a b undef" ], + [ 1, qr#^(??{"(?:|)"})$nested_tags$#, "bla blubb bla", "a b a" ], + [ 1, qr#^((??{"(?:bla|)"}))((??{$nested_tags}))$#, "bla blubb <bla><blubb></blubb></bla>", "a b <bla><blubb></blubb></bla>" ], + [ 1, qr#^((??{"(?!)?"}))((??{$nested_tags}))$#, "bla blubb <bla><blubb></blubb></bla>", "a b <bla><blubb></blubb></bla>" ], + [ 1, qr#^((??{"(?:|<(/?bla)>)"}))((??{$nested_tags}))\1$#, "bla blubb <bla><blubb></blubb></bla>", "a b <bla><blubb></blubb></bla>" ], + [ 0, qr#^((??{"(?!)"}))?((??{$nested_tags}))(?!)$#, "bla blubb undef", "a b undef" ], + + ) { #"#silence vim highlighting + $c++; + @ctl_n = (); + @plus = (); + my $match = (("<bla><blubb></blubb></bla>" =~ $test->[1]) ? 1 : 0); + push @ctl_n, (defined $^N ? $^N : "undef"); + push @plus, (defined $+ ? $+ : "undef"); + ok($test->[0] == $match, "match $c"); + if ($test->[0] != $match) { + # unset @ctl_n and @plus + @ctl_n = @plus = (); } + iseq("@ctl_n", $test->[2], "ctl_n $c"); + iseq("@plus", $test->[3], "plus $c"); } } -} -# Test counter is at bottom of file. Put new tests above here. -#------------------------------------------------------------------- -# Keep the following tests last -- they may crash perl -{ - # RT#19049 / RT#38869 - my @list = ( - 'ab cdef', # matches regex - ( 'e' x 40000 ) .'ab c' # matches not, but 'ab c' matches part of it - ); - my $y; - my $x; - foreach (@list) { - m/ab(.+)cd/i; # the ignore-case seems to be important - $y = $1; # use $1, which might not be from the last match! - $x = substr($list[0],$-[0],$+[0]-$-[0]); - } - iseq($y,' ', - 'pattern in a loop, failure should not affect previous success'); - iseq($x,'ab cd', - 'pattern in a loop, failure should not affect previous success'); -} + { + use re 'eval'; + local $BugId = '56194'; + + our $f; + local $f; + $f = sub { + defined $_[0] ? $_[0] : "undef"; + }; + + ok("123" =~ m/^(\d)(((??{1 + $^N})))+$/); + + our @ctl_n; + our @plus; + + my $re = qr#(1)((??{ push @ctl_n, $f->($^N); push @plus, $f->($+); $^N + 1}))*(?{$^N})#; + my $re2 = qr#(1)((??{ push @ctl_n, $f->($^N); push @plus, $f->($+); $^N + 1}))*(?{$^N})(|a(b)c|def)(??{"$^R"})#; + my $re3 = qr#(1)((??{ push @ctl_n, $f->($^N); push @plus, $f->($+); $^N + 1})){2}(?{$^N})(|a(b)c|def)(??{"$^R"})#; + our $re5; + local $re5 = qr#(1)((??{ push @ctl_n, $f->($^N); push @plus, $f->($+); $^N + 1})){2}(?{$^N})#; + my $re6 = qr#(??{ push @ctl_n, $f->($^N); push @plus, $f->($+); $^N + 1})#; + my $re7 = qr#(??{ push @ctl_n, $f->($^N); push @plus, $f->($+); $^N + 1})#; + my $re8 = qr/(\d+)/; + my $c = 0; + for my $test ( + # Test structure: + # [ + # String to match + # Regex too match + # Expected values of $^N + # Expected values of $+ + # Expected values of $1, $2, $3, $4 and $5 + # ] + [ + "1233", + qr#^(1)((??{ push @ctl_n, $f->($^N); push @plus, $f->($+); $^N + 1}))+(??{$^N})$#, + "1 2 3 3", + "1 2 3 3", + "\$1 = 1, \$2 = 3, \$3 = undef, \$4 = undef, \$5 = undef", + ], + [ + "1233", + qr#^(1)((??{ push @ctl_n, $f->($^N); push @plus, $f->($+); $^N + 1}))+(abc|def|)?(??{$+})$#, + "1 2 3 3", + "1 2 3 3", + "\$1 = 1, \$2 = 3, \$3 = undef, \$4 = undef, \$5 = undef", + ], + [ + "1233", + qr#^(1)((??{ push @ctl_n, $f->($^N); push @plus, $f->($+); $^N + 1}))+(|abc|def)?(??{$+})$#, + "1 2 3 3", + "1 2 3 3", + "\$1 = 1, \$2 = 3, \$3 = undef, \$4 = undef, \$5 = undef", + ], + [ + "1233", + qr#^(1)((??{ push @ctl_n, $f->($^N); push @plus, $f->($+); $^N + 1}))+(abc|def|)?(??{$^N})$#, + "1 2 3 3", + "1 2 3 3", + "\$1 = 1, \$2 = 3, \$3 = undef, \$4 = undef, \$5 = undef", + ], + [ + "1233", + qr#^(1)((??{ push @ctl_n, $f->($^N); push @plus, $f->($+); $^N + 1}))+(|abc|def)?(??{$^N})$#, + "1 2 3 3", + "1 2 3 3", + "\$1 = 1, \$2 = 3, \$3 = undef, \$4 = undef, \$5 = undef", + ], + [ + "123abc3", + qr#^($re)(|a(b)c|def)(??{$^R})$#, + "1 2 3 abc", + "1 2 3 b", + "\$1 = 123, \$2 = 1, \$3 = 3, \$4 = abc, \$5 = b", + ], + [ + "123abc3", + qr#^($re2)$#, + "1 2 3 123abc3", + "1 2 3 b", + "\$1 = 123abc3, \$2 = 1, \$3 = 3, \$4 = abc, \$5 = b", + ], + [ + "123abc3", + qr#^($re3)$#, + "1 2 123abc3", + "1 2 b", + "\$1 = 123abc3, \$2 = 1, \$3 = 3, \$4 = abc, \$5 = b", + ], + [ + "123abc3", + qr#^(??{$re5})(|abc|def)(??{"$^R"})$#, + "1 2 abc", + "1 2 abc", + "\$1 = abc, \$2 = undef, \$3 = undef, \$4 = undef, \$5 = undef", + ], + [ + "123abc3", + qr#^(??{$re5})(|a(b)c|def)(??{"$^R"})$#, + "1 2 abc", + "1 2 b", + "\$1 = abc, \$2 = b, \$3 = undef, \$4 = undef, \$5 = undef", + ], + [ + "1234", + qr#^((\d+)((??{push @ctl_n, $f->($^N); push @plus, $f->($+);$^N + 1}))((??{push @ctl_n, $f->($^N); push @plus, $f->($+);$^N + 1}))((??{push @ctl_n, $f->($^N); push @plus, $f->($+);$^N + 1})))$#, + "1234 123 12 1 2 3 1234", + "1234 123 12 1 2 3 4", + "\$1 = 1234, \$2 = 1, \$3 = 2, \$4 = 3, \$5 = 4", + ], + [ + "1234556", + qr#^(\d+)($re6)($re6)($re6)$re6(($re6)$re6)$#, + "1234556 123455 12345 1234 123 12 1 2 3 4 4 5 56", + "1234556 123455 12345 1234 123 12 1 2 3 4 4 5 5", + "\$1 = 1, \$2 = 2, \$3 = 3, \$4 = 4, \$5 = 56", + ], + [ + "12345562", + qr#^((??{$re8}))($re7)($re7)($re7)$re7($re7)($re7(\2))$#, + "12345562 1234556 123455 12345 1234 123 12 1 2 3 4 4 5 62", + "12345562 1234556 123455 12345 1234 123 12 1 2 3 4 4 5 2", + "\$1 = 1, \$2 = 2, \$3 = 3, \$4 = 4, \$5 = 5", + ], + ) { + $c++; + @ctl_n = (); + @plus = (); + undef $^R; + my $match = $test->[0] =~ $test->[1]; + my $str = join(", ", '$1 = '.$f->($1), '$2 = '.$f->($2), '$3 = '.$f->($3), '$4 = '.$f->($4),'$5 = '.$f->($5)); + push @ctl_n, $f->($^N); + push @plus, $f->($+); + ok($match, "match $c"); + if (not $match) { + # unset $str, @ctl_n and @plus + $str = ""; + @ctl_n = @plus = (); + } + iseq("@ctl_n", $test->[2], "ctl_n $c"); + iseq("@plus", $test->[3], "plus $c"); + iseq($str, $test->[4], "str $c"); + } + SKIP: { + if ($] le '5.010') { + skip "test segfaults on perl < 5.10", 4; + } -ok(("a" x (2**15 - 10)) =~ /^()(a|bb)*$/, "Recursive stack cracker: #24274") - or print "# Unexpected outcome: should pass or crash perl\n"; - -ok((q(a)x 100) =~ /^(??{'(.)'x 100})/, - "Regexp /^(??{'(.)'x 100})/ crashes older perls") - or print "# Unexpected outcome: should pass or crash perl\n"; - -eval '/\k/'; -ok($@=~/\QSequence \k... not terminated in regex;\E/); - -{ - local $Message = "substitution with lookahead (possible segv)"; - $_="ns1ns1ns1"; - s/ns(?=\d)/ns_/g; - iseq($_,"ns_1ns_1ns_1"); - $_="ns1"; - s/ns(?=\d)/ns_/; - iseq($_,"ns_1"); - $_="123"; - s/(?=\d+)|(?<=\d)/!Bang!/g; - iseq($_,"!Bang!1!Bang!2!Bang!3!Bang!"); -} + @ctl_n = (); + @plus = (); + + our $re4; + local $re4 = qr#(1)((??{push @ctl_n, $f->($^N); push @plus, $f->($+);$^N + 1})){2}(?{$^N})(|abc|def)(??{"$^R"})#; + undef $^R; + my $match = "123abc3" =~ m/^(??{$re4})$/; + my $str = join(", ", '$1 = '.$f->($1), '$2 = '.$f->($2), '$3 = '.$f->($3), '$4 = '.$f->($4),'$5 = '.$f->($5),'$^R = '.$f->($^R)); + push @ctl_n, $f->($^N); + push @plus, $f->($+); + ok($match); + if (not $match) { + # unset $str + @ctl_n = (); + @plus = (); + $str = ""; + } + iseq("@ctl_n", "1 2 undef"); + iseq("@plus", "1 2 undef"); + iseq($str, "\$1 = undef, \$2 = undef, \$3 = undef, \$4 = undef, \$5 = undef, \$^R = undef"); + } + } -# [perl #45337] utf8 + "[a]a{2}" + /$.../ = panic: sv_len_utf8 cache + { + local $BugId = 65372; # minimal CURLYM limited to 32767 matches + my @pat = ( + qr{a(x|y)*b}, # CURLYM + qr{a(x|y)*?b}, # .. with minmod + qr{a([wx]|[yz])*b}, # .. and without tries + qr{a([wx]|[yz])*?b}, + ); + my $len = 32768; + my $s = join '', 'a', 'x' x $len, 'b'; + for my $pat (@pat) { + ok($s =~ $pat, $pat); + } + } + # + # This should be the last test. + # + iseq $test + 1, $EXPECTED_TESTS, "Got the right number of tests!"; -{ - local ${^UTF8CACHE} = -1; - my $s="[a]a{2}"; - utf8::upgrade $s; - ok("aaa" =~ /$s/, "#45337"); -} +} # End of sub run_tests -# Put new tests above the dotted line about a page above this comment -iseq(0+$::test,$::TestCount,"Got the right number of tests!"); -# Don't forget to update this! -BEGIN { - $::TestCount = 4013; - print "1..$::TestCount\n"; -} +1; diff --git a/gnu/usr.bin/perl/t/op/range.t b/gnu/usr.bin/perl/t/op/range.t index 3cef292446d..214c16835f5 100644 --- a/gnu/usr.bin/perl/t/op/range.t +++ b/gnu/usr.bin/perl/t/op/range.t @@ -9,7 +9,7 @@ require 'test.pl'; use Config; -plan (45); +plan (135); is(join(':',1..5), '1:2:3:4:5'); @@ -188,3 +188,219 @@ is(join(":", map "[$_]", @foo), '[]'); @foo=(); push @foo, $_ for $1..""; is(join(":", map "[$_]", @foo), ''); } + +# Test upper range limit +my $MAX_INT = ~0>>1; + +foreach my $ii (-3 .. 3) { + my ($first, $last); + eval { + my $lim=0; + for ($MAX_INT-10 .. $MAX_INT+$ii) { + if (! defined($first)) { + $first = $_; + } + $last = $_; + last if ($lim++ > 100); # Protect against integer wrap + } + }; + if ($ii <= 0) { + ok(! $@, 'Upper bound accepted: ' . ($MAX_INT+$ii)); + is($first, $MAX_INT-10, 'Lower bound okay'); + is($last, $MAX_INT+$ii, 'Upper bound okay'); + } else { + ok($@, 'Upper bound rejected: ' . ($MAX_INT+$ii)); + } +} + +foreach my $ii (-3 .. 3) { + my ($first, $last); + eval { + my $lim=0; + for ($MAX_INT+$ii .. $MAX_INT) { + if (! defined($first)) { + $first = $_; + } + $last = $_; + last if ($lim++ > 100); + } + }; + if ($ii <= 0) { + ok(! $@, 'Lower bound accepted: ' . ($MAX_INT+$ii)); + is($first, $MAX_INT+$ii, 'Lower bound okay'); + is($last, $MAX_INT, 'Upper bound okay'); + } else { + ok($@, 'Lower bound rejected: ' . ($MAX_INT+$ii)); + } +} + +{ + my $first; + eval { + my $lim=0; + for ($MAX_INT .. $MAX_INT-1) { + if (! defined($first)) { + $first = $_; + } + $last = $_; + last if ($lim++ > 100); + } + }; + ok(! $@, 'Range accepted'); + ok(! defined($first), 'Range ineffectual'); +} + +foreach my $ii (~0, ~0+1, ~0+(~0>>4)) { + eval { + my $lim=0; + for ($MAX_INT-10 .. $ii) { + last if ($lim++ > 100); + } + }; + ok($@, 'Upper bound rejected: ' . $ii); +} + +# Test lower range limit +my $MIN_INT = -1-$MAX_INT; + +if (! $Config{d_nv_preserves_uv}) { + # $MIN_INT needs adjustment when IV won't fit into an NV + my $NV = $MIN_INT - 1; + my $OFFSET = 1; + while (($NV + $OFFSET) == $MIN_INT) { + $OFFSET++ + } + $MIN_INT += $OFFSET; +} + +foreach my $ii (-3 .. 3) { + my ($first, $last); + eval { + my $lim=0; + for ($MIN_INT+$ii .. $MIN_INT+10) { + if (! defined($first)) { + $first = $_; + } + $last = $_; + last if ($lim++ > 100); + } + }; + if ($ii >= 0) { + ok(! $@, 'Lower bound accepted: ' . ($MIN_INT+$ii)); + is($first, $MIN_INT+$ii, 'Lower bound okay'); + is($last, $MIN_INT+10, 'Upper bound okay'); + } else { + ok($@, 'Lower bound rejected: ' . ($MIN_INT+$ii)); + } +} + +foreach my $ii (-3 .. 3) { + my ($first, $last); + eval { + my $lim=0; + for ($MIN_INT .. $MIN_INT+$ii) { + if (! defined($first)) { + $first = $_; + } + $last = $_; + last if ($lim++ > 100); + } + }; + if ($ii >= 0) { + ok(! $@, 'Upper bound accepted: ' . ($MIN_INT+$ii)); + is($first, $MIN_INT, 'Lower bound okay'); + is($last, $MIN_INT+$ii, 'Upper bound okay'); + } else { + ok($@, 'Upper bound rejected: ' . ($MIN_INT+$ii)); + } +} + +{ + my $first; + eval { + my $lim=0; + for ($MIN_INT+1 .. $MIN_INT) { + if (! defined($first)) { + $first = $_; + } + $last = $_; + last if ($lim++ > 100); + } + }; + ok(! $@, 'Range accepted'); + ok(! defined($first), 'Range ineffectual'); +} + +foreach my $ii (~0, ~0+1, ~0+(~0>>4)) { + eval { + my $lim=0; + for (-$ii .. $MIN_INT+10) { + last if ($lim++ > 100); + } + }; + ok($@, 'Lower bound rejected: ' . -$ii); +} + +# double/tripple magic tests +sub TIESCALAR { bless { value => $_[1], orig => $_[1] } } +sub STORE { $_[0]{store}++; $_[0]{value} = $_[1] } +sub FETCH { $_[0]{fetch}++; $_[0]{value} } +sub stores { tied($_[0])->{value} = tied($_[0])->{orig}; + delete(tied($_[0])->{store}) || 0 } +sub fetches { delete(tied($_[0])->{fetch}) || 0 } + +tie $x, "main", 6; + +my @foo; +@foo = 4 .. $x; +is(scalar @foo, 3); +is("@foo", "4 5 6"); +{ + local $TODO = "test for double magic with range operator"; + is(fetches($x), 1); +} +is(stores($x), 0); + +@foo = $x .. 8; +is(scalar @foo, 3); +is("@foo", "6 7 8"); +{ + local $TODO = "test for double magic with range operator"; + is(fetches($x), 1); +} +is(stores($x), 0); + +@foo = $x .. $x + 1; +is(scalar @foo, 2); +is("@foo", "6 7"); +{ + local $TODO = "test for double magic with range operator"; + is(fetches($x), 2); +} +is(stores($x), 0); + +@foo = (); +for (4 .. $x) { + push @foo, $_; +} +is(scalar @foo, 3); +is("@foo", "4 5 6"); +{ + local $TODO = "test for double magic with range operator"; + is(fetches($x), 1); +} +is(stores($x), 0); + +@foo = (); +for (reverse 4 .. $x) { + push @foo, $_; +} +is(scalar @foo, 3); +is("@foo", "6 5 4"); +{ + local $TODO = "test for double magic with range operator"; + is(fetches($x), 1); +} +is(stores($x), 0); + +# EOF diff --git a/gnu/usr.bin/perl/t/op/re_tests b/gnu/usr.bin/perl/t/op/re_tests index 87a3e50285c..4b0e1209689 100644 --- a/gnu/usr.bin/perl/t/op/re_tests +++ b/gnu/usr.bin/perl/t/op/re_tests @@ -1,3 +1,6 @@ +# This stops me getting screenfulls of syntax errors every time I accidentally +# run this file via a shell glob +__END__ abc abc y $& abc abc abc y $-[0] 0 abc abc y $+[0] 3 @@ -411,6 +414,7 @@ a[-]?c ac y $& ac '(abc)\1'i ABCABC y $1 ABC '([a-c]*)\1'i ABCABC y $1 ABC a(?!b). abad y $& ad +(?=)a a y $& a a(?=d). abad y $& ad a(?=c|d). abad y $& ad a(?:b|c|d)(.) ace y $1 e @@ -614,6 +618,7 @@ $(?<=^(a)) a y $1 a ((?>[^()]+)|\([^()]*\))+ ((abc(ade)ufh()()x y $& abc(ade)ufh()()x (?<=x+)y - c - Variable length lookbehind not implemented a{37,17} - c - Can't do {n,m} with n > m +a{37,0} - c - Can't do {n,m} with n > m \Z a\nb\n y $-[0] 3 \z a\nb\n y $-[0] 4 $ a\nb\n y $-[0] 3 @@ -1281,6 +1286,7 @@ a*(*F) aaaab n - - X(\w+)(?=\s)|X(\w+) Xab y [$1-$2] [-ab] #check that branch reset works ok. +(?|(a)) a y $1-$+-$^N a-a-a (?|a(.)b|d(.(o).)d|i(.)(.)j)(.) d!o!da y $1-$2-$3 !o!-o-a (?|a(.)b|d(.(o).)d|i(.)(.)j)(.) aabc y $1-$2-$3 a--c (?|a(.)b|d(.(o).)d|i(.)(.)j)(.) ixyjp y $1-$2-$3 x-y-p @@ -1289,6 +1295,11 @@ X(\w+)(?=\s)|X(\w+) Xab y [$1-$2] [-ab] (?|(?|(a)|(b))|(?|(c)|(d))) c y $1 c (?|(?|(a)|(b))|(?|(c)|(d))) d y $1 d (.)(?|(.)(.)x|(.)d)(.) abcde y $1-$2-$3-$4-$5- b-c--e-- +(?|(?<foo>x)) x y $+{foo} x +(?|(?<foo>x)|(?<bar>y)) x y $+{foo} x +(?|(?<bar>y)|(?<foo>x)) x y $+{foo} x +(?<bar>)(?|(?<foo>x)) x y $+{foo} x + #Bug #41492 (?(DEFINE)(?<A>(?&B)+)(?<B>a))(?&A) a y $& a (?(DEFINE)(?<A>(?&B)+)(?<B>a))(?&A) aa y $& aa @@ -1338,3 +1349,27 @@ foo(\h)bar foo\tbar y $1 \t .*\z foo\n y - - ^(?:(\d)x)?\d$ 1 y ${\(defined($1)?1:0)} 0 .*?(?:(\w)|(\w))x abx y $1-$2 b- + +0{50} 000000000000000000000000000000000000000000000000000 y - - +^a?(?=b)b ab y $& ab # Bug #56690 +^a*(?=b)b ab y $& ab # Bug #56690 +/>\d+$ \n/ix >10\n y $& >10 +/>\d+$ \n/ix >1\n y $& >1 +/\d+$ \n/ix >10\n y $& 10 +/>\d\d$ \n/ix >10\n y $& >10 +/>\d+$ \n/x >10\n y $& >10 + +# Two regressions in 5.8.x (only) introduced by change 30638 +# Simplification of the test failure in XML::LibXML::Simple: +/^\s*i.*?o\s*$/s io\n io y - - +# As reported in #59168 by Father Chrysostomos: +/(.*?)a(?!(a+)b\2c)/ baaabaac y $&-$1 baa-ba +# [perl #60344] Regex lookbehind failure after an (if)then|else in perl 5.10 +/\A(?(?=db2)db2|\D+)(?<!processed)\.csv\z/xms sql_processed.csv n - - +/\N{U+0100}/ \x{100} y $& \x{100} # Bug #59328 +[\s][\S] \x{a0}\x{a0} nT - - # TODO Unicode complements should not match same character + +# was generating malformed utf8 +'[\x{100}\xff]'i \x{ff} y $& \x{ff} + +((??{ "(?:|)" }))\s C\x20 y - - diff --git a/gnu/usr.bin/perl/t/op/read.t b/gnu/usr.bin/perl/t/op/read.t index 8235bc20724..23f1b51a2c6 100644 --- a/gnu/usr.bin/perl/t/op/read.t +++ b/gnu/usr.bin/perl/t/op/read.t @@ -31,9 +31,7 @@ my $has_perlio = !eval { !$Config::Config{useperlio} }; -my $tmpfile = 'Op_read.tmp'; - -END { 1 while unlink $tmpfile } +my $tmpfile = tempfile(); my (@values, @buffers) = ('', ''); @@ -56,7 +54,6 @@ foreach my $value (@values) { skip "Needs :utf8 layer but no perlio", 2 * @offsets * @lengths if $utf8 and !$has_perlio; - 1 while unlink $tmpfile; open FH, ">$tmpfile" or die "Can't open $tmpfile: $!"; binmode FH, "utf8" if $utf8; print FH $value; diff --git a/gnu/usr.bin/perl/t/op/readdir.t b/gnu/usr.bin/perl/t/op/readdir.t index 971a02ada7d..53c7b68c27d 100644 --- a/gnu/usr.bin/perl/t/op/readdir.t +++ b/gnu/usr.bin/perl/t/op/readdir.t @@ -20,11 +20,12 @@ if (opendir(OP, "op")) { print "ok 1\n"; } else { print "not ok 1\n"; } @D = grep(/^[^\.].*\.t$/i, readdir(OP)); closedir(OP); -## -## This range will have to adjust as the number of tests expands, -## as it's counting the number of .t files in src/t -## -my ($min, $max) = (150, 170); +open $man, "<../MANIFEST" or die "Can't open ../MANIFEST: $!"; +my $expect; +while (<$man>) { + ++$expect if m!^t/op/[^/]+\t!; +} +my ($min, $max) = ($expect - 10, $expect + 10); if (@D > $min && @D < $max) { print "ok 2\n"; } else { printf "not ok 2 # counting op/*.t, expect $min < %d < $max files\n", diff --git a/gnu/usr.bin/perl/t/op/ref.t b/gnu/usr.bin/perl/t/op/ref.t index 3fdc8333888..a98da6e5a29 100644 --- a/gnu/usr.bin/perl/t/op/ref.t +++ b/gnu/usr.bin/perl/t/op/ref.t @@ -8,7 +8,7 @@ BEGIN { require 'test.pl'; use strict qw(refs subs); -plan(138); +plan(189); # Test glob operations. @@ -54,11 +54,6 @@ $BAR = \$BAZ; $BAZ = "hit"; is ($$$FOO, 'hit'); -# test that ref(vstring) makes sense -my $vstref = \v1; -is (ref($vstref), "VSTRING", "ref(vstr) eq VSTRING"); -like ( $vstref, qr/VSTRING\(0x[0-9a-f]+\)/, '\vstr is also VSTRING'); - # Test references to real arrays. my $test = curr_test(); @@ -131,9 +126,49 @@ sub mysub2 { lc shift } # Test the ref operator. -is (ref $subref, 'CODE'); -is (ref $ref, 'ARRAY'); -is (ref $refref, 'HASH'); +sub PVBM () { 'foo' } +{ my $dummy = index 'foo', PVBM } + +my $pviv = 1; "$pviv"; +my $pvnv = 1.0; "$pvnv"; +my $x; + +# we don't test +# tied lvalue => SCALAR, as we haven't tested tie yet +# BIND, 'cos we can't create them yet +# REGEXP, 'cos that requires overload or Scalar::Util +# LVALUE ref, 'cos I can't work out how to create one :) + +for ( + [ 'undef', SCALAR => \undef ], + [ 'constant IV', SCALAR => \1 ], + [ 'constant NV', SCALAR => \1.0 ], + [ 'constant PV', SCALAR => \'f' ], + [ 'scalar', SCALAR => \$x ], + [ 'PVIV', SCALAR => \$pviv ], + [ 'PVNV', SCALAR => \$pvnv ], + [ 'PVMG', SCALAR => \$0 ], + [ 'PVBM', SCALAR => \PVBM ], + [ 'vstring', VSTRING => \v1 ], + [ 'ref', REF => \\1 ], + [ 'lvalue', LVALUE => \substr($x, 0, 0) ], + [ 'named array', ARRAY => \@ary ], + [ 'anon array', ARRAY => [ 1 ] ], + [ 'named hash', HASH => \%whatever ], + [ 'anon hash', HASH => { a => 1 } ], + [ 'named sub', CODE => \&mysub, ], + [ 'anon sub', CODE => sub { 1; } ], + [ 'glob', GLOB => \*foo ], + [ 'format', FORMAT => *STDERR{FORMAT} ], +) { + my ($desc, $type, $ref) = @$_; + is (ref $ref, $type, "ref() for ref to $desc"); + like ("$ref", qr/^$type\(0x[0-9a-f]+\)$/, "stringify for ref to $desc"); +} + +is (ref *STDOUT{IO}, 'IO::Handle', 'IO refs are blessed into IO::Handle'); +like (*STDOUT{IO}, qr/^IO::Handle=IO\(0x[0-9a-f]+\)$/, + 'stringify for IO refs'); # Test anonymous hash syntax. @@ -536,6 +571,32 @@ is ( (sub {"bar"})[0]->(), "bar", 'code deref from list slice w/ ->' ); is($ref, *{$ref}{IO}, "IO slot of the temporary glob is set correctly"); } +# these will segfault if they fail + +my $pvbm = PVBM; +my $rpvbm = \$pvbm; + +ok (!eval { *$rpvbm }, 'PVBM ref is not a GLOB ref'); +ok (!eval { *$pvbm }, 'PVBM is not a GLOB ref'); +ok (!eval { $$pvbm }, 'PVBM is not a SCALAR ref'); +ok (!eval { @$pvbm }, 'PVBM is not an ARRAY ref'); +ok (!eval { %$pvbm }, 'PVBM is not a HASH ref'); +ok (!eval { $pvbm->() }, 'PVBM is not a CODE ref'); +ok (!eval { $rpvbm->foo }, 'PVBM is not an object'); + +# bug 24254 +is( runperl(stderr => 1, prog => 'map eval qq(exit),1 for 1'), ""); +is( runperl(stderr => 1, prog => 'eval { for (1) { map { die } 2 } };'), ""); +is( runperl(stderr => 1, prog => 'for (125) { map { exit } (213)}'), ""); +my $hushed = $^O eq 'VMS' ? 'use vmsish qw(hushed);' : ''; +is( runperl(stderr => 1, prog => $hushed . 'map die,4 for 3'), "Died at -e line 1.\n"); +is( runperl(stderr => 1, prog => $hushed . 'grep die,4 for 3'), "Died at -e line 1.\n"); +is( runperl(stderr => 1, prog => $hushed . 'for $a (3) {@b=sort {die} 4,5}'), "Died at -e line 1.\n"); + +# bug 57564 +is( runperl(stderr => 1, prog => 'my $i;for $i (1) { for $i (2) { } }'), ""); + + # Bit of a hack to make test.pl happy. There are 3 more tests after it leaves. $test = curr_test(); curr_test($test + 3); diff --git a/gnu/usr.bin/perl/t/op/regexp.t b/gnu/usr.bin/perl/t/op/regexp.t index 7ad7d89bc92..ba5da62b656 100644 --- a/gnu/usr.bin/perl/t/op/regexp.t +++ b/gnu/usr.bin/perl/t/op/regexp.t @@ -13,8 +13,10 @@ # y expect a match # n expect no match # c expect an error +# T the test is a TODO (can be combined with y/n/c) # B test exposes a known bug in Perl, should be skipped # b test exposes a known bug in Perl, should be skipped if noamp +# t test exposes a bug with threading, TODO if qr_embed_thr # # Columns 4 and 5 are used only if column 3 contains C<y> or C<c>. # @@ -49,12 +51,25 @@ BEGIN { chdir 't' if -d 't'; @INC = '../lib'; + + if ($qr_embed_thr) { + require Config; + if (!$Config::Config{useithreads}) { + print "1..0 # Skip: no ithreads\n"; + exit 0; + } + if ($ENV{PERL_CORE_MINITEST}) { + print "1..0 # Skip: no dynamic loading on miniperl, no threads\n"; + exit 0; + } + require threads; + } } use strict; use warnings FATAL=>"all"; use vars qw($iters $numtests $bang $ffff $nulnul $OP); -use vars qw($qr $skip_amp $qr_embed); # set by our callers +use vars qw($qr $skip_amp $qr_embed $qr_embed_thr); # set by our callers if (!defined $file) { @@ -73,13 +88,14 @@ $OP = $qr ? 'qr' : 'm'; $| = 1; printf "1..%d\n# $iters iterations\n", scalar @tests; + my $test; TEST: foreach (@tests) { $test++; - if (!/\S/ || /^\s*#/) { + if (!/\S/ || /^\s*#/ || /^__END__$/) { print "ok $test # (Blank line or comment)\n"; - if (/\S/) { print $_ }; + if (/#/) { print $_ }; next; } chomp; @@ -87,15 +103,19 @@ foreach (@tests) { my ($pat, $subject, $result, $repl, $expect, $reason) = split(/\t/,$_,6); $reason = '' unless defined $reason; my $input = join(':',$pat,$subject,$result,$repl,$expect); - $pat = "'$pat'" unless $pat =~ /^[:'\/]/; + # the double '' below keeps simple syntax highlighters from going crazy + $pat = "'$pat'" unless $pat =~ /^[:''\/]/; $pat =~ s/(\$\{\w+\})/$1/eeg; $pat =~ s/\\n/\n/g; $subject = eval qq("$subject"); die $@ if $@; $expect = eval qq("$expect"); die $@ if $@; $expect = $repl = '-' if $skip_amp and $input =~ /\$[&\`\']/; + my $todo_qr = $qr_embed_thr && ($result =~ s/t//); my $skip = ($skip_amp ? ($result =~ s/B//i) : ($result =~ s/B//)); $reason = 'skipping $&' if $reason eq '' && $skip_amp; $result =~ s/B//i unless $skip; + my $todo= $result =~ s/T// ? " # TODO" : ""; + for my $study ('', 'study $subject', 'utf8::upgrade($subject)', 'utf8::upgrade($subject); study $subject') { @@ -120,6 +140,16 @@ EOFCODE \$got = "$repl"; EOFCODE } + elsif ($qr_embed_thr) { + $code= <<EOFCODE; + # Can't run the match in a subthread, but can do this and + # clone the pattern the other way. + my \$RE = threads->new(sub {qr$pat})->join(); + $study; + \$match = (\$subject =~ /(?:)\$RE(?:)/) while \$c--; + \$got = "$repl"; +EOFCODE + } else { $code= <<EOFCODE; $study; @@ -139,35 +169,39 @@ EOFCODE } chomp( my $err = $@ ); if ($result eq 'c') { - if ($err !~ m!^\Q$expect!) { print "not ok $test (compile) $input => `$err'\n"; next TEST } + if ($err !~ m!^\Q$expect!) { print "not ok $test$todo (compile) $input => `$err'\n"; next TEST } last; # no need to study a syntax error } elsif ( $skip ) { print "ok $test # skipped", length($reason) ? " $reason" : '', "\n"; next TEST; } + elsif ( $todo_qr ) { + print "not ok $test # TODO", length($reason) ? " - $reason" : '', "\n"; + next TEST; + } elsif ($@) { - print "not ok $test $input => error `$err'\n$code\n$@\n"; next TEST; + print "not ok $test$todo $input => error `$err'\n$code\n$@\n"; next TEST; } - elsif ($result eq 'n') { - if ($match) { print "not ok $test ($study) $input => false positive\n"; next TEST } + elsif ($result =~ /^n/) { + if ($match) { print "not ok $test$todo ($study) $input => false positive\n"; next TEST } } else { if (!$match || $got ne $expect) { eval { require Data::Dumper }; if ($@) { - print "not ok $test ($study) $input => `$got', match=$match\n$code\n"; + print "not ok $test$todo ($study) $input => `$got', match=$match\n$code\n"; } else { # better diagnostics my $s = Data::Dumper->new([$subject],['subject'])->Useqq(1)->Dump; my $g = Data::Dumper->new([$got],['got'])->Useqq(1)->Dump; - print "not ok $test ($study) $input => `$got', match=$match\n$s\n$g\n$code\n"; + print "not ok $test$todo ($study) $input => `$got', match=$match\n$s\n$g\n$code\n"; } next TEST; } } } - print "ok $test\n"; + print "ok $test$todo\n"; } 1; diff --git a/gnu/usr.bin/perl/t/op/runlevel.t b/gnu/usr.bin/perl/t/op/runlevel.t index 36c63effac8..44aedc0c081 100644 --- a/gnu/usr.bin/perl/t/op/runlevel.t +++ b/gnu/usr.bin/perl/t/op/runlevel.t @@ -8,6 +8,7 @@ chdir 't' if -d 't'; @INC = '../lib'; +require './test.pl'; $Is_VMS = $^O eq 'VMS'; $Is_MSWin32 = $^O eq 'MSWin32'; $Is_NetWare = $^O eq 'NetWare'; @@ -20,9 +21,7 @@ undef $/; @prgs = split "\n########\n", <DATA>; print "1..", scalar @prgs, "\n"; -$tmpfile = "runltmp000"; -1 while -f ++$tmpfile; -END { if ($tmpfile) { 1 while unlink $tmpfile; } } +$tmpfile = tempfile(); for (@prgs){ my $switch = ""; @@ -45,7 +44,7 @@ for (@prgs){ my $status = $?; $results =~ s/\n+$//; # allow expected output to be written as if $prog is on STDIN - $results =~ s/runltmp\d+/-/g; + $results =~ s/$::tempfile_regexp/-/ig; $results =~ s/\n%[A-Z]+-[SIWEF]-.*$// if $Is_VMS; # clip off DCL status msg $expected =~ s/\n+$//; if ($results ne $expected) { diff --git a/gnu/usr.bin/perl/t/op/sort.t b/gnu/usr.bin/perl/t/op/sort.t index 737727ef747..616761a05d4 100644 --- a/gnu/usr.bin/perl/t/op/sort.t +++ b/gnu/usr.bin/perl/t/op/sort.t @@ -2,10 +2,11 @@ BEGIN { chdir 't' if -d 't'; - @INC = qw(. ../lib); require 'test.pl'; + @INC = qw(. ../lib); + require 'test.pl'; } use warnings; -plan( tests => 143 ); +plan( tests => 144 ); # these shouldn't hang { @@ -260,48 +261,43 @@ $x = join('', sort { $a <=> $b } 3, 1, 2); cmp_ok($x,'eq','123',q(optimized-away comparison block doesn't take any other arguments away with it)); # test sorting in non-main package -package Foo; -@a = ( 5, 19, 1996, 255, 90 ); -@b = sort { $b <=> $a } @a; -main::cmp_ok("@b",'eq','1996 255 90 19 5','not in main:: 1'); - - -@b = sort main::Backwards_stacked @a; -main::cmp_ok("@b",'eq','90 5 255 1996 19','not in main:: 2'); - - -# check if context for sort arguments is handled right - - -sub test_if_list { - my $gimme = wantarray; - main::is($gimme,1,'wantarray 1'); - - -} -my $m = sub { $a <=> $b }; - -sub cxt_one { sort $m test_if_list() } -cxt_one(); -sub cxt_two { sort { $a <=> $b } test_if_list() } -cxt_two(); -sub cxt_three { sort &test_if_list() } -cxt_three(); +{ + package Foo; + @a = ( 5, 19, 1996, 255, 90 ); + @b = sort { $b <=> $a } @a; + ::cmp_ok("@b",'eq','1996 255 90 19 5','not in main:: 1'); -sub test_if_scalar { - my $gimme = wantarray; - main::is(!($gimme or !defined($gimme)),1,'wantarray 2'); + @b = sort ::Backwards_stacked @a; + ::cmp_ok("@b",'eq','90 5 255 1996 19','not in main:: 2'); + # check if context for sort arguments is handled right + sub test_if_list { + my $gimme = wantarray; + ::is($gimme,1,'wantarray 1'); + } + my $m = sub { $a <=> $b }; + + sub cxt_one { sort $m test_if_list() } + cxt_one(); + sub cxt_two { sort { $a <=> $b } test_if_list() } + cxt_two(); + sub cxt_three { sort &test_if_list() } + cxt_three(); + + sub test_if_scalar { + my $gimme = wantarray; + ::is(!($gimme or !defined($gimme)),1,'wantarray 2'); + } + $m = \&test_if_scalar; + sub cxt_four { sort $m 1,2 } + @x = cxt_four(); + sub cxt_five { sort { test_if_scalar($a,$b); } 1,2 } + @x = cxt_five(); + sub cxt_six { sort test_if_scalar 1,2 } + @x = cxt_six(); } -$m = \&test_if_scalar; -sub cxt_four { sort $m 1,2 } -@x = cxt_four(); -sub cxt_five { sort { test_if_scalar($a,$b); } 1,2 } -@x = cxt_five(); -sub cxt_six { sort test_if_scalar 1,2 } -@x = cxt_six(); # test against a reentrancy bug { @@ -316,84 +312,81 @@ sub cxt_six { sort test_if_scalar 1,2 } Bar::reenter() unless $init++; $a <=> $b } qw/4 3 1 2/; - main::cmp_ok("@b",'eq','1 2 3 4','reenter 1'); + cmp_ok("@b",'eq','1 2 3 4','reenter 1'); - main::ok(!$def,'reenter 2'); + ok(!$def,'reenter 2'); } { sub routine { "one", "two" }; @a = sort(routine(1)); - main::cmp_ok("@a",'eq',"one two",'bug id 19991001.003'); + cmp_ok("@a",'eq',"one two",'bug id 19991001.003'); } -#my $test = 59; -sub ok { main::cmp_ok($_[0],'eq',$_[1],$_[2]); -# print "not " unless $_[0] eq $_[1]; -# print "ok $test - $_[2]\n"; -# print "#[$_[0]] ne [$_[1]]\n" unless $_[0] eq $_[1]; -# $test++; -} - # check for in-place optimisation of @a = sort @a { my ($r1,$r2,@a); our @g; @g = (3,2,1); $r1 = \$g[2]; @g = sort @g; $r2 = \$g[0]; - ok "$r1-@g", "$r2-1 2 3", "inplace sort of global"; + is "$r1-@g", "$r2-1 2 3", "inplace sort of global"; @a = qw(b a c); $r1 = \$a[1]; @a = sort @a; $r2 = \$a[0]; - ok "$r1-@a", "$r2-a b c", "inplace sort of lexical"; + is "$r1-@a", "$r2-a b c", "inplace sort of lexical"; @g = (2,3,1); $r1 = \$g[1]; @g = sort { $b <=> $a } @g; $r2 = \$g[0]; - ok "$r1-@g", "$r2-3 2 1", "inplace reversed sort of global"; + is "$r1-@g", "$r2-3 2 1", "inplace reversed sort of global"; @g = (2,3,1); $r1 = \$g[1]; @g = sort { $a<$b?1:$a>$b?-1:0 } @g; $r2 = \$g[0]; - ok "$r1-@g", "$r2-3 2 1", "inplace custom sort of global"; + is "$r1-@g", "$r2-3 2 1", "inplace custom sort of global"; sub mysort { $b cmp $a }; @a = qw(b c a); $r1 = \$a[1]; @a = sort mysort @a; $r2 = \$a[0]; - ok "$r1-@a", "$r2-c b a", "inplace sort with function of lexical"; + is "$r1-@a", "$r2-c b a", "inplace sort with function of lexical"; use Tie::Array; my @t; tie @t, 'Tie::StdArray'; @t = qw(b c a); @t = sort @t; - ok "@t", "a b c", "inplace sort of tied array"; + is "@t", "a b c", "inplace sort of tied array"; @t = qw(b c a); @t = sort mysort @t; - ok "@t", "c b a", "inplace sort of tied array with function"; + is "@t", "c b a", "inplace sort of tied array with function"; # [perl #29790] don't optimise @a = ('a', sort @a) ! @g = (3,2,1); @g = ('0', sort @g); - ok "@g", "0 1 2 3", "un-inplace sort of global"; + is "@g", "0 1 2 3", "un-inplace sort of global"; @g = (3,2,1); @g = (sort(@g),'4'); - ok "@g", "1 2 3 4", "un-inplace sort of global 2"; + is "@g", "1 2 3 4", "un-inplace sort of global 2"; @a = qw(b a c); @a = ('x', sort @a); - ok "@a", "x a b c", "un-inplace sort of lexical"; + is "@a", "x a b c", "un-inplace sort of lexical"; @a = qw(b a c); @a = ((sort @a), 'x'); - ok "@a", "a b c x", "un-inplace sort of lexical 2"; + is "@a", "a b c x", "un-inplace sort of lexical 2"; @g = (2,3,1); @g = ('0', sort { $b <=> $a } @g); - ok "@g", "0 3 2 1", "un-inplace reversed sort of global"; + is "@g", "0 3 2 1", "un-inplace reversed sort of global"; @g = (2,3,1); @g = ((sort { $b <=> $a } @g),'4'); - ok "@g", "3 2 1 4", "un-inplace reversed sort of global 2"; + is "@g", "3 2 1 4", "un-inplace reversed sort of global 2"; @g = (2,3,1); @g = ('0', sort { $a<$b?1:$a>$b?-1:0 } @g); - ok "@g", "0 3 2 1", "un-inplace custom sort of global"; + is "@g", "0 3 2 1", "un-inplace custom sort of global"; @g = (2,3,1); @g = ((sort { $a<$b?1:$a>$b?-1:0 } @g),'4'); - ok "@g", "3 2 1 4", "un-inplace custom sort of global 2"; + is "@g", "3 2 1 4", "un-inplace custom sort of global 2"; @a = qw(b c a); @a = ('x', sort mysort @a); - ok "@a", "x c b a", "un-inplace sort with function of lexical"; + is "@a", "x c b a", "un-inplace sort with function of lexical"; @a = qw(b c a); @a = ((sort mysort @a),'x'); - ok "@a", "c b a x", "un-inplace sort with function of lexical 2"; + is "@a", "c b a x", "un-inplace sort with function of lexical 2"; + + # RT#54758. Git 62b40d2474e7487e6909e1872b6bccdf812c6818 + no warnings 'void'; + my @m; push @m, 0 for 1 .. 1024; $#m; @m = sort @m; + ::pass("in-place sorting segfault"); } # Test optimisations of reversed sorts. As we now guarantee stability by @@ -419,77 +412,77 @@ sub generate { my @input = &generate; my @output = sort @input; -ok join(" ", map {0+$_} @output), "0 1 2 3 4 5 6 7 8", "Simple stable sort"; +is join(" ", map {0+$_} @output), "0 1 2 3 4 5 6 7 8", "Simple stable sort"; @input = &generate; @input = sort @input; -ok join(" ", map {0+$_} @input), "0 1 2 3 4 5 6 7 8", +is join(" ", map {0+$_} @input), "0 1 2 3 4 5 6 7 8", "Simple stable in place sort"; # This won't be very interesting @input = &generate; @output = sort {$a <=> $b} @input; -ok "@output", "A A A B B B C C C", 'stable $a <=> $b sort'; +is "@output", "A A A B B B C C C", 'stable $a <=> $b sort'; @input = &generate; @output = sort {$a cmp $b} @input; -ok join(" ", map {0+$_} @output), "0 1 2 3 4 5 6 7 8", 'stable $a cmp $b sort'; +is join(" ", map {0+$_} @output), "0 1 2 3 4 5 6 7 8", 'stable $a cmp $b sort'; @input = &generate; @input = sort {$a cmp $b} @input; -ok join(" ", map {0+$_} @input), "0 1 2 3 4 5 6 7 8", +is join(" ", map {0+$_} @input), "0 1 2 3 4 5 6 7 8", 'stable $a cmp $b in place sort'; @input = &generate; @output = sort {$b cmp $a} @input; -ok join(" ", map {0+$_} @output), "6 7 8 3 4 5 0 1 2", 'stable $b cmp $a sort'; +is join(" ", map {0+$_} @output), "6 7 8 3 4 5 0 1 2", 'stable $b cmp $a sort'; @input = &generate; @input = sort {$b cmp $a} @input; -ok join(" ", map {0+$_} @input), "6 7 8 3 4 5 0 1 2", +is join(" ", map {0+$_} @input), "6 7 8 3 4 5 0 1 2", 'stable $b cmp $a in place sort'; @input = &generate; @output = reverse sort @input; -ok join(" ", map {0+$_} @output), "8 7 6 5 4 3 2 1 0", "Reversed stable sort"; +is join(" ", map {0+$_} @output), "8 7 6 5 4 3 2 1 0", "Reversed stable sort"; @input = &generate; @input = reverse sort @input; -ok join(" ", map {0+$_} @input), "8 7 6 5 4 3 2 1 0", +is join(" ", map {0+$_} @input), "8 7 6 5 4 3 2 1 0", "Reversed stable in place sort"; @input = &generate; my $output = reverse sort @input; -ok $output, "CCCBBBAAA", "Reversed stable sort in scalar context"; +is $output, "CCCBBBAAA", "Reversed stable sort in scalar context"; @input = &generate; @output = reverse sort {$a cmp $b} @input; -ok join(" ", map {0+$_} @output), "8 7 6 5 4 3 2 1 0", +is join(" ", map {0+$_} @output), "8 7 6 5 4 3 2 1 0", 'reversed stable $a cmp $b sort'; @input = &generate; @input = reverse sort {$a cmp $b} @input; -ok join(" ", map {0+$_} @input), "8 7 6 5 4 3 2 1 0", +is join(" ", map {0+$_} @input), "8 7 6 5 4 3 2 1 0", 'revesed stable $a cmp $b in place sort'; @input = &generate; $output = reverse sort {$a cmp $b} @input; -ok $output, "CCCBBBAAA", 'Reversed stable $a cmp $b sort in scalar context'; +is $output, "CCCBBBAAA", 'Reversed stable $a cmp $b sort in scalar context'; @input = &generate; @output = reverse sort {$b cmp $a} @input; -ok join(" ", map {0+$_} @output), "2 1 0 5 4 3 8 7 6", +is join(" ", map {0+$_} @output), "2 1 0 5 4 3 8 7 6", 'reversed stable $b cmp $a sort'; @input = &generate; @input = reverse sort {$b cmp $a} @input; -ok join(" ", map {0+$_} @input), "2 1 0 5 4 3 8 7 6", +is join(" ", map {0+$_} @input), "2 1 0 5 4 3 8 7 6", 'revesed stable $b cmp $a in place sort'; @input = &generate; $output = reverse sort {$b cmp $a} @input; -ok $output, "AAABBBCCC", 'Reversed stable $b cmp $a sort in scalar context'; +is $output, "AAABBBCCC", 'Reversed stable $b cmp $a sort in scalar context'; sub stuff { # Something complex enough to defeat any constant folding optimiser @@ -498,27 +491,27 @@ sub stuff { @input = &generate; @output = reverse sort {stuff || $a cmp $b} @input; -ok join(" ", map {0+$_} @output), "8 7 6 5 4 3 2 1 0", +is join(" ", map {0+$_} @output), "8 7 6 5 4 3 2 1 0", 'reversed stable complex sort'; @input = &generate; @input = reverse sort {stuff || $a cmp $b} @input; -ok join(" ", map {0+$_} @input), "8 7 6 5 4 3 2 1 0", +is join(" ", map {0+$_} @input), "8 7 6 5 4 3 2 1 0", 'revesed stable complex in place sort'; @input = &generate; $output = reverse sort {stuff || $a cmp $b } @input; -ok $output, "CCCBBBAAA", 'Reversed stable complex sort in scalar context'; +is $output, "CCCBBBAAA", 'Reversed stable complex sort in scalar context'; sub sortr { reverse sort @_; } @output = sortr &generate; -ok join(" ", map {0+$_} @output), "8 7 6 5 4 3 2 1 0", +is join(" ", map {0+$_} @output), "8 7 6 5 4 3 2 1 0", 'reversed stable sort return list context'; $output = sortr &generate; -ok $output, "CCCBBBAAA", +is $output, "CCCBBBAAA", 'reversed stable sort return scalar context'; sub sortcmpr { @@ -526,10 +519,10 @@ sub sortcmpr { } @output = sortcmpr &generate; -ok join(" ", map {0+$_} @output), "8 7 6 5 4 3 2 1 0", +is join(" ", map {0+$_} @output), "8 7 6 5 4 3 2 1 0", 'reversed stable $a cmp $b sort return list context'; $output = sortcmpr &generate; -ok $output, "CCCBBBAAA", +is $output, "CCCBBBAAA", 'reversed stable $a cmp $b sort return scalar context'; sub sortcmprba { @@ -537,10 +530,10 @@ sub sortcmprba { } @output = sortcmprba &generate; -ok join(" ", map {0+$_} @output), "2 1 0 5 4 3 8 7 6", +is join(" ", map {0+$_} @output), "2 1 0 5 4 3 8 7 6", 'reversed stable $b cmp $a sort return list context'; $output = sortcmprba &generate; -ok $output, "AAABBBCCC", +is $output, "AAABBBCCC", 'reversed stable $b cmp $a sort return scalar context'; sub sortcmprq { @@ -548,10 +541,10 @@ sub sortcmprq { } @output = sortcmpr &generate; -ok join(" ", map {0+$_} @output), "8 7 6 5 4 3 2 1 0", +is join(" ", map {0+$_} @output), "8 7 6 5 4 3 2 1 0", 'reversed stable complex sort return list context'; $output = sortcmpr &generate; -ok $output, "CCCBBBAAA", +is $output, "CCCBBBAAA", 'reversed stable complex sort return scalar context'; # And now with numbers @@ -564,148 +557,148 @@ sub generate1 { # This won't be very interesting @input = &generate1; @output = sort {$a cmp $b} @input; -ok "@output", "A B C D E F G H I", 'stable $a cmp $b sort'; +is "@output", "A B C D E F G H I", 'stable $a cmp $b sort'; @input = &generate1; @output = sort {$a <=> $b} @input; -ok "@output", "A B C D E F G H I", 'stable $a <=> $b sort'; +is "@output", "A B C D E F G H I", 'stable $a <=> $b sort'; @input = &generate1; @input = sort {$a <=> $b} @input; -ok "@input", "A B C D E F G H I", 'stable $a <=> $b in place sort'; +is "@input", "A B C D E F G H I", 'stable $a <=> $b in place sort'; @input = &generate1; @output = sort {$b <=> $a} @input; -ok "@output", "G H I D E F A B C", 'stable $b <=> $a sort'; +is "@output", "G H I D E F A B C", 'stable $b <=> $a sort'; @input = &generate1; @input = sort {$b <=> $a} @input; -ok "@input", "G H I D E F A B C", 'stable $b <=> $a in place sort'; +is "@input", "G H I D E F A B C", 'stable $b <=> $a in place sort'; # test that optimized {$b cmp $a} and {$b <=> $a} remain stable # (new in 5.9) without overloading { no warnings; @b = sort { $b <=> $a } @input = qw/5first 6first 5second 6second/; -ok "@b" , "6first 6second 5first 5second", "optimized {$b <=> $a} without overloading" ; +is "@b" , "6first 6second 5first 5second", "optimized {$b <=> $a} without overloading" ; @input = sort {$b <=> $a} @input; -ok "@input" , "6first 6second 5first 5second","inline optimized {$b <=> $a} without overloading" ; +is "@input" , "6first 6second 5first 5second","inline optimized {$b <=> $a} without overloading" ; }; # These two are actually doing string cmp on 0 1 and 2 @input = &generate1; @output = reverse sort @input; -ok "@output", "I H G F E D C B A", "Reversed stable sort"; +is "@output", "I H G F E D C B A", "Reversed stable sort"; @input = &generate1; @input = reverse sort @input; -ok "@input", "I H G F E D C B A", "Reversed stable in place sort"; +is "@input", "I H G F E D C B A", "Reversed stable in place sort"; @input = &generate1; $output = reverse sort @input; -ok $output, "IHGFEDCBA", "Reversed stable sort in scalar context"; +is $output, "IHGFEDCBA", "Reversed stable sort in scalar context"; @input = &generate1; @output = reverse sort {$a <=> $b} @input; -ok "@output", "I H G F E D C B A", 'reversed stable $a <=> $b sort'; +is "@output", "I H G F E D C B A", 'reversed stable $a <=> $b sort'; @input = &generate1; @input = reverse sort {$a <=> $b} @input; -ok "@input", "I H G F E D C B A", 'revesed stable $a <=> $b in place sort'; +is "@input", "I H G F E D C B A", 'revesed stable $a <=> $b in place sort'; @input = &generate1; $output = reverse sort {$a <=> $b} @input; -ok $output, "IHGFEDCBA", 'reversed stable $a <=> $b sort in scalar context'; +is $output, "IHGFEDCBA", 'reversed stable $a <=> $b sort in scalar context'; @input = &generate1; @output = reverse sort {$b <=> $a} @input; -ok "@output", "C B A F E D I H G", 'reversed stable $b <=> $a sort'; +is "@output", "C B A F E D I H G", 'reversed stable $b <=> $a sort'; @input = &generate1; @input = reverse sort {$b <=> $a} @input; -ok "@input", "C B A F E D I H G", 'revesed stable $b <=> $a in place sort'; +is "@input", "C B A F E D I H G", 'revesed stable $b <=> $a in place sort'; @input = &generate1; $output = reverse sort {$b <=> $a} @input; -ok $output, "CBAFEDIHG", 'reversed stable $b <=> $a sort in scalar context'; +is $output, "CBAFEDIHG", 'reversed stable $b <=> $a sort in scalar context'; @input = &generate1; @output = reverse sort {stuff || $a <=> $b} @input; -ok "@output", "I H G F E D C B A", 'reversed stable complex sort'; +is "@output", "I H G F E D C B A", 'reversed stable complex sort'; @input = &generate1; @input = reverse sort {stuff || $a <=> $b} @input; -ok "@input", "I H G F E D C B A", 'revesed stable complex in place sort'; +is "@input", "I H G F E D C B A", 'revesed stable complex in place sort'; @input = &generate1; $output = reverse sort {stuff || $a <=> $b} @input; -ok $output, "IHGFEDCBA", 'reversed stable complex sort in scalar context'; +is $output, "IHGFEDCBA", 'reversed stable complex sort in scalar context'; sub sortnumr { reverse sort {$a <=> $b} @_; } @output = sortnumr &generate1; -ok "@output", "I H G F E D C B A", +is "@output", "I H G F E D C B A", 'reversed stable $a <=> $b sort return list context'; $output = sortnumr &generate1; -ok $output, "IHGFEDCBA", 'reversed stable $a <=> $b sort return scalar context'; +is $output, "IHGFEDCBA", 'reversed stable $a <=> $b sort return scalar context'; sub sortnumrba { reverse sort {$b <=> $a} @_; } @output = sortnumrba &generate1; -ok "@output", "C B A F E D I H G", +is "@output", "C B A F E D I H G", 'reversed stable $b <=> $a sort return list context'; $output = sortnumrba &generate1; -ok $output, "CBAFEDIHG", 'reversed stable $b <=> $a sort return scalar context'; +is $output, "CBAFEDIHG", 'reversed stable $b <=> $a sort return scalar context'; sub sortnumrq { reverse sort {stuff || $a <=> $b} @_; } @output = sortnumrq &generate1; -ok "@output", "I H G F E D C B A", +is "@output", "I H G F E D C B A", 'reversed stable complex sort return list context'; $output = sortnumrq &generate1; -ok $output, "IHGFEDCBA", 'reversed stable complex sort return scalar context'; +is $output, "IHGFEDCBA", 'reversed stable complex sort return scalar context'; @output = reverse (sort(qw(C A B)), 0); -ok "@output", "0 C B A", 'reversed sort with trailing argument'; +is "@output", "0 C B A", 'reversed sort with trailing argument'; @output = reverse (0, sort(qw(C A B))); -ok "@output", "C B A 0", 'reversed sort with leading argument'; +is "@output", "C B A 0", 'reversed sort with leading argument'; eval { @output = sort {goto sub {}} 1,2; }; $fail_msg = q(Can't goto subroutine outside a subroutine); -main::cmp_ok(substr($@,0,length($fail_msg)),'eq',$fail_msg,'goto subr outside subr'); +cmp_ok(substr($@,0,length($fail_msg)),'eq',$fail_msg,'goto subr outside subr'); sub goto_sub {goto sub{}} eval { @output = sort goto_sub 1,2; }; $fail_msg = q(Can't goto subroutine from a sort sub); -main::cmp_ok(substr($@,0,length($fail_msg)),'eq',$fail_msg,'goto subr from a sort sub'); +cmp_ok(substr($@,0,length($fail_msg)),'eq',$fail_msg,'goto subr from a sort sub'); eval { @output = sort {goto label} 1,2; }; $fail_msg = q(Can't "goto" out of a pseudo block); -main::cmp_ok(substr($@,0,length($fail_msg)),'eq',$fail_msg,'goto out of a pseudo block 1'); +cmp_ok(substr($@,0,length($fail_msg)),'eq',$fail_msg,'goto out of a pseudo block 1'); sub goto_label {goto label} label: eval { @output = sort goto_label 1,2; }; $fail_msg = q(Can't "goto" out of a pseudo block); -main::cmp_ok(substr($@,0,length($fail_msg)),'eq',$fail_msg,'goto out of a pseudo block 2'); +cmp_ok(substr($@,0,length($fail_msg)),'eq',$fail_msg,'goto out of a pseudo block 2'); sub self_immolate {undef &self_immolate; $a<=>$b} eval { @output = sort self_immolate 1,2,3 }; $fail_msg = q(Can't undef active subroutine); -main::cmp_ok(substr($@,0,length($fail_msg)),'eq',$fail_msg,'undef active subr'); +cmp_ok(substr($@,0,length($fail_msg)),'eq',$fail_msg,'undef active subr'); @@ -724,13 +717,12 @@ main::cmp_ok(substr($@,0,length($fail_msg)),'eq',$fail_msg,'undef active subr'); } rec(1); - main::ok(!$failed, "sort from active sub"); + ok(!$failed, "sort from active sub"); } # $a and $b are set in the package the sort() is called from, # *not* the package the sort sub is in. This is longstanding # de facto behaviour that shouldn't be broken. -package main; my $answer = "good"; () = sort OtherPack::foo 1,2,3,4; @@ -744,62 +736,68 @@ my $answer = "good"; } } -main::cmp_ok($answer,'eq','good','sort subr called from other package'); +cmp_ok($answer,'eq','good','sort subr called from other package'); # Bug 36430 - sort called in package2 while a # sort in package1 is active should set $package2::a/b. - -$answer = "good"; -my @list = sort { A::min(@$a) <=> A::min(@$b) } - [3, 1, 5], [2, 4], [0]; - -main::cmp_ok($answer,'eq','good','bug 36430'); - -package A; -sub min { - my @list = sort { - $answer = '$a and/or $b are not defined ' if !defined($a) || !defined($b); - $a <=> $b; - } @_; - $list[0]; +{ + my $answer = "good"; + my @list = sort { A::min(@$a) <=> A::min(@$b) } + [3, 1, 5], [2, 4], [0]; + + cmp_ok($answer,'eq','good','bug 36430'); + + package A; + sub min { + my @list = sort { + $answer = '$a and/or $b are not defined ' if !defined($a) || !defined($b); + $a <=> $b; + } @_; + $list[0]; + } } + # Bug 7567 - an array shouldn't be modifiable while it's being # sorted in-place. -eval { @a=(1..8); @a = sort { @a = (0) } @a; }; - -$fail_msg = q(Modification of a read-only value attempted); -main::cmp_ok(substr($@,0,length($fail_msg)),'eq',$fail_msg,'bug 7567'); +{ + eval { @a=(1..8); @a = sort { @a = (0) } @a; }; + $fail_msg = q(Modification of a read-only value attempted); + cmp_ok(substr($@,0,length($fail_msg)),'eq',$fail_msg,'bug 7567'); +} # Sorting shouldn't increase the refcount of a sub -sub foo {(1+$a) <=> (1+$b)} -my $refcnt = &Internals::SvREFCNT(\&foo); -@output = sort foo 3,7,9; -package Foo; -ok($refcnt, &Internals::SvREFCNT(\&foo), "sort sub refcnt"); -$fail_msg = q(Modification of a read-only value attempted); -# Sorting a read-only array in-place shouldn't be allowed -my @readonly = (1..10); -Internals::SvREADONLY(@readonly, 1); -eval { @readonly = sort @readonly; }; -main::cmp_ok(substr($@,0,length($fail_msg)),'eq',$fail_msg,'in-place sort of read-only array'); - - +{ + sub foo {(1+$a) <=> (1+$b)} + my $refcnt = &Internals::SvREFCNT(\&foo); + @output = sort foo 3,7,9; + + { + package Foo; + ::is($refcnt, &Internals::SvREFCNT(\&foo), "sort sub refcnt"); + $fail_msg = q(Modification of a read-only value attempted); + # Sorting a read-only array in-place shouldn't be allowed + my @readonly = (1..10); + Internals::SvREADONLY(@readonly, 1); + eval { @readonly = sort @readonly; }; + ::cmp_ok(substr($@,0,length($fail_msg)),'eq',$fail_msg,'in-place sort of read-only array'); + } +} # Using return() should be okay even in a deeper context @b = sort {while (1) {return ($a <=> $b)} } 1..10; -ok("@b", "1 2 3 4 5 6 7 8 9 10", "return within loop"); +is("@b", "1 2 3 4 5 6 7 8 9 10", "return within loop"); # Using return() should be okay even if there are other items # on the stack at the time. @b = sort {$_ = ($a<=>$b) + do{return $b<=> $a}} 1..10; -ok("@b", "10 9 8 7 6 5 4 3 2 1", "return with SVs on stack"); +is("@b", "10 9 8 7 6 5 4 3 2 1", "return with SVs on stack"); # As above, but with a sort sub rather than a sort block. sub ret_with_stacked { $_ = ($a<=>$b) + do {return $b <=> $a} } @b = sort ret_with_stacked 1..10; -ok("@b", "10 9 8 7 6 5 4 3 2 1", "return with SVs on stack"); +is("@b", "10 9 8 7 6 5 4 3 2 1", "return with SVs on stack"); diff --git a/gnu/usr.bin/perl/t/op/split.t b/gnu/usr.bin/perl/t/op/split.t index 025327f3853..b3a97415691 100644 --- a/gnu/usr.bin/perl/t/op/split.t +++ b/gnu/usr.bin/perl/t/op/split.t @@ -6,7 +6,7 @@ BEGIN { require './test.pl'; } -plan tests => 135; +plan tests => 136; $FS = ':'; @@ -358,3 +358,9 @@ ok(@ary == 3 && is($s[2]," XYZ"); is(join(':',@s), join(':',@r)); } + +{ + use constant BANG => {}; + () = split m/,/, "", BANG; + ok(1); +} diff --git a/gnu/usr.bin/perl/t/op/sprintf.t b/gnu/usr.bin/perl/t/op/sprintf.t index c2209467454..ba77e64cf84 100644 --- a/gnu/usr.bin/perl/t/op/sprintf.t +++ b/gnu/usr.bin/perl/t/op/sprintf.t @@ -49,8 +49,8 @@ while (<DATA>) { } $evalData = eval $data; - $data = ref $evalData ? $evalData : [$evalData]; - push @tests, [$template, $data, $result, $comment]; + $evalData = ref $evalData ? $evalData : [$evalData]; + push @tests, [$template, $evalData, $result, $comment, $data]; } print '1..', scalar @tests, "\n"; @@ -66,9 +66,9 @@ $SIG{__WARN__} = sub { }; for ($i = 1; @tests; $i++) { - ($template, $data, $result, $comment) = @{shift @tests}; + ($template, $evalData, $result, $comment, $data) = @{shift @tests}; $w = undef; - $x = sprintf(">$template<", @$data); + $x = sprintf(">$template<", @$evalData); substr($x, -1, 0) = $w if $w; # $x may have 3 exponent digits, not 2 my $y = $x; diff --git a/gnu/usr.bin/perl/t/op/sprintf2.t b/gnu/usr.bin/perl/t/op/sprintf2.t index c92ab897023..1327cdd67ca 100755 --- a/gnu/usr.bin/perl/t/op/sprintf2.t +++ b/gnu/usr.bin/perl/t/op/sprintf2.t @@ -6,7 +6,7 @@ BEGIN { require './test.pl'; } -plan tests => 1292; +plan tests => 1368; is( sprintf("%.40g ",0.01), @@ -134,3 +134,28 @@ for my $num (0, -1, 1) { } } +# test that %f doesn't panic with +Inf, -Inf, NaN [perl #45383] +foreach my $n (2**1e100, -2**1e100, 2**1e100/2**1e100) { # +Inf, -Inf, NaN + eval { my $f = sprintf("%f", $n); }; + is $@, "", "sprintf(\"%f\", $n)"; +} + +SKIP: { + skip "placeholder for tests not merged from 53f65a9ef4", 24; +} + +# Check unicode vs byte length +for my $width (1,2,3,4,5,6,7) { + for my $precis (1,2,3,4,5,6,7) { + my $v = "\x{20ac}\x{20ac}"; + my $format = "%" . $width . "." . $precis . "s"; + my $chars = ($precis > 2 ? 2 : $precis); + my $space = ($width < 2 ? 0 : $width - $chars); + fresh_perl_is( + 'my $v = "\x{20ac}\x{20ac}"; my $x = sprintf "'.$format.'", $v; $x =~ /^(\s*)(\S*)$/; print "$_" for map {length} $1, $2', + "$space$chars", + {}, + q(sprintf ").$format.q(", "\x{20ac}\x{20ac}"), + ); + } +} diff --git a/gnu/usr.bin/perl/t/op/stat.t b/gnu/usr.bin/perl/t/op/stat.t index dbddaef6546..a225de4f257 100644 --- a/gnu/usr.bin/perl/t/op/stat.t +++ b/gnu/usr.bin/perl/t/op/stat.t @@ -38,8 +38,8 @@ my($DEV, $INO, $MODE, $NLINK, $UID, $GID, $RDEV, $SIZE, my $Curdir = File::Spec->curdir; -my $tmpfile = 'Op_stat.tmp'; -my $tmpfile_link = $tmpfile.'2'; +my $tmpfile = tempfile(); +my $tmpfile_link = tempfile(); chmod 0666, $tmpfile; 1 while unlink $tmpfile; @@ -50,6 +50,10 @@ open(FOO, ">$tmpfile") || DIE("Can't open temp test file: $!"); my($nlink, $mtime, $ctime) = (stat(FOO))[$NLINK, $MTIME, $CTIME]; +# The clock on a network filesystem might be different from the +# system clock. +my $Filesystem_Time_Offset = abs($mtime - time); + #nlink should if link support configured in Perl. SKIP: { skip "No link count - Hard link support not built in.", 1 @@ -453,20 +457,24 @@ SKIP: { unlink $linkname or print "# unlink $linkname failed: $!\n"; } -print "# Zzz...\n"; -sleep(3); -my $f = 'tstamp.tmp'; -unlink $f; -ok (open(S, "> $f"), 'can create tmp file'); -close S or die; -my @a = stat $f; -print "# time=$^T, stat=(@a)\n"; -my @b = (-M _, -A _, -C _); -print "# -MAC=(@b)\n"; -ok( (-M _) < 0, 'negative -M works'); -ok( (-A _) < 0, 'negative -A works'); -ok( (-C _) < 0, 'negative -C works'); -ok(unlink($f), 'unlink tmp file'); +SKIP: { + skip "Too much clock skew between system and filesystem", 5 + if ($Filesystem_Time_Offset > 5); + print "# Zzz...\n"; + sleep($Filesystem_Time_Offset+1); + my $f = 'tstamp.tmp'; + unlink $f; + ok (open(S, "> $f"), 'can create tmp file'); + close S or die; + my @a = stat $f; + print "# time=$^T, stat=(@a)\n"; + my @b = (-M _, -A _, -C _); + print "# -MAC=(@b)\n"; + ok( (-M _) < 0, 'negative -M works'); + ok( (-A _) < 0, 'negative -A works'); + ok( (-C _) < 0, 'negative -C works'); + ok(unlink($f), 'unlink tmp file'); +} { ok(open(F, ">", $tmpfile), 'can create temp file'); diff --git a/gnu/usr.bin/perl/t/op/subst.t b/gnu/usr.bin/perl/t/op/subst.t index 6cf84b73990..06c04e83392 100644 --- a/gnu/usr.bin/perl/t/op/subst.t +++ b/gnu/usr.bin/perl/t/op/subst.t @@ -7,7 +7,7 @@ BEGIN { } require './test.pl'; -plan( tests => 136 ); +plan( tests => 139 ); $x = 'foo'; $_ = "x"; @@ -583,3 +583,11 @@ is($name, "cis", q[#22351 bug with 'e' substitution modifier]); is($want,$_,"RT#17542"); } +{ + my @tests = ('ABC', "\xA3\xA4\xA5", "\x{410}\x{411}\x{412}"); + foreach (@tests) { + my $id = ord $_; + s/./pos/ge; + is($_, "012", "RT#52104: $id"); + } +} diff --git a/gnu/usr.bin/perl/t/op/substr.t b/gnu/usr.bin/perl/t/op/substr.t index 40f87662e33..81c87be87bd 100644 --- a/gnu/usr.bin/perl/t/op/substr.t +++ b/gnu/usr.bin/perl/t/op/substr.t @@ -25,6 +25,12 @@ require './test.pl'; plan(334); +run_tests() unless caller; + +my $krunch = "a"; + +sub run_tests { + $FATAL_MSG = qr/^substr outside of string/; is(substr($a,0,3), 'abc'); # P=Q R S @@ -643,11 +649,10 @@ is($x, "\x{100}\x{200}\xFFb"); # [perl #24200] string corruption with lvalue sub { - my $foo = "a"; - sub bar: lvalue { substr $foo, 0 } + sub bar: lvalue { substr $krunch, 0 } bar = "XXX"; is(bar, 'XXX'); - $foo = '123456789'; + $krunch = '123456789'; is(bar, '123456789'); } @@ -675,3 +680,5 @@ is($x, "\x{100}\x{200}\xFFb"); is(substr($a,1,2), 'bc'); is(substr($a,1,1), 'b'); } + +} diff --git a/gnu/usr.bin/perl/t/op/sysio.t b/gnu/usr.bin/perl/t/op/sysio.t index 435be12efbf..dd63a1588c2 100644 --- a/gnu/usr.bin/perl/t/op/sysio.t +++ b/gnu/usr.bin/perl/t/op/sysio.t @@ -4,6 +4,7 @@ print "1..42\n"; chdir('op') || chdir('t/op') || die "sysio.t: cannot look for myself: $!"; @INC = '../../lib'; +require '../test.pl'; open(I, 'sysio.t') || die "sysio.t: cannot find myself: $!"; @@ -60,7 +61,7 @@ print "ok 9\n"; print 'not ' unless ($a eq "#!.\0\0erl"); print "ok 10\n"; -$outfile = 'sysio.out'; +$outfile = tempfile(); open(O, ">$outfile") || die "sysio.t: cannot write $outfile: $!"; diff --git a/gnu/usr.bin/perl/t/op/taint.t b/gnu/usr.bin/perl/t/op/taint.t index b2688cfe607..0ac02a6306d 100644 --- a/gnu/usr.bin/perl/t/op/taint.t +++ b/gnu/usr.bin/perl/t/op/taint.t @@ -17,7 +17,7 @@ use Config; use File::Spec::Functions; BEGIN { require './test.pl'; } -plan tests => 267; +plan tests => 301; $| = 1; @@ -285,7 +285,7 @@ my $TEST = catfile(curdir(), 'TEST'); # How about command-line arguments? The problem is that we don't # always get some, so we'll run another process with some. SKIP: { - my $arg = catfile(curdir(), "arg$$"); + my $arg = tempfile(); open PROG, "> $arg" or die "Can't create $arg: $!"; print PROG q{ eval { join('', @ARGV), kill 0 }; @@ -418,8 +418,7 @@ SKIP: { test !eval { require $foo }, 'require'; test $@ =~ /^Insecure dependency/, $@; - my $filename = "./taintB$$"; # NB: $filename isn't tainted! - END { unlink $filename if defined $filename } + my $filename = tempfile(); # NB: $filename isn't tainted! $foo = $filename . $TAINT; unlink $filename; # in any case @@ -506,8 +505,7 @@ SKIP: { my $foo = "x" x 979; taint_these $foo; local *FOO; - my $temp = "./taintC$$"; - END { unlink $temp } + my $temp = tempfile(); test open(FOO, "> $temp"), "Couldn't open $temp for write: $!"; test !eval { ioctl FOO, $TAINT0, $foo }, 'ioctl'; @@ -1254,6 +1252,70 @@ foreach my $ord (78, 163, 256) { ok(!tainted($1), "\\S match with chr $ord"); } +{ + # 59998 + sub cr { my $x = crypt($_[0], $_[1]); $x } + sub co { my $x = ~$_[0]; $x } + my ($a, $b); + $a = cr('hello', 'foo' . $TAINT); + $b = cr('hello', 'foo'); + ok(tainted($a), "tainted crypt"); + ok(!tainted($b), "untainted crypt"); + $a = co('foo' . $TAINT); + $b = co('foo'); + ok(tainted($a), "tainted complement"); + ok(!tainted($b), "untainted complement"); +} + +{ + my @data = qw(bonk zam zlonk qunckkk); + # Clearly some sort of usenet bang-path + my $string = $TAINT . join "!", @data; + + ok(tainted($string), "tainted data"); + + my @got = split /!|,/, $string; + + # each @got would be useful here, but I want the test for earlier perls + for my $i (0 .. $#data) { + ok(tainted($got[$i]), "tainted result $i"); + is($got[$i], $data[$i], "correct content $i"); + } + + ok(tainted($string), "still tainted data"); + + my @got = split /[!,]/, $string; + + # each @got would be useful here, but I want the test for earlier perls + for my $i (0 .. $#data) { + ok(tainted($got[$i]), "tainted result $i"); + is($got[$i], $data[$i], "correct content $i"); + } + + ok(tainted($string), "still tainted data"); + + my @got = split /!/, $string; + + # each @got would be useful here, but I want the test for earlier perls + for my $i (0 .. $#data) { + ok(tainted($got[$i]), "tainted result $i"); + is($got[$i], $data[$i], "correct content $i"); + } +} + +# Bug RT #52552 - broken by change at git commit id f337b08 +{ + my $x = $TAINT. q{print "Hello world\n"}; + my $y = pack "a*", $x; + ok(tainted($y), "pack a* preserves tainting"); + + my $z = pack "A*", q{print "Hello world\n"}.$TAINT; + ok(tainted($z), "pack A* preserves tainting"); + + my $zz = pack "a*a*", q{print "Hello world\n"}, $TAINT; + ok(tainted($zz), "pack a*a* preserves tainting"); +} + # This may bomb out with the alarm signal so keep it last SKIP: { skip "No alarm()" unless $Config{d_alarm}; diff --git a/gnu/usr.bin/perl/t/op/undef.t b/gnu/usr.bin/perl/t/op/undef.t index 04cac52fd67..8bfecab9e4d 100644 --- a/gnu/usr.bin/perl/t/op/undef.t +++ b/gnu/usr.bin/perl/t/op/undef.t @@ -3,102 +3,116 @@ BEGIN { chdir 't' if -d 't'; @INC = '../lib'; + require './test.pl'; } -print "1..36\n"; +use strict; -print defined($a) ? "not ok 1\n" : "ok 1\n"; +use vars qw(@ary %ary %hash); + +plan 37; + +ok !defined($a); $a = 1+1; -print defined($a) ? "ok 2\n" : "not ok 2\n"; +ok defined($a); undef $a; -print defined($a) ? "not ok 3\n" : "ok 3\n"; +ok !defined($a); $a = "hi"; -print defined($a) ? "ok 4\n" : "not ok 4\n"; +ok defined($a); $a = $b; -print defined($a) ? "not ok 5\n" : "ok 5\n"; +ok !defined($a); @ary = ("1arg"); $a = pop(@ary); -print defined($a) ? "ok 6\n" : "not ok 6\n"; +ok defined($a); $a = pop(@ary); -print defined($a) ? "not ok 7\n" : "ok 7\n"; +ok !defined($a); @ary = ("1arg"); $a = shift(@ary); -print defined($a) ? "ok 8\n" : "not ok 8\n"; +ok defined($a); $a = shift(@ary); -print defined($a) ? "not ok 9\n" : "ok 9\n"; +ok !defined($a); $ary{'foo'} = 'hi'; -print defined($ary{'foo'}) ? "ok 10\n" : "not ok 10\n"; -print defined($ary{'bar'}) ? "not ok 11\n" : "ok 11\n"; +ok defined($ary{'foo'}); +ok !defined($ary{'bar'}); undef $ary{'foo'}; -print defined($ary{'foo'}) ? "not ok 12\n" : "ok 12\n"; +ok !defined($ary{'foo'}); -print defined(@ary) ? "ok 13\n" : "not ok 13\n"; -print defined(%ary) ? "ok 14\n" : "not ok 14\n"; +ok defined(@ary); +ok defined(%ary); undef @ary; -print defined(@ary) ? "not ok 15\n" : "ok 15\n"; +ok !defined(@ary); undef %ary; -print defined(%ary) ? "not ok 16\n" : "ok 16\n"; +ok !defined(%ary); @ary = (1); -print defined @ary ? "ok 17\n" : "not ok 17\n"; +ok defined @ary; %ary = (1,1); -print defined %ary ? "ok 18\n" : "not ok 18\n"; +ok defined %ary; -sub foo { print "ok 19\n"; } +sub foo { pass; 1 } -&foo || print "not ok 19\n"; +&foo || fail; -print defined &foo ? "ok 20\n" : "not ok 20\n"; +ok defined &foo; undef &foo; -print defined(&foo) ? "not ok 21\n" : "ok 21\n"; +ok !defined(&foo); eval { undef $1 }; -print $@ =~ /^Modification of a read/ ? "ok 22\n" : "not ok 22\n"; +like $@, qr/^Modification of a read/; eval { $1 = undef }; -print $@ =~ /^Modification of a read/ ? "ok 23\n" : "not ok 23\n"; +like $@, qr/^Modification of a read/; { require Tie::Hash; tie my %foo, 'Tie::StdHash'; - print defined %foo ? "ok 24\n" : "not ok 24\n"; + ok defined %foo; %foo = ( a => 1 ); - print defined %foo ? "ok 25\n" : "not ok 25\n"; + ok defined %foo; } { require Tie::Array; tie my @foo, 'Tie::StdArray'; - print defined @foo ? "ok 26\n" : "not ok 26\n"; + ok defined @foo; @foo = ( a => 1 ); - print defined @foo ? "ok 27\n" : "not ok 27\n"; + ok defined @foo; } { # [perl #17753] segfault when undef'ing unquoted string constant eval 'undef tcp'; - print $@ =~ /^Can't modify constant item/ ? "ok 28\n" : "not ok 28\n"; + like $@, qr/^Can't modify constant item/; } # bugid 3096 # undefing a hash may free objects with destructors that then try to # modify the hash. To them, the hash should appear empty. -$test = 29; %hash = ( key1 => bless({}, 'X'), key2 => bless({}, 'X'), ); undef %hash; sub X::DESTROY { - print "not " if keys %hash; print "ok $test\n"; $test++; - print "not " if values %hash; print "ok $test\n"; $test++; - print "not " if each %hash; print "ok $test\n"; $test++; - print "not " if defined delete $hash{'key2'}; print "ok $test\n"; $test++; + is scalar keys %hash, 0; + is scalar values %hash, 0; + my @l = each %hash; + is @l, 0; + is delete $hash{'key2'}, undef; } + +# this will segfault if it fails + +sub PVBM () { 'foo' } +{ my $dummy = index 'foo', PVBM } + +my $pvbm = PVBM; +undef $pvbm; +ok !defined $pvbm; diff --git a/gnu/usr.bin/perl/t/op/universal.t b/gnu/usr.bin/perl/t/op/universal.t index 9817d3fe680..f1c0323c67d 100644 --- a/gnu/usr.bin/perl/t/op/universal.t +++ b/gnu/usr.bin/perl/t/op/universal.t @@ -10,7 +10,7 @@ BEGIN { require "./test.pl"; } -plan tests => 111; +plan tests => 116; $a = {}; bless $a, "Bob"; @@ -228,3 +228,20 @@ package main; eval { UNIVERSAL::DOES([], "foo") }; like( $@, qr/Can't call method "DOES" on unblessed reference/, 'DOES call error message says DOES, not isa' ); + +# Tests for can seem to be split between here and method.t +# Add the verbatim perl code mentioned in the comments of +# http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2001-05/msg01710.html +# but never actually tested. +is(UNIVERSAL->can("NoSuchPackage::foo"), undef); + +@splatt::ISA = 'zlopp'; +ok (splatt->isa('zlopp')); +ok (!splatt->isa('plop')); + +# This should reset the ->isa lookup cache +@splatt::ISA = 'plop'; +# And here is the new truth. +ok (!splatt->isa('zlopp')); +ok (splatt->isa('plop')); + diff --git a/gnu/usr.bin/perl/t/op/write.t b/gnu/usr.bin/perl/t/op/write.t index 25101d109d0..f13ac5f247e 100644 --- a/gnu/usr.bin/perl/t/op/write.t +++ b/gnu/usr.bin/perl/t/op/write.t @@ -3,8 +3,11 @@ BEGIN { chdir 't' if -d 't'; @INC = '../lib'; + require './test.pl'; } +use strict; # Amazed that this hackery can be made strict ... + # read in a file sub cat { my $file = shift; @@ -58,14 +61,21 @@ for my $tref ( @NumTests ){ my $bas_tests = 20; # number of tests in section 3 -my $hmb_tests = 39; +my $bug_tests = 4 + 3 * 3 * 5 * 2 * 3 + 2 + 1 + 1; + +# number of tests in section 4 +my $hmb_tests = 35; -printf "1..%d\n", $bas_tests + $num_tests + $hmb_tests; +my $tests = $bas_tests + $num_tests + $bug_tests + $hmb_tests; + +plan $tests; ############ ## Section 1 ############ +use vars qw($fox $multiline $foo $good); + format OUT = the quick brown @<< $fox @@ -94,7 +104,7 @@ $foo = 'when in the course of human events it becomes necessary'; write(OUT); close OUT or die "Could not close: $!"; -$right = +my $right = "the quick brown fox jumped forescore @@ -105,10 +115,7 @@ the course of huma... now is the time for all good men to come to\n"; -if (cat('Op_write.tmp') eq $right) - { print "ok 1\n"; 1 while unlink 'Op_write.tmp'; } -else - { print "not ok 1\n"; } +is cat('Op_write.tmp'), $right and do { 1 while unlink 'Op_write.tmp'; }; $fox = 'wolfishness'; my $fox = 'foxiness'; # Test a lexical variable. @@ -147,10 +154,7 @@ becomes necessary now is the time for all good men to come to\n"; -if (cat('Op_write.tmp') eq $right) - { print "ok 2\n"; 1 while unlink 'Op_write.tmp'; } -else - { print "not ok 2\n"; } +is cat('Op_write.tmp'), $right and do { 1 while unlink 'Op_write.tmp'; }; eval <<'EOFORMAT'; format OUT2 = @@ -191,14 +195,11 @@ becomes necessary now is the time for all good men to come to\n"; -if (cat('Op_write.tmp') eq $right) - { print "ok 3\n"; 1 while unlink 'Op_write.tmp'; } -else - { print "not ok 3\n"; } +is cat('Op_write.tmp'), $right and do { 1 while unlink 'Op_write.tmp' }; # formline tests -$mustbe = <<EOT; +$right = <<EOT; @ a @> ab @>> abc @@ -212,7 +213,8 @@ $mustbe = <<EOT; @>>>>>>>>>> abc EOT -$was1 = $was2 = ''; +my $was1 = my $was2 = ''; +use vars '$format2'; for (0..10) { # lexical picture $^A = ''; @@ -225,8 +227,8 @@ for (0..10) { formline $format2, 'abc'; $was2 .= "$format2 $^A\n"; } -print $was1 eq $mustbe ? "ok 4\n" : "not ok 4\n"; -print $was2 eq $mustbe ? "ok 5\n" : "not ok 5\n"; +is $was1, $right; +is $was2, $right; $^A = ''; @@ -246,24 +248,24 @@ close OUT3 or die "Could not close: $!"; $right = "fit\n"; -if (cat('Op_write.tmp') eq $right) - { print "ok 6\n"; 1 while unlink 'Op_write.tmp'; } -else - { print "not ok 6\n"; } +is cat('Op_write.tmp'), $right and do { 1 while unlink 'Op_write.tmp' }; + # test lexicals and globals { + my $test = curr_test(); my $this = "ok"; - our $that = 7; + our $that = $test; format LEX = @<<@| $this,$that . open(LEX, ">&STDOUT") or die; write LEX; - $that = 8; + $that = ++$test; write LEX; close LEX or die "Could not close: $!"; + curr_test($test + 1); } # LEX_INTERPNORMAL test my %e = ( a => 1 ); @@ -274,13 +276,7 @@ format OUT4 = open OUT4, ">Op_write.tmp" or die "Can't create Op_write.tmp"; write (OUT4); close OUT4 or die "Could not close: $!"; -if (cat('Op_write.tmp') eq "1\n") { - print "ok 9\n"; - 1 while unlink "Op_write.tmp"; - } -else { - print "not ok 9\n"; - } +is cat('Op_write.tmp'), "1\n" and do { 1 while unlink "Op_write.tmp" }; eval <<'EOFORMAT'; format OUT10 = @@ -291,15 +287,13 @@ EOFORMAT open(OUT10, '>Op_write.tmp') || die "Can't create Op_write.tmp"; +use vars '$test1'; $test1 = 12.95; write(OUT10); close OUT10 or die "Could not close: $!"; $right = " 12.95 00012.95\n"; -if (cat('Op_write.tmp') eq $right) - { print "ok 10\n"; 1 while unlink 'Op_write.tmp'; } -else - { print "not ok 10\n"; } +is cat('Op_write.tmp'), $right and do { 1 while unlink 'Op_write.tmp' }; eval <<'EOFORMAT'; format OUT11 = @@ -322,18 +316,16 @@ $right = "00012.95 1 0# 10 #\n"; -if (cat('Op_write.tmp') eq $right) - { print "ok 11\n"; 1 while unlink 'Op_write.tmp'; } -else - { print "not ok 11\n"; } +is cat('Op_write.tmp'), $right and do { 1 while unlink 'Op_write.tmp' }; { + my $test = curr_test(); my $el; format OUT12 = ok ^<<<<<<<<<<<<<<~~ # sv_chop() naze $el . - my %hash = (12 => 3); + my %hash = ($test => 3); open(OUT12, '>Op_write.tmp') || die "Can't create Op_write.tmp"; for $el (keys %hash) { @@ -341,15 +333,16 @@ $el } close OUT12 or die "Could not close: $!"; print cat('Op_write.tmp'); - + curr_test($test + 1); } { + my $test = curr_test(); # Bug report and testcase by Alexey Tourbin use Tie::Scalar; my $v; tie $v, 'Tie::StdScalar'; - $v = 13; + $v = $test; format OUT13 = ok ^<<<<<<<<< ~~ $v @@ -358,6 +351,7 @@ $v write(OUT13); close OUT13 or die "Could not close: $!"; print cat('Op_write.tmp'); + curr_test($test + 1); } { # test 14 @@ -365,9 +359,7 @@ $v # must fail since we have a trailing ; in the eval'ed string (WL) my @v = ('k'); eval "format OUT14 = \n@\n\@v"; - print +($@ && $@ =~ /Format not terminated/) - ? "ok 14\n" : "not ok 14 $@\n"; - + like $@, qr/Format not terminated/; } { # test 15 @@ -383,7 +375,7 @@ $txt write(OUT15); close OUT15 or die "Could not close: $!"; my $res = cat('Op_write.tmp'); - print $res eq "line 1\nline 2\n" ? "ok 15\n" : "not ok 15\n"; + is $res, "line 1\nline 2\n"; } { # test 16: multiple use of a variable in same line with ^< @@ -398,7 +390,7 @@ $txt, $txt write(OUT16); close OUT16 or die "Could not close: $!"; my $res = cat('Op_write.tmp'); - print $res eq <<EOD ? "ok 16\n" : "not ok 16\n"; + is $res, <<EOD; this_is_block_1 this_is_block_2 this_is_block_3 this_is_block_4 EOD @@ -420,7 +412,7 @@ Here we go: @* That's all, folks! my $exp = <<EOD; Here we go: $txt That's all, folks! EOD - print $res eq $exp ? "ok 17\n" : "not ok 17\n"; + is $res, $exp; } { # test 18: @# and ~~ would cause runaway format, but we now @@ -432,8 +424,7 @@ EOD . open(OUT18, '>Op_write.tmp') || die "Can't create Op_write.tmp"; eval { write(OUT18); }; - print +($@ && $@ =~ /Repeated format line will never terminate/) - ? "ok 18\n" : "not ok 18: $@\n"; + like $@, qr/Repeated format line will never terminate/; close OUT18 or die "Could not close: $!"; } @@ -448,7 +439,7 @@ EOD write(OUT19); close OUT19 or die "Could not close: $!"; my $res = cat('Op_write.tmp'); - print $res eq <<EOD ? "ok 19\n" : "not ok 19\n"; + is $res, <<EOD; gaga\0 gaga\0 EOD @@ -477,7 +468,7 @@ $h{xkey}, $h{ykey} write(OUT20); close OUT20 or die "Could not close: $!"; my $res = cat('Op_write.tmp'); - print $res eq $exp ? "ok 20\n" : "not ok 20 res=[$res]exp=[$exp]\n"; + is $res, $exp; } @@ -486,68 +477,112 @@ $h{xkey}, $h{ykey} ## numeric formatting ##################### -my $nt = $bas_tests; +curr_test($bas_tests + 1); + for my $tref ( @NumTests ){ my $writefmt = shift( @$tref ); while (@$tref) { my $val = shift @$tref; my $expected = shift @$tref; my $writeres = swrite( $writefmt, $val ); - $nt++; - my $ok = ref($expected) - ? $writeres =~ $expected - : $writeres eq $expected; - - print $ok - ? "ok $nt - $writefmt\n" - : "not ok $nt\n# f=[$writefmt] exp=[$expected] got=[$writeres]\n"; + if (ref $expected) { + like $writeres, $expected, $writefmt; + } else { + is $writeres, $expected, $writefmt; + } } } ##################################### ## Section 3 -## Easiest to add new tests above here -####################################### - -# scary format testing from H.Merijn Brand - -my $test = $bas_tests + $num_tests + 1; -my $tests = $bas_tests + $num_tests + $hmb_tests; - -if ($^O eq 'VMS' || $^O eq 'MSWin32' || $^O eq 'dos' || $^O eq 'MacOS' || - ($^O eq 'os2' and not eval '$OS2::can_fork')) { - foreach ($test..$tests) { - print "ok $_ # skipped: '|-' and '-|' not supported\n"; - } - exit(0); -} - - -use strict; # Amazed that this hackery can be made strict ... +## Easiest to add new tests just here +##################################### # DAPM. Exercise a couple of error codepaths { local $~ = ''; eval { write }; - print "not " unless $@ and $@ =~ /Not a format reference/; - print "ok $test - Not a format reference\n"; - $test++; + like $@, qr/Not a format reference/, 'format reference'; $~ = "NOSUCHFORMAT"; eval { write }; - print "not " unless $@ and $@ =~ /Undefined format/; - print "ok $test - Undefined format\n"; - $test++; + like $@, qr/Undefined format/, 'no such format'; } -# Just a complete test for format, including top-, left- and bottom marging -# and format detection through glob entries +{ + package Count; + + sub TIESCALAR { + my $class = shift; + bless [shift, 0, 0], $class; + } + + sub FETCH { + my $self = shift; + ++$self->[1]; + $self->[0]; + } + + sub STORE { + my $self = shift; + ++$self->[2]; + $self->[0] = shift; + } +} + +{ + my ($pound_utf8, $pm_utf8) = map { my $a = "$_\x{100}"; chop $a; $a} + my ($pound, $pm) = ("\xA3", "\xB1"); + + foreach my $first ('N', $pound, $pound_utf8) { + foreach my $base ('N', $pm, $pm_utf8) { + foreach my $second ($base, "$base\n", "$base\nMoo!", "$base\nMoo!\n", + "$base\nMoo!\n",) { + foreach (['^*', qr/(.+)/], ['@*', qr/(.*?)$/s]) { + my ($format, $re) = @$_; + foreach my $class ('', 'Count') { + my $name = "$first, $second $format $class"; + $name =~ s/\n/\\n/g; + + $first =~ /(.+)/ or die $first; + my $expect = "1${1}2"; + $second =~ $re or die $second; + $expect .= " 3${1}4"; + + if ($class) { + my $copy1 = $first; + my $copy2; + tie $copy2, $class, $second; + is swrite("1^*2 3${format}4", $copy1, $copy2), $expect, $name; + my $obj = tied $copy2; + is $obj->[1], 1, 'value read exactly once'; + } else { + my ($copy1, $copy2) = ($first, $second); + is swrite("1^*2 3${format}4", $copy1, $copy2), $expect, $name; + } + } + } + } + } + } +} + +{ + # This will fail an assertion in 5.10.0 built with -DDEBUGGING (because + # pp_formline attempts to set SvCUR() on an SVt_RV). I suspect that it will + # be doing something similarly out of bounds on everything from 5.000 + my $ref = []; + is swrite('>^*<', $ref), ">$ref<"; + is swrite('>@*<', $ref), ">$ref<"; +} format EMPTY = . +my $test = curr_test(); + format Comment = ok @<<<<< $test @@ -559,19 +594,59 @@ $test open STDOUT_DUP, ">&STDOUT"; my $oldfh = select STDOUT_DUP; $= = 10; -{ local $~ = "Comment"; - write; - $test++; - print $- == 9 - ? "ok $test # TODO\n" : "not ok $test # TODO \$- = $- instead of 9\n"; - $test++; - print $^ eq "STDOUT_DUP_TOP" - ? "ok $test\n" : "not ok $test\n# \$^ = $^ instead of 'STDOUT_DUP_TOP'\n"; - $test++; +{ + local $~ = "Comment"; + write; + curr_test($test + 1); + { + local $::TODO = '[ID 20020227.005] format bug with undefined _TOP'; + is $-, 9; + } + is $^, "STDOUT_DUP_TOP"; } select $oldfh; close STDOUT_DUP; +*CmT = *{$::{Comment}}{FORMAT}; +ok defined *{$::{CmT}}{FORMAT}, "glob assign"; + +fresh_perl_like(<<'EOP', qr/^Format STDOUT redefined at/, {stderr => 1}, '#64562 - Segmentation fault with redefined formats and warnings'); +#!./perl + +use strict; +use warnings; # crashes! + +format = +. + +write; + +format = +. + +write; +EOP + +############################# +## Section 4 +## Add new tests *above* here +############################# + +# scary format testing from H.Merijn Brand + +# Just a complete test for format, including top-, left- and bottom marging +# and format detection through glob entries + +if ($^O eq 'VMS' || $^O eq 'MSWin32' || $^O eq 'dos' || $^O eq 'MacOS' || + ($^O eq 'os2' and not eval '$OS2::can_fork')) { + $test = curr_test(); + SKIP: { + skip "'|-' and '-|' not supported", $tests - $test + 1; + } + exit(0); +} + + $^ = "STDOUT_TOP"; $= = 7; # Page length $- = 0; # Lines left @@ -591,33 +666,31 @@ select ((select (STDOUT), $| = 1)[0]); # flush STDOUT my $opened = open FROM_CHILD, "-|"; unless (defined $opened) { - print "not ok $test - open gave $!\n"; exit 0; + fail "open gave $!"; + exit 0; } if ($opened) { # in parent here - print "ok $test - open\n"; $test++; + pass 'open'; my $s = " " x $lm; while (<FROM_CHILD>) { unless (@data) { - print "not ok $test - too much output\n"; + fail 'too much output'; exit; } s/^/$s/; my $exp = shift @data; - print + ($_ eq $exp ? "" : "not "), "ok ", $test++, " \n"; - if ($_ ne $exp) { - s/\n/\\n/g for $_, $exp; - print "#expected: $exp\n#got: $_\n"; - } + is $_, $exp; } close FROM_CHILD; - print + (@data?"not ":""), "ok ", $test++, " - too little output\n"; + is "@data", "", "correct length of output"; exit; } # in child here +$::NO_ENDING = 1; select ((select (STDOUT), $| = 1)[0]); $tm = "\n" x $tm; |