Epigraph for 5.29.8
[perl.git] / t / op / index.t
1 #!./perl
2
3 BEGIN {
4     chdir 't' if -d 't';
5     require './test.pl';
6     set_up_inc('../lib');
7     require './charset_tools.pl';
8 }
9
10 use strict;
11 plan( tests => 412 );
12
13 run_tests() unless caller;
14
15 sub run_tests {
16
17     my $foo = 'Now is the time for all good men to come to the aid of their country.';
18
19     my $first = substr($foo,0,index($foo,'the'));
20     is($first, "Now is ");
21
22     my $last = substr($foo,rindex($foo,'the'),100);
23     is($last, "their country.");
24
25     $last = substr($foo,index($foo,'Now'),2);
26     is($last, "No");
27
28     $last = substr($foo,rindex($foo,'Now'),2);
29     is($last, "No");
30
31     $last = substr($foo,index($foo,'.'),100);
32     is($last, ".");
33
34     $last = substr($foo,rindex($foo,'.'),100);
35     is($last, ".");
36
37     is(index("ababa","a",-1), 0);
38     is(index("ababa","a",0), 0);
39     is(index("ababa","a",1), 2);
40     is(index("ababa","a",2), 2);
41     is(index("ababa","a",3), 4);
42     is(index("ababa","a",4), 4);
43     is(index("ababa","a",5), -1);
44
45     is(rindex("ababa","a",-1), -1);
46     is(rindex("ababa","a",0), 0);
47     is(rindex("ababa","a",1), 0);
48     is(rindex("ababa","a",2), 2);
49     is(rindex("ababa","a",3), 2);
50     is(rindex("ababa","a",4), 4);
51     is(rindex("ababa","a",5), 4);
52
53     # tests for empty search string
54     is(index("abc", "", -1), 0);
55     is(index("abc", "", 0), 0);
56     is(index("abc", "", 1), 1);
57     is(index("abc", "", 2), 2);
58     is(index("abc", "", 3), 3);
59     is(index("abc", "", 4), 3);
60     is(rindex("abc", "", -1), 0);
61     is(rindex("abc", "", 0), 0);
62     is(rindex("abc", "", 1), 1);
63     is(rindex("abc", "", 2), 2);
64     is(rindex("abc", "", 3), 3);
65     is(rindex("abc", "", 4), 3);
66
67     $a = "foo \x{1234}bar";
68
69     is(index($a, "\x{1234}"), 4);
70     is(index($a, "bar",    ), 5);
71
72     is(rindex($a, "\x{1234}"), 4);
73     is(rindex($a, "foo",    ), 0);
74
75     {
76         my $needle = "\x{1230}\x{1270}";
77         my @needles = split ( //, $needle );
78         my $haystack = "\x{1228}\x{1228}\x{1230}\x{1270}";
79         foreach ( @needles ) {
80             my $a = index ( "\x{1228}\x{1228}\x{1230}\x{1270}", $_ );
81             my $b = index ( $haystack, $_ );
82             is($a, $b, q{[perl #22375] 'split'/'index' problem for utf8});
83         }
84         $needle = "\x{1270}\x{1230}"; # Transpose them.
85         @needles = split ( //, $needle );
86         foreach ( @needles ) {
87             my $a = index ( "\x{1228}\x{1228}\x{1230}\x{1270}", $_ );
88             my $b = index ( $haystack, $_ );
89             is($a, $b, q{[perl #22375] 'split'/'index' problem for utf8});
90         }
91     }
92
93     {
94         my $search;
95         my $text;
96         $search = "foo " . uni_to_native("\xc9") . " bar";
97         $text = "a" . uni_to_native("\xa3\xa3") . "a $search    $search quux";
98
99         my $text_utf8 = $text;
100         utf8::upgrade($text_utf8);
101         my $search_utf8 = $search;
102         utf8::upgrade($search_utf8);
103
104         is (index($text, $search), 5);
105         is (rindex($text, $search), 18);
106         is (index($text, $search_utf8), 5);
107         is (rindex($text, $search_utf8), 18);
108         is (index($text_utf8, $search), 5);
109         is (rindex($text_utf8, $search), 18);
110         is (index($text_utf8, $search_utf8), 5);
111         is (rindex($text_utf8, $search_utf8), 18);
112
113         my $text_octets = $text_utf8;
114         utf8::encode ($text_octets);
115         my $search_octets = $search_utf8;
116         utf8::encode ($search_octets);
117
118         is (index($text_octets, $search_octets), 7, "index octets, octets")
119             or _diag ($text_octets, $search_octets);
120         is (rindex($text_octets, $search_octets), 21, "rindex octets, octets");
121         is (index($text_octets, $search_utf8), -1);
122         is (rindex($text_octets, $search_utf8), -1);
123         is (index($text_utf8, $search_octets), -1);
124         is (rindex($text_utf8, $search_octets), -1);
125
126         is (index($text_octets, $search), -1);
127         is (rindex($text_octets, $search), -1);
128         is (index($text, $search_octets), -1);
129         is (rindex($text, $search_octets), -1);
130     }
131
132     SKIP: {
133         skip("Not a 64-bit machine", 3) if length sprintf("%x", ~0) <= 8;
134         my $a = eval q{"\x{80000000}"};
135         my $s = $a.'defxyz';
136         is(index($s, 'def'), 1, "0x80000000 is a single character");
137
138         my $b = eval q{"\x{fffffffd}"};
139         my $t = $b.'pqrxyz';
140         is(index($t, 'pqr'), 1, "0xfffffffd is a single character");
141
142         local ${^UTF8CACHE} = -1;
143         is(index($t, 'xyz'), 4, "0xfffffffd and utf8cache");
144     }
145
146
147     # Tests for NUL characters.
148     {
149         my @tests = (
150             ["",            -1, -1, -1],
151             ["foo",         -1, -1, -1],
152             ["\0",           0, -1, -1],
153             ["\0\0",         0,  0, -1],
154             ["\0\0\0",       0,  0,  0],
155             ["foo\0",        3, -1, -1],
156             ["foo\0foo\0\0", 3,  7, -1],
157         );
158         foreach my $l (1 .. 3) {
159             my $q = "\0" x $l;
160             my $i = 0;
161             foreach my $test (@tests) {
162                 $i ++;
163                 my $str = $$test [0];
164                 my $res = $$test [$l];
165
166                 {
167                     is (index ($str, $q), $res, "Find NUL character(s)");
168                 }
169
170                 #
171                 # Bug #53746 shows a difference between variables and literals,
172                 # so test literals as well.
173                 #
174                 my $test_str = qq {is (index ("$str", "$q"), $res, } .
175                                qq {"Find NUL character(s)")};
176                    $test_str =~ s/\0/\\0/g;
177
178                 eval $test_str;
179                 die $@ if $@;
180             }
181         }
182     }
183
184     {
185         # RT#75898
186         is(eval { utf8::upgrade($_ = " "); index $_, " ", 72 }, -1,
187            'UTF-8 cache handles offset beyond the end of the string');
188         $_ = "\x{100}BC";
189         is(index($_, "C", 4), -1,
190            'UTF-8 cache handles offset beyond the end of the string');
191     }
192
193     # RT #89218
194     use constant {PVBM => 'galumphing', PVBM2 => 'bang'};
195
196     sub index_it {
197         is(index('galumphing', PVBM), 0,
198            "index isn't confused by format compilation");
199     }
200      
201     index_it();
202     is($^A, '', '$^A is empty');
203     formline PVBM;
204     is($^A, 'galumphing', "formline isn't confused by index compilation");
205     index_it();
206
207     $^A = '';
208     # must not do index here before formline.
209     is($^A, '', '$^A is empty');
210     formline PVBM2;
211     is($^A, 'bang', "formline isn't confused by index compilation");
212     is(index('bang', PVBM2), 0, "index isn't confused by format compilation");
213
214     {
215         use constant perl => "rules";
216         is(index("perl rules", perl), 5, 'first index of a constant works');
217         is(index("rules 1 & 2", perl), 0, 'second index of the same constant works');
218     }
219
220     # PVBM compilation should not flatten ref constants
221     use constant riffraff => \our $referent;
222     index "foo", riffraff;
223     is ref riffraff, 'SCALAR', 'index does not flatten ref constants';
224
225     package o { use overload '""' => sub { "foo" } }
226     bless \our $referent, o::;
227     is index("foo", riffraff), 0,
228         'index respects changes in ref stringification';
229
230     use constant quire => ${qr/(?{})/}; # A REGEXP, not a reference to one
231     index "foo", quire;
232     eval ' "" =~ quire ';
233     is $@, "", 'regexp constants containing code blocks are not flattened';
234
235     use constant bang => $! = 8;
236     index "foo", bang;
237     cmp_ok bang, '==', 8, 'dualvar constants are not flattened';
238
239     use constant u => undef;
240     {
241         my $w;
242         local $SIG{__WARN__} = sub { $w .= shift };
243         eval '
244             use warnings;
245             sub { () = index "foo", u; }
246         ';
247         is $w, undef, 'no warnings from compiling index($foo, undef_constant)';
248     }
249     is u, undef, 'undef constant is still undef';
250
251     is index('the main road', __PACKAGE__), 4,
252         '[perl #119169] __PACKAGE__ as 2nd argument';
253
254     utf8::upgrade my $substr = "\x{a3}a";
255
256     is index($substr, 'a'), 1, 'index reply reflects characters not octets';
257
258     # op_eq, op_const optimised away in (index() == -1) and variants
259
260     for my $test (
261           # expect:
262           #    F: always false regardless of the expression
263           #    T: always true  regardless of the expression
264           #    f: expect false if the string is found
265           #    t: expect true  if the string is found
266           #
267           # op  const  expect
268         [ '<',    -1,      'F' ],
269         [ '<',     0,      'f' ],
270
271         [ '<=',   -1,      'f' ],
272         [ '<=',    0,      'f' ],
273
274         [ '==',   -1,      'f' ],
275         [ '==',    0,      'F' ],
276
277         [ '!=',   -1,      't' ],
278         [ '!=',    0,      'T' ],
279
280         [ '>=',   -1,      'T' ],
281         [ '>=',    0,      't' ],
282
283         [ '>',    -1,      't' ],
284         [ '>',     0,      't' ],
285     ) {
286         my ($op, $const, $expect0) = @$test;
287
288         my $s = "abcde";
289         my $r;
290
291         for my $substr ("e", "z") {
292             my $expect =
293                 $expect0 eq 'T' ? 1 == 1 :
294                 $expect0 eq 'F' ? 0 == 1 :
295                 $expect0 eq 't' ? ($substr eq "e") :
296                                   ($substr ne "e");
297
298             for my $rindex ("", "r") {
299                 for my $reverse (0, 1) {
300                     my $rop = $op;
301                     if ($reverse) {
302                         $rop =~ s/>/</ or  $rop =~ s/</>/;
303                     }
304                     for my $targmy (0, 1) {
305                         my $index = "${rindex}index(\$s, '$substr')";
306                         my $expr = $reverse ? "$const $rop $index" : "$index $rop $const";
307                         # OPpTARGET_MY variant: the '$r = ' is optimised away too
308                         $expr = "\$r = ($expr)" if $targmy;
309
310                         my $got = eval $expr;
311                         die "eval of <$expr> gave: $@\n" if $@ ne "";
312
313                         is !!$got, $expect, $expr;
314                         if ($targmy) {
315                             is !!$r, $expect, "$expr - r value";
316                         }
317                     }
318                 }
319             }
320         }
321     }
322
323     {
324         # RT #131823
325         # index with OPpTARGET_MY shouldn't do the '== -1' optimisation
326         my $s = "abxyz";
327         my $r;
328
329         ok(!(($r = index($s,"z")) == -1),  "(r = index(a)) == -1");
330         is($r, 4,                          "(r = index(a)) == -1 - r value");
331
332
333     }
334
335 } # end of sub run_tests