This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Variants of several regression tests that run the actul tests inside
[perl5.git] / t / op / pat.t
index b431db3..2ccc07c 100755 (executable)
@@ -12,10 +12,14 @@ BEGIN {
     chdir 't' if -d 't';
     @INC = '../lib';
 }
-our $Message = "Line";
+our $Message = "Noname test";
 
 eval 'use Config';          #  Defaults assumed if this fails
 
+run_tests() unless caller;
+
+sub run_tests {
+
 $x = "abc\ndef\n";
 
 if ($x =~ /^abc/) {print "ok 1\n";} else {print "not ok 1\n";}
@@ -533,25 +537,32 @@ print "not " unless $1 and /$1/;
 print "ok $test\n";
 $test++;
 
+if ($::running_as_thread) {
+    print "not ok $test # TODO & SKIP: croaks in 5.10 when threaded\n";
+    $test++;
+} else {
 $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++;
+{
+    local $TODO = $::running_as_thread;
+    $c="$a";
+    /$a$a/;
+    iseq($b, '11');
+}
 
 {
   use re "eval";
   /$a$c$a/;
-  print "not " unless $b eq '14';
-  print "ok $test\n";
-  $test++;
+  {
+      local $TODO = $::running_as_thread;
+      iseq($b, '14');
+  }
 
   local $lex_a = 2;
   my $lex_a = 43;
@@ -571,10 +582,10 @@ $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++;
+  # FIXME - split this one. That would require removing a lot of hard coded
+  # test numbers.
+  local $TODO = $::running_as_thread;
+  ok($b eq '14' and $@ =~ /Eval-group not allowed/ and not $match);
 }
 
 {
@@ -789,9 +800,10 @@ print "not " if $str =~ /^...\G/;
 print "ok $test\n";
 $test++;
 
-print "not " unless $str =~ /.\G./ and $& eq 'bc';
-print "ok $test\n";
-$test++;
+{
+    local $TODO = $::running_as_thread;
+    ok($str =~ /.\G./ and $& eq 'bc');
+}
 
 print "not " unless $str =~ /\G../ and $& eq 'cd';
 print "ok $test\n";
@@ -875,25 +887,29 @@ $foo='aabbccddeeffgg';
 pos($foo)=1;
 
 $foo=~/.\G(..)/g;
-print "not " unless($1 eq 'ab');
-print "ok $test\n";
-$test++;
+{
+    local $TODO = $::running_as_thread;
+    iseq($1,'ab');
+}
 
 pos($foo) += 1;
 $foo=~/.\G(..)/g;
-print "not " unless($1 eq 'cc');
-print "ok $test\n";
-$test++;
+{
+    local $TODO = $::running_as_thread;
+    iseq($1, 'cc');
+}
 
 pos($foo) += 1;
 $foo=~/.\G(..)/g;
-print "not " unless($1 eq 'de');
-print "ok $test\n";
-$test++;
+{
+    local $TODO = $::running_as_thread;
+    iseq($1, 'de');
+}
 
-print "not " unless $foo =~ /\Gef/g;
-print "ok $test\n";
-$test++;
+{
+    local $TODO = $::running_as_thread;
+    ok($foo =~ /\Gef/g);
+}
 
 undef pos $foo;
 
@@ -1048,9 +1064,7 @@ $test++;
 
 @b = grep(/\w/,@a);
 @c = grep(/[\w]/,@a);
-print "not " if "@b" ne "@c";
-print "ok $test\n";
-$test++;
+iseq("@b","@c");
 
 # see if backtracking optimization works correctly
 "\n\n" =~ /\n  $ \n/x or print "not ";
@@ -1283,7 +1297,10 @@ print "ok 246\n";
 print "not " unless "\x{abcd}" =~ /\x{abcd}/;
 print "ok 247\n";
 
-{
+if ($::running_as_thread) {
+    print "not ok 248 # TODO & SKIP: SEGVs in 5.10 when threaded\n";
+    print "not ok 249 # TODO & SKIP: SEGVs in 5.10 when threaded\n";
+} else {
     # bug id 20001008.001
 
     $test = 248;
@@ -2037,9 +2054,10 @@ $test = 687;
 # Force scalar context on the patern match
 sub ok ($;$) {
     my($ok, $name) = @_;
+    my $todo = $TODO ? " # TODO $TODO" : '';
 
     printf "%sok %d - %s\n", ($ok ? "" : "not "), $test,
-        $name||"$Message:".((caller)[2]);
+        ($name||$Message)."$todo\tLine ".((caller)[2]);
 
     printf "# Failed test at line %d\n", (caller)[2] unless $ok;
 
@@ -3078,12 +3096,15 @@ ok("A" =~ /\p{AsciiHexAndDash}/, "'A' is AsciiHexAndDash");
     ok($a !~ /^\C{4}y/,     q{don't match \C{4}y});
 }
 
-$_ = '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");
+{
+    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");
+}
 
 ok("\x{100}" =~ /\x{100}/, "[perl #15397]");
 ok("\x{100}" =~ /(\x{100})/, "[perl #15397]");
@@ -3138,13 +3159,13 @@ ok("bbbbac" =~ /$pattern/ && $1 eq 'a', "[perl #3547]");
     foreach (1,2,3,4) {
            $p++ if /(??{ $p })/
     }
-    ok ($p == 5, "[perl #20683] (??{ }) returns stale values");
+    iseq ($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 })/
     }
-    ok ( $p == 5, "(??{ }) returns stale values");
+    iseq ( $p, 5, "(??{ }) returns stale values");
 }
 
 {
@@ -3390,7 +3411,7 @@ ok(("foba  ba${s}pxySS$s$s" =~ qr/(b(?:a${s}t|a${s}f|a${s}p)[xy]+$s*)/i)
 }
 
 
-
+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;
@@ -3410,9 +3431,9 @@ if (!$ENV{PERL_SKIP_PSYCHO_TEST}){
     ok($utf8 =~ /(abc|\xe9)/i, "utf8/latin trie");
     ok($utf8 =~ /(abc|$latin1)/i, "utf8/latin trie runtime");
 
-    ok("\xe9" =~ /$utf8/i, "# TODO latin/utf8");
+    ok("\xe9" =~ /$utf8/i, "# latin/utf8");
     ok("\xe9" =~ /(abc|$utf8)/i, "# latin/utf8 trie");
-    ok($latin1 =~ /$utf8/i, "# TODO latin/utf8 runtime");
+    ok($latin1 =~ /$utf8/i, "# latin/utf8 runtime");
     ok($latin1 =~ /(abc|$utf8)/i, "# latin/utf8 trie runtime");
 }
 
@@ -3449,6 +3470,7 @@ if (!$ENV{PERL_SKIP_PSYCHO_TEST}){
 }
 
 {
+    local $TODO = "See changes 26925-26928, which reverted change 26410";
     package lv;
     $var = "abc";
     sub variable : lvalue { $var }
@@ -3457,16 +3479,17 @@ if (!$ENV{PERL_SKIP_PSYCHO_TEST}){
     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";
+    ok($f eq "ab", "pos retained between calls") or print "# $@\n";
 }
 
 {
+    local $TODO = "See changes 26925-26928, which reverted change 26410";
     $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";
+    ok($f eq "ab", "pos retained between calls") or print "# $@\n";
 }
 
 # [perl #37836] Simple Regex causes SEGV when run on specific data
@@ -3667,16 +3690,44 @@ SKIP:{
     $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 \%+");
+    }
+}
+
 sub iseq($$;$) { 
     my ( $got, $expect, $name)=@_;
+    my $todo = $TODO ? " # TODO $TODO" : '';
     
     $_=defined($_) ? "'$_'" : "undef"
         for $got, $expect;
         
     my $ok=  $got eq $expect;
         
-    printf "%sok %d - %s\n", ($ok ? "" : "not "), $test,
-        $name||"$Message:".((caller)[2]);
+    printf "%sok %d - %s$todo\n", ($ok ? "" : "not "), $test,
+        ($name||$Message)."\tLine ".((caller)[2]);
 
     printf "# Failed test at line %d\n".
            "# expected: %s\n". 
@@ -3722,7 +3773,24 @@ sub iseq($$;$) {
     ';
     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]";
+            }
+        }
+    }
+    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
@@ -3733,6 +3801,7 @@ sub iseq($$;$) {
 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+)+ )
@@ -4053,16 +4122,460 @@ for my $c ("z", "\0", "!", chr(254), chr(256)) {
         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');
 }
 {
-    local $Message="RT#22395";
+    local $Message="RT 22395";
+    local $TODO = "Should be L+1 not L*(L+3)/2 (L=$l)";
     our $count;
-    for my $l (1,10,100,1000) {
+    for my $l (10,100,1000) {
        $count=0;
        ('a' x $l) =~ /(.*)(?{$count++})[bc]/;
-       iseq($l+1,$count,"Should be L+1 not L*(L+3)/2 (L=$l)");
+       iseq( $count, $l + 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++;
+        }
+        # End bad block
+    }
+    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");
+                    }
+                }
+            }
+       }
+    };    
+    
+    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");
+}
+
+{
+# 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");
+    }
+}
+
+{
+    my $res="";
+
+    if ('1' =~ /(?|(?<digit>1)|(?<digit>2))/) {
+      $res = "@{$- {digit}}";
+    }
+    iseq($res,"1",
+        "Check that (?|...) doesnt cause dupe entries in the names array");
+    #---
+    $res="";
+    if ('11' =~ /(?|(?<digit>1)|(?<digit>2))(?&digit)/) {
+      $res = "@{$- {digit}}";
+    }
+    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");
+            }
+        }
+    }
+}
+{
+    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(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" );
+}
+
+# length() on captures, the numbered ones end up in Perl_magic_len
+{
+    my $_ = "aoeu \xe6var ook";
+    /^ \w+ \s (?<eek>\S+)/x;
+
+    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
+
+    my $utf_8 = "\xd6schel";
+    utf8::upgrade($utf_8);
+    $utf_8 =~ m{(\xd6|&Ouml;)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");
+            }
+        }
+    }
+}
+{
+    my $a = 3; "" =~ /(??{ $a })/;
+    my $b = $a;
+    iseq($b, $a, "copy of scalar used for postponed subexpression");
+}
+{
+     local $Message = "\$REGMARK in replacement -- Bug #49190";
+     my $_ = "A";
+     s/(*:B)A/$REGMARK/;
+     iseq $_, "B";
+     $_ = "CCCCBAA";
+     s/(*:X)A+|(*:Y)B+|(*:Z)C+/$REGMARK/g;
+     iseq $_, "ZYX";
+}
+if ($::running_as_thread) {
+    for (1..3) {
+       print "not ok $test # TODO & SKIP: croaks when threaded\n";
+       $test++;
+    }
+} else {
+    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');
+}
+
+
+
+
 # Test counter is at bottom of file. Put new tests above here.
 #-------------------------------------------------------------------
 # Keep the following tests last -- they may crash perl
@@ -4092,8 +4605,11 @@ 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 = "substituation with lookahead (possible segv)";
+    local $Message = "substitution with lookahead (possible segv)";
     $_="ns1ns1ns1";
     s/ns(?=\d)/ns_/g;
     iseq($_,"ns_1ns_1ns_1");
@@ -4105,7 +4621,24 @@ ok((q(a)x 100) =~ /^(??{'(.)'x 100})/,
     iseq($_,"!Bang!1!Bang!2!Bang!3!Bang!");
 }
 
+# [perl #45337] utf8 + "[a]a{2}" + /$.../ = panic: sv_len_utf8 cache
+
+{
+    local ${^UTF8CACHE} = -1;
+    my $s="[a]a{2}";
+    utf8::upgrade $s;
+    ok("aaa" =~ /$s/, "#45337");
+}
+
 # Put new tests above the dotted line about a page above this comment
+iseq(0+$::test,$::TestCount,"Got the right number of tests!");
+
+} # end of sub pat_tests
 
 # Don't forget to update this!
-BEGIN { print "1..1363\n" };
+BEGIN {
+    $::TestCount = 4019;
+    print "1..$::TestCount\n";
+}
+
+"Truth";