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