|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* |
|
7 * |
|
8 * Date: 18 Feb 2002 |
|
9 * SUMMARY: Testing re.exec(str) when re.lastIndex is < 0 or > str.length |
|
10 * |
|
11 * Case 1: If re has the global flag set, then re(str) should be null |
|
12 * Case 2: If re doesn't have this set, then re(str) should be unaffected |
|
13 * |
|
14 * See http://bugzilla.mozilla.org/show_bug.cgi?id=76717 |
|
15 * |
|
16 * |
|
17 * From the ECMA-262 Final spec: |
|
18 * |
|
19 * 15.10.6.2 RegExp.prototype.exec(string) |
|
20 * Performs a regular expression match of string against the regular |
|
21 * expression and returns an Array object containing the results of |
|
22 * the match, or null if the string did not match. |
|
23 * |
|
24 * The string ToString(string) is searched for an occurrence of the |
|
25 * regular expression pattern as follows: |
|
26 * |
|
27 * 1. Let S be the value of ToString(string). |
|
28 * 2. Let length be the length of S. |
|
29 * 3. Let lastIndex be the value of the lastIndex property. |
|
30 * 4. Let i be the value of ToInteger(lastIndex). |
|
31 * 5. If the global property is false, let i = 0. |
|
32 * 6. If i < 0 or i > length then set lastIndex to 0 and return null. |
|
33 * 7. Call [[Match]], giving it the arguments S and i. |
|
34 * If [[Match]] returned failure, go to step 8; |
|
35 * otherwise let r be its State result and go to step 10. |
|
36 * 8. Let i = i+1. |
|
37 * 9. Go to step 6. |
|
38 * 10. Let e be r's endIndex value. |
|
39 * 11. If the global property is true, set lastIndex to e. |
|
40 * |
|
41 * etc. |
|
42 * |
|
43 * |
|
44 * So: |
|
45 * |
|
46 * A. If the global flag is not set, |lastIndex| is set to 0 |
|
47 * before the match is attempted; thus the match is unaffected. |
|
48 * |
|
49 * B. If the global flag IS set and re.lastIndex is >= 0 and <= str.length, |
|
50 * |lastIndex| is incremented every time there is a match; not from |
|
51 * i to i+1, but from i to "endIndex" e: |
|
52 * |
|
53 * e = (index of last input character matched so far by the pattern) + 1 |
|
54 * |
|
55 * The match is then attempted from this position in the string (Step 7). |
|
56 * |
|
57 * C. When the global flag IS set and re.lastIndex is < 0 or > str.length, |
|
58 * |lastIndex| is set to 0 and the match returns null. |
|
59 * |
|
60 * |
|
61 * Note the |lastIndex| property is writeable, and may be set arbitrarily |
|
62 * by the programmer - and we will do that below. |
|
63 * |
|
64 */ |
|
65 //----------------------------------------------------------------------------- |
|
66 var i = 0; |
|
67 var BUGNUMBER = 76717; |
|
68 var summary = 'Testing re.exec(str) when re.lastIndex is < 0 or > str.length'; |
|
69 var status = ''; |
|
70 var statusmessages = new Array(); |
|
71 var pattern = ''; |
|
72 var patterns = new Array(); |
|
73 var string = ''; |
|
74 var strings = new Array(); |
|
75 var actualmatch = ''; |
|
76 var actualmatches = new Array(); |
|
77 var expectedmatch = ''; |
|
78 var expectedmatches = new Array(); |
|
79 |
|
80 |
|
81 /****************************************************************************** |
|
82 * |
|
83 * Case 1 : when the global flag is set - |
|
84 * |
|
85 *****************************************************************************/ |
|
86 pattern = /abc/gi; |
|
87 string = 'AbcaBcabC'; |
|
88 |
|
89 status = inSection(1); |
|
90 actualmatch = pattern.exec(string); |
|
91 expectedmatch = Array('Abc'); |
|
92 addThis(); |
|
93 |
|
94 status = inSection(2); |
|
95 actualmatch = pattern.exec(string); |
|
96 expectedmatch = Array('aBc'); |
|
97 addThis(); |
|
98 |
|
99 status = inSection(3); |
|
100 actualmatch = pattern.exec(string); |
|
101 expectedmatch = Array('abC'); |
|
102 addThis(); |
|
103 |
|
104 /* |
|
105 * At this point |lastIndex| is > string.length, so the match should be null - |
|
106 */ |
|
107 status = inSection(4); |
|
108 actualmatch = pattern.exec(string); |
|
109 expectedmatch = null; |
|
110 addThis(); |
|
111 |
|
112 /* |
|
113 * Now let's set |lastIndex| to -1, so the match should again be null - |
|
114 */ |
|
115 status = inSection(5); |
|
116 pattern.lastIndex = -1; |
|
117 actualmatch = pattern.exec(string); |
|
118 expectedmatch = null; |
|
119 addThis(); |
|
120 |
|
121 /* |
|
122 * Now try some edge-case values. Thanks to the work done in |
|
123 * http://bugzilla.mozilla.org/show_bug.cgi?id=124339, |lastIndex| |
|
124 * is now stored as a double instead of a uint32_t (unsigned integer). |
|
125 * |
|
126 * Note 2^32 -1 is the upper bound for uint32's, but doubles can go |
|
127 * all the way up to Number.MAX_VALUE. So that's why we need cases |
|
128 * between those two numbers. |
|
129 */ |
|
130 status = inSection(6); |
|
131 pattern.lastIndex = Math.pow(2,32); |
|
132 actualmatch = pattern.exec(string); |
|
133 expectedmatch = null; |
|
134 addThis(); |
|
135 |
|
136 status = inSection(7); |
|
137 pattern.lastIndex = -Math.pow(2,32); |
|
138 actualmatch = pattern.exec(string); |
|
139 expectedmatch = null; |
|
140 addThis(); |
|
141 |
|
142 status = inSection(8); |
|
143 pattern.lastIndex = Math.pow(2,32) + 1; |
|
144 actualmatch = pattern.exec(string); |
|
145 expectedmatch = null; |
|
146 addThis(); |
|
147 |
|
148 status = inSection(9); |
|
149 pattern.lastIndex = -(Math.pow(2,32) + 1); |
|
150 actualmatch = pattern.exec(string); |
|
151 expectedmatch = null; |
|
152 addThis(); |
|
153 |
|
154 status = inSection(10); |
|
155 pattern.lastIndex = Math.pow(2,32) * 2; |
|
156 actualmatch = pattern.exec(string); |
|
157 expectedmatch = null; |
|
158 addThis(); |
|
159 |
|
160 status = inSection(11); |
|
161 pattern.lastIndex = -Math.pow(2,32) * 2; |
|
162 actualmatch = pattern.exec(string); |
|
163 expectedmatch = null; |
|
164 addThis(); |
|
165 |
|
166 status = inSection(12); |
|
167 pattern.lastIndex = Math.pow(2,40); |
|
168 actualmatch = pattern.exec(string); |
|
169 expectedmatch = null; |
|
170 addThis(); |
|
171 |
|
172 status = inSection(13); |
|
173 pattern.lastIndex = -Math.pow(2,40); |
|
174 actualmatch = pattern.exec(string); |
|
175 expectedmatch = null; |
|
176 addThis(); |
|
177 |
|
178 status = inSection(14); |
|
179 pattern.lastIndex = Number.MAX_VALUE; |
|
180 actualmatch = pattern.exec(string); |
|
181 expectedmatch = null; |
|
182 addThis(); |
|
183 |
|
184 status = inSection(15); |
|
185 pattern.lastIndex = -Number.MAX_VALUE; |
|
186 actualmatch = pattern.exec(string); |
|
187 expectedmatch = null; |
|
188 addThis(); |
|
189 |
|
190 |
|
191 |
|
192 /****************************************************************************** |
|
193 * |
|
194 * Case 2: repeat all the above cases WITHOUT the global flag set. |
|
195 * According to EMCA. |lastIndex| should get set to 0 before the match. |
|
196 * |
|
197 * Therefore re.exec(str) should be unaffected; thus our expected values |
|
198 * below are now DIFFERENT when |lastIndex| is < 0 or > str.length |
|
199 * |
|
200 *****************************************************************************/ |
|
201 |
|
202 pattern = /abc/i; |
|
203 string = 'AbcaBcabC'; |
|
204 |
|
205 status = inSection(16); |
|
206 actualmatch = pattern.exec(string); |
|
207 expectedmatch = Array('Abc'); |
|
208 addThis(); |
|
209 |
|
210 status = inSection(17); |
|
211 actualmatch = pattern.exec(string); |
|
212 expectedmatch = Array('Abc'); // NOT Array('aBc') as before - |
|
213 addThis(); |
|
214 |
|
215 status = inSection(18); |
|
216 actualmatch = pattern.exec(string); |
|
217 expectedmatch = Array('Abc'); // NOT Array('abC') as before - |
|
218 addThis(); |
|
219 |
|
220 /* |
|
221 * At this point above, |lastIndex| WAS > string.length, but not here - |
|
222 */ |
|
223 status = inSection(19); |
|
224 actualmatch = pattern.exec(string); |
|
225 expectedmatch = Array('Abc') // NOT null as before - |
|
226 addThis(); |
|
227 |
|
228 /* |
|
229 * Now let's set |lastIndex| to -1 |
|
230 */ |
|
231 status = inSection(20); |
|
232 pattern.lastIndex = -1; |
|
233 actualmatch = pattern.exec(string); |
|
234 expectedmatch = Array('Abc') // NOT null as before - |
|
235 addThis(); |
|
236 |
|
237 /* |
|
238 * Now try some edge-case values. Thanks to the work done in |
|
239 * http://bugzilla.mozilla.org/show_bug.cgi?id=124339, |lastIndex| |
|
240 * is now stored as a double instead of a uint32_t (unsigned integer). |
|
241 * |
|
242 * Note 2^32 -1 is the upper bound for uint32's, but doubles can go |
|
243 * all the way up to Number.MAX_VALUE. So that's why we need cases |
|
244 * between those two numbers. |
|
245 */ |
|
246 status = inSection(21); |
|
247 pattern.lastIndex = Math.pow(2,32); |
|
248 actualmatch = pattern.exec(string); |
|
249 expectedmatch = Array('Abc') // NOT null as before - |
|
250 addThis(); |
|
251 |
|
252 status = inSection(22); |
|
253 pattern.lastIndex = -Math.pow(2,32); |
|
254 actualmatch = pattern.exec(string); |
|
255 expectedmatch = Array('Abc') // NOT null as before - |
|
256 addThis(); |
|
257 |
|
258 status = inSection(23); |
|
259 pattern.lastIndex = Math.pow(2,32) + 1; |
|
260 actualmatch = pattern.exec(string); |
|
261 expectedmatch = Array('Abc') // NOT null as before - |
|
262 addThis(); |
|
263 |
|
264 status = inSection(24); |
|
265 pattern.lastIndex = -(Math.pow(2,32) + 1); |
|
266 actualmatch = pattern.exec(string); |
|
267 expectedmatch = Array('Abc') // NOT null as before - |
|
268 addThis(); |
|
269 |
|
270 status = inSection(25); |
|
271 pattern.lastIndex = Math.pow(2,32) * 2; |
|
272 actualmatch = pattern.exec(string); |
|
273 expectedmatch = Array('Abc') // NOT null as before - |
|
274 addThis(); |
|
275 |
|
276 status = inSection(26); |
|
277 pattern.lastIndex = -Math.pow(2,32) * 2; |
|
278 actualmatch = pattern.exec(string); |
|
279 expectedmatch = Array('Abc') // NOT null as before - |
|
280 addThis(); |
|
281 |
|
282 status = inSection(27); |
|
283 pattern.lastIndex = Math.pow(2,40); |
|
284 actualmatch = pattern.exec(string); |
|
285 expectedmatch = Array('Abc') // NOT null as before -; |
|
286 addThis(); |
|
287 |
|
288 status = inSection(28); |
|
289 pattern.lastIndex = -Math.pow(2,40); |
|
290 actualmatch = pattern.exec(string); |
|
291 expectedmatch = Array('Abc') // NOT null as before - |
|
292 addThis(); |
|
293 |
|
294 status = inSection(29); |
|
295 pattern.lastIndex = Number.MAX_VALUE; |
|
296 actualmatch = pattern.exec(string); |
|
297 expectedmatch = Array('Abc') // NOT null as before - |
|
298 addThis(); |
|
299 |
|
300 status = inSection(30); |
|
301 pattern.lastIndex = -Number.MAX_VALUE; |
|
302 actualmatch = pattern.exec(string); |
|
303 expectedmatch = Array('Abc') // NOT null as before - |
|
304 addThis(); |
|
305 |
|
306 |
|
307 |
|
308 |
|
309 //------------------------------------------------------------------------------------------------- |
|
310 test(); |
|
311 //------------------------------------------------------------------------------------------------- |
|
312 |
|
313 |
|
314 |
|
315 function addThis() |
|
316 { |
|
317 statusmessages[i] = status; |
|
318 patterns[i] = pattern; |
|
319 strings[i] = string; |
|
320 actualmatches[i] = actualmatch; |
|
321 expectedmatches[i] = expectedmatch; |
|
322 i++; |
|
323 } |
|
324 |
|
325 |
|
326 function test() |
|
327 { |
|
328 enterFunc ('test'); |
|
329 printBugNumber(BUGNUMBER); |
|
330 printStatus (summary); |
|
331 testRegExp(statusmessages, patterns, strings, actualmatches, expectedmatches); |
|
332 exitFunc ('test'); |
|
333 } |