15.10.6.2-2.js (8439B)
1 /* -*- indent-tabs-mode: nil; js-indent-level: 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 try some edge-case values. Thanks to the work done in 114 * http://bugzilla.mozilla.org/show_bug.cgi?id=124339, |lastIndex| 115 * is now stored as a double instead of a uint32_t (unsigned integer). 116 * 117 * Note 2^32 -1 is the upper bound for uint32's, but doubles can go 118 * all the way up to Number.MAX_VALUE. So that's why we need cases 119 * between those two numbers. 120 */ 121 status = inSection(6); 122 pattern.lastIndex = Math.pow(2,32); 123 actualmatch = pattern.exec(string); 124 expectedmatch = null; 125 addThis(); 126 127 status = inSection(8); 128 pattern.lastIndex = Math.pow(2,32) + 1; 129 actualmatch = pattern.exec(string); 130 expectedmatch = null; 131 addThis(); 132 133 status = inSection(10); 134 pattern.lastIndex = Math.pow(2,32) * 2; 135 actualmatch = pattern.exec(string); 136 expectedmatch = null; 137 addThis(); 138 139 status = inSection(12); 140 pattern.lastIndex = Math.pow(2,40); 141 actualmatch = pattern.exec(string); 142 expectedmatch = null; 143 addThis(); 144 145 status = inSection(14); 146 pattern.lastIndex = Number.MAX_VALUE; 147 actualmatch = pattern.exec(string); 148 expectedmatch = null; 149 addThis(); 150 151 152 153 /****************************************************************************** 154 * 155 * Case 2: repeat all the above cases WITHOUT the global flag set. 156 * According to EMCA. |lastIndex| should get set to 0 before the match. 157 * 158 * Therefore re.exec(str) should be unaffected; thus our expected values 159 * below are now DIFFERENT when |lastIndex| is < 0 or > str.length 160 * 161 *****************************************************************************/ 162 163 pattern = /abc/i; 164 string = 'AbcaBcabC'; 165 166 status = inSection(16); 167 actualmatch = pattern.exec(string); 168 expectedmatch = Array('Abc'); 169 addThis(); 170 171 status = inSection(17); 172 actualmatch = pattern.exec(string); 173 expectedmatch = Array('Abc'); // NOT Array('aBc') as before - 174 addThis(); 175 176 status = inSection(18); 177 actualmatch = pattern.exec(string); 178 expectedmatch = Array('Abc'); // NOT Array('abC') as before - 179 addThis(); 180 181 /* 182 * At this point above, |lastIndex| WAS > string.length, but not here - 183 */ 184 status = inSection(19); 185 actualmatch = pattern.exec(string); 186 expectedmatch = Array('Abc') // NOT null as before - 187 addThis(); 188 189 /* 190 * Now let's set |lastIndex| to -1 191 */ 192 status = inSection(20); 193 pattern.lastIndex = -1; 194 actualmatch = pattern.exec(string); 195 expectedmatch = Array('Abc') // NOT null as before - 196 addThis(); 197 198 /* 199 * Now try some edge-case values. Thanks to the work done in 200 * http://bugzilla.mozilla.org/show_bug.cgi?id=124339, |lastIndex| 201 * is now stored as a double instead of a uint32_t (unsigned integer). 202 * 203 * Note 2^32 -1 is the upper bound for uint32's, but doubles can go 204 * all the way up to Number.MAX_VALUE. So that's why we need cases 205 * between those two numbers. 206 */ 207 status = inSection(21); 208 pattern.lastIndex = Math.pow(2,32); 209 actualmatch = pattern.exec(string); 210 expectedmatch = Array('Abc') // NOT null as before - 211 addThis(); 212 213 status = inSection(22); 214 pattern.lastIndex = -Math.pow(2,32); 215 actualmatch = pattern.exec(string); 216 expectedmatch = Array('Abc') // NOT null as before - 217 addThis(); 218 219 status = inSection(23); 220 pattern.lastIndex = Math.pow(2,32) + 1; 221 actualmatch = pattern.exec(string); 222 expectedmatch = Array('Abc') // NOT null as before - 223 addThis(); 224 225 status = inSection(24); 226 pattern.lastIndex = -(Math.pow(2,32) + 1); 227 actualmatch = pattern.exec(string); 228 expectedmatch = Array('Abc') // NOT null as before - 229 addThis(); 230 231 status = inSection(25); 232 pattern.lastIndex = Math.pow(2,32) * 2; 233 actualmatch = pattern.exec(string); 234 expectedmatch = Array('Abc') // NOT null as before - 235 addThis(); 236 237 status = inSection(26); 238 pattern.lastIndex = -Math.pow(2,32) * 2; 239 actualmatch = pattern.exec(string); 240 expectedmatch = Array('Abc') // NOT null as before - 241 addThis(); 242 243 status = inSection(27); 244 pattern.lastIndex = Math.pow(2,40); 245 actualmatch = pattern.exec(string); 246 expectedmatch = Array('Abc') // NOT null as before -; 247 addThis(); 248 249 status = inSection(28); 250 pattern.lastIndex = -Math.pow(2,40); 251 actualmatch = pattern.exec(string); 252 expectedmatch = Array('Abc') // NOT null as before - 253 addThis(); 254 255 status = inSection(29); 256 pattern.lastIndex = Number.MAX_VALUE; 257 actualmatch = pattern.exec(string); 258 expectedmatch = Array('Abc') // NOT null as before - 259 addThis(); 260 261 status = inSection(30); 262 pattern.lastIndex = -Number.MAX_VALUE; 263 actualmatch = pattern.exec(string); 264 expectedmatch = Array('Abc') // NOT null as before - 265 addThis(); 266 267 268 269 270 //------------------------------------------------------------------------------------------------- 271 test(); 272 //------------------------------------------------------------------------------------------------- 273 274 275 276 function addThis() 277 { 278 statusmessages[i] = status; 279 patterns[i] = pattern; 280 strings[i] = string; 281 actualmatches[i] = actualmatch; 282 expectedmatches[i] = expectedmatch; 283 i++; 284 } 285 286 287 function test() 288 { 289 printBugNumber(BUGNUMBER); 290 printStatus (summary); 291 testRegExp(statusmessages, patterns, strings, actualmatches, expectedmatches); 292 }