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