xref: /openbsd-src/gnu/usr.bin/perl/t/re/pat_psycho.t (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1#!./perl
2#
3# This is a home for regular expression tests that don't fit into
4# the format supported by re/regexp.t.  If you want to add a test
5# that does fit that format, add it to re/re_tests, not here.
6#
7# this file includes test that my burn a lot of CPU or otherwise be heavy
8# on resources. Set env var $PERL_SKIP_PSYCHO_TEST to skip this file
9
10use strict;
11use warnings;
12use 5.010;
13
14
15sub run_tests;
16
17$| = 1;
18
19
20BEGIN {
21    chdir 't' if -d 't';
22    @INC = ('../lib','.');
23    require './test.pl';
24    if ($^O eq 'dec_osf') {
25        skip_all("$^O cannot handle this test");
26    }
27}
28
29
30skip_all('$PERL_SKIP_PSYCHO_TEST set') if $ENV{PERL_SKIP_PSYCHO_TEST};
31
32plan tests => 15;  # Update this when adding/deleting tests.
33
34run_tests() unless caller;
35
36#
37# Tests start here.
38#
39sub run_tests {
40    print "# Set PERL_SKIP_PSYCHO_TEST to skip these tests\n";
41
42    {
43
44	# stress test tries
45
46        my @normal = qw [the are some normal words];
47
48        local $" = "|";
49
50	note "setting up trie psycho vars ...";
51        my @psycho = (@normal, map chr $_, 255 .. 20000);
52        my $psycho1 = "@psycho";
53        for (my $i = @psycho; -- $i;) {
54            my $j = int rand (1 + $i);
55            @psycho [$i, $j] = @psycho [$j, $i];
56        }
57        my $psycho2 = "@psycho";
58
59        foreach my $word (@normal) {
60            ok $word =~ /($psycho1)/ && $1 eq $word, qq{"$word" =~ /\$psycho1/};
61            ok $word =~ /($psycho2)/ && $1 eq $word, qq{"$word" =~ /\$psycho1/};
62        }
63    }
64
65
66    {
67        # stress test CURLYX/WHILEM.
68        #
69        # This test includes varying levels of nesting, and according to
70        # profiling done against build 28905, exercises every code line in the
71        # CURLYX and WHILEM blocks, except those related to LONGJMP, the
72        # super-linear cache and warnings. It executes about 0.5M regexes
73
74        no warnings 'regexp';   # Silence "has useless greediness modifier"
75        my $r = qr/^
76                    (?:
77                        ( (?:a|z+)+ )
78                        (?:
79                            ( (?:b|z+){3,}? )
80                            (
81                                (?:
82                                    (?:
83                                        (?:c|z+){1,1}?z
84                                    )?
85                                    (?:c|z+){1,1}
86                                )*
87                            )
88                            (?:z*){2,}
89                            ( (?:z+|d)+ )
90                            (?:
91                                ( (?:e|z+)+ )
92                            )*
93                            ( (?:f|z+)+ )
94                        )*
95                        ( (?:z+|g)+ )
96                        (?:
97                            ( (?:h|z+)+ )
98                        )*
99                        ( (?:i|z+)+ )
100                    )+
101                    ( (?:j|z+)+ )
102                    (?:
103                        ( (?:k|z+)+ )
104                    )*
105                    ( (?:l|z+)+ )
106              $/x;
107        use warnings 'regexp';
108
109        my $ok = 1;
110        my $msg = "CURLYX stress test";
111        OUTER:
112          for my $a ("x","a","aa") {
113            for my $b ("x","bbb","bbbb") {
114              my $bs = $a.$b;
115              for my $c ("x","c","cc") {
116                my $cs = $bs.$c;
117                for my $d ("x","d","dd") {
118                  my $ds = $cs.$d;
119                  for my $e ("x","e","ee") {
120                    my $es = $ds.$e;
121                    for my $f ("x","f","ff") {
122                      my $fs = $es.$f;
123                      for my $g ("x","g","gg") {
124                        my $gs = $fs.$g;
125                        for my $h ("x","h","hh") {
126                          my $hs = $gs.$h;
127                          for my $i ("x","i","ii") {
128                            my $is = $hs.$i;
129                            for my $j ("x","j","jj") {
130                              my $js = $is.$j;
131                              for my $k ("x","k","kk") {
132                                my $ks = $js.$k;
133                                for my $l ("x","l","ll") {
134                                  my $ls = $ks.$l;
135                                  if ($ls =~ $r) {
136                                    if ($ls =~ /x/) {
137                                      $msg .= ": unexpected match for [$ls]";
138                                      $ok = 0;
139                                      last OUTER;
140                                    }
141                                    my $cap = "$1$2$3$4$5$6$7$8$9$10$11$12";
142                                    unless ($ls eq $cap) {
143                                      $msg .= ": capture: [$ls], got [$cap]";
144                                      $ok = 0;
145                                      last OUTER;
146                                    }
147                                  }
148                                  else {
149                                    unless ($ls =~ /x/) {
150                                      $msg = ": failed for [$ls]";
151                                      $ok = 0;
152                                      last OUTER;
153                                    }
154                                  }
155                                }
156                              }
157                            }
158                          }
159                        }
160                      }
161                    }
162                  }
163                }
164              }
165            }
166        }
167        ok($ok, $msg);
168    }
169
170
171    {
172	# these bits of test code used to run quadratically. If we break
173	# anything, they'll start to take minutes to run, rather than
174	# seconds. We don't actually measure times or set alarms, since
175	# that tends to be very fragile and prone to false positives.
176	# Instead, just hope that if someone is messing with
177	# performance-related code, they'll re-run the test suite and
178	# notice it suddenly takes a lot longer.
179
180	my $x;
181
182	$x = 'x' x 1_000_000;
183	1 while $x =~ /(.)/g;
184	pass "ascii =~ /(.)/";
185
186	{
187	    local ${^UTF8CACHE} = 1; # defeat debugging
188	    $x = "\x{100}" x 1_000_000;
189	    1 while $x =~ /(.)/g;
190	    pass "utf8 =~ /(.)/";
191	}
192
193	# run these in separate processes, since they set $&
194
195        fresh_perl_is(<<'EOF', "ok\n", {}, 'ascii =~ /(.)/, mention $&');
196$&;
197$x = 'x' x 1_000_000;
1981 while $x =~ /(.)/g;
199print "ok\n";
200EOF
201
202        fresh_perl_is(<<'EOF', "ok\n", {}, 'utf8 =~ /(.)/, mention $&');
203$&;
204local ${^UTF8CACHE} = 1; # defeat debugging
205$x = "\x{100}" x 1_000_000;
2061 while $x =~ /(.)/g;
207print "ok\n";
208EOF
209
210
211    }
212} # End of sub run_tests
213
2141;
215