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@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//----------------------------------------------------------------------------- 95var i = 0; 96var bug = 76717; 97var summary = 'Testing re.exec(str) when re.lastIndex is < 0 or > str.length'; 98var status = ''; 99var statusmessages = new Array(); 100var pattern = ''; 101var patterns = new Array(); 102var string = ''; 103var strings = new Array(); 104var actualmatch = ''; 105var actualmatches = new Array(); 106var expectedmatch = ''; 107var expectedmatches = new Array(); 108 109 110/****************************************************************************** 111 * 112 * Case 1 : when the global flag is set - 113 * 114 *****************************************************************************/ 115pattern = /abc/gi; 116string = '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 231pattern = /abc/i; 232string = '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//------------------------------------------------------------------------------------------------- 339test(); 340//------------------------------------------------------------------------------------------------- 341 342 343 344function 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 355function test() 356{ 357 enterFunc ('test'); 358 printBugNumber (bug); 359 printStatus (summary); 360 testRegExp(statusmessages, patterns, strings, actualmatches, expectedmatches); 361 exitFunc ('test'); 362} 363