1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 function testEscape(str, regex) { 29 assertEquals("foo:bar:baz", str.split(regex).join(":")); 30 } 31 32 testEscape("foo\nbar\nbaz", /\n/); 33 testEscape("foo bar baz", /\s/); 34 testEscape("foo\tbar\tbaz", /\s/); 35 testEscape("foo-bar-baz", /\u002D/); 36 37 // Test containing null char in regexp. 38 var s = '[' + String.fromCharCode(0) + ']'; 39 var re = new RegExp(s); 40 assertEquals(s.match(re).length, 1); 41 assertEquals(s.match(re)[0], String.fromCharCode(0)); 42 43 // Test strings containing all line separators 44 s = 'aA\nbB\rcC\r\ndD\u2028eE\u2029fF'; 45 re = /^./gm; // any non-newline character at the beginning of a line 46 var result = s.match(re); 47 assertEquals(result.length, 6); 48 assertEquals(result[0], 'a'); 49 assertEquals(result[1], 'b'); 50 assertEquals(result[2], 'c'); 51 assertEquals(result[3], 'd'); 52 assertEquals(result[4], 'e'); 53 assertEquals(result[5], 'f'); 54 55 re = /.$/gm; // any non-newline character at the end of a line 56 result = s.match(re); 57 assertEquals(result.length, 6); 58 assertEquals(result[0], 'A'); 59 assertEquals(result[1], 'B'); 60 assertEquals(result[2], 'C'); 61 assertEquals(result[3], 'D'); 62 assertEquals(result[4], 'E'); 63 assertEquals(result[5], 'F'); 64 65 re = /^[^]/gm; // *any* character at the beginning of a line 66 result = s.match(re); 67 assertEquals(result.length, 7); 68 assertEquals(result[0], 'a'); 69 assertEquals(result[1], 'b'); 70 assertEquals(result[2], 'c'); 71 assertEquals(result[3], '\n'); 72 assertEquals(result[4], 'd'); 73 assertEquals(result[5], 'e'); 74 assertEquals(result[6], 'f'); 75 76 re = /[^]$/gm; // *any* character at the end of a line 77 result = s.match(re); 78 assertEquals(result.length, 7); 79 assertEquals(result[0], 'A'); 80 assertEquals(result[1], 'B'); 81 assertEquals(result[2], 'C'); 82 assertEquals(result[3], '\r'); 83 assertEquals(result[4], 'D'); 84 assertEquals(result[5], 'E'); 85 assertEquals(result[6], 'F'); 86 87 // Some tests from the Mozilla tests, where our behavior used to differ from 88 // SpiderMonkey. 89 // From ecma_3/RegExp/regress-334158.js 90 assertTrue(/\ca/.test( "\x01" )); 91 assertFalse(/\ca/.test( "\\ca" )); 92 assertFalse(/\ca/.test( "ca" )); 93 assertTrue(/\c[a/]/.test( "\\ca" )); 94 assertTrue(/\c[a/]/.test( "\\c/" )); 95 96 // Test \c in character class 97 re = /^[\cM]$/; 98 assertTrue(re.test("\r")); 99 assertFalse(re.test("M")); 100 assertFalse(re.test("c")); 101 assertFalse(re.test("\\")); 102 assertFalse(re.test("\x03")); // I.e., read as \cc 103 104 re = /^[\c]]$/; 105 assertTrue(re.test("c]")); 106 assertTrue(re.test("\\]")); 107 assertFalse(re.test("\x1d")); // ']' & 0x1f 108 assertFalse(re.test("\x03]")); // I.e., read as \cc 109 110 re = /^[\c1]$/; // Digit control characters are masked in character classes. 111 assertTrue(re.test("\x11")); 112 assertFalse(re.test("\\")); 113 assertFalse(re.test("c")); 114 assertFalse(re.test("1")); 115 116 re = /^[\c_]$/; // Underscore control character is masked in character classes. 117 assertTrue(re.test("\x1f")); 118 assertFalse(re.test("\\")); 119 assertFalse(re.test("c")); 120 assertFalse(re.test("_")); 121 122 re = /^[\c$]$/; // Other characters are interpreted literally. 123 assertFalse(re.test("\x04")); 124 assertTrue(re.test("\\")); 125 assertTrue(re.test("c")); 126 assertTrue(re.test("$")); 127 128 assertTrue(/^[Z-\c-e]*$/.test("Z[\\cde")); 129 130 // Test that we handle \s and \S correctly on special Unicode characters. 131 re = /\s/; 132 assertTrue(re.test("\u2028")); 133 assertTrue(re.test("\u2029")); 134 assertTrue(re.test("\uFEFF")); 135 136 re = /\S/; 137 assertFalse(re.test("\u2028")); 138 assertFalse(re.test("\u2029")); 139 assertFalse(re.test("\uFEFF")); 140 141 // Test that we handle \s and \S correctly inside some bizarre 142 // character classes. 143 re = /[\s-:]/; 144 assertTrue(re.test('-')); 145 assertTrue(re.test(':')); 146 assertTrue(re.test(' ')); 147 assertTrue(re.test('\t')); 148 assertTrue(re.test('\n')); 149 assertFalse(re.test('a')); 150 assertFalse(re.test('Z')); 151 152 re = /[\S-:]/; 153 assertTrue(re.test('-')); 154 assertTrue(re.test(':')); 155 assertFalse(re.test(' ')); 156 assertFalse(re.test('\t')); 157 assertFalse(re.test('\n')); 158 assertTrue(re.test('a')); 159 assertTrue(re.test('Z')); 160 161 re = /[^\s-:]/; 162 assertFalse(re.test('-')); 163 assertFalse(re.test(':')); 164 assertFalse(re.test(' ')); 165 assertFalse(re.test('\t')); 166 assertFalse(re.test('\n')); 167 assertTrue(re.test('a')); 168 assertTrue(re.test('Z')); 169 170 re = /[^\S-:]/; 171 assertFalse(re.test('-')); 172 assertFalse(re.test(':')); 173 assertTrue(re.test(' ')); 174 assertTrue(re.test('\t')); 175 assertTrue(re.test('\n')); 176 assertFalse(re.test('a')); 177 assertFalse(re.test('Z')); 178 179 re = /[\s]/; 180 assertFalse(re.test('-')); 181 assertFalse(re.test(':')); 182 assertTrue(re.test(' ')); 183 assertTrue(re.test('\t')); 184 assertTrue(re.test('\n')); 185 assertFalse(re.test('a')); 186 assertFalse(re.test('Z')); 187 188 re = /[^\s]/; 189 assertTrue(re.test('-')); 190 assertTrue(re.test(':')); 191 assertFalse(re.test(' ')); 192 assertFalse(re.test('\t')); 193 assertFalse(re.test('\n')); 194 assertTrue(re.test('a')); 195 assertTrue(re.test('Z')); 196 197 re = /[\S]/; 198 assertTrue(re.test('-')); 199 assertTrue(re.test(':')); 200 assertFalse(re.test(' ')); 201 assertFalse(re.test('\t')); 202 assertFalse(re.test('\n')); 203 assertTrue(re.test('a')); 204 assertTrue(re.test('Z')); 205 206 re = /[^\S]/; 207 assertFalse(re.test('-')); 208 assertFalse(re.test(':')); 209 assertTrue(re.test(' ')); 210 assertTrue(re.test('\t')); 211 assertTrue(re.test('\n')); 212 assertFalse(re.test('a')); 213 assertFalse(re.test('Z')); 214 215 re = /[\s\S]/; 216 assertTrue(re.test('-')); 217 assertTrue(re.test(':')); 218 assertTrue(re.test(' ')); 219 assertTrue(re.test('\t')); 220 assertTrue(re.test('\n')); 221 assertTrue(re.test('a')); 222 assertTrue(re.test('Z')); 223 224 re = /[^\s\S]/; 225 assertFalse(re.test('-')); 226 assertFalse(re.test(':')); 227 assertFalse(re.test(' ')); 228 assertFalse(re.test('\t')); 229 assertFalse(re.test('\n')); 230 assertFalse(re.test('a')); 231 assertFalse(re.test('Z')); 232 233 // First - is treated as range operator, second as literal minus. 234 // This follows the specification in parsing, but doesn't throw on 235 // the \s at the beginning of the range. 236 re = /[\s-0-9]/; 237 assertTrue(re.test(' ')); 238 assertTrue(re.test('\xA0')); 239 assertTrue(re.test('-')); 240 assertTrue(re.test('0')); 241 assertTrue(re.test('9')); 242 assertFalse(re.test('1')); 243 244 // Test beginning and end of line assertions with or without the 245 // multiline flag. 246 re = /^\d+/; 247 assertFalse(re.test("asdf\n123")); 248 re = /^\d+/m; 249 assertTrue(re.test("asdf\n123")); 250 251 re = /\d+$/; 252 assertFalse(re.test("123\nasdf")); 253 re = /\d+$/m; 254 assertTrue(re.test("123\nasdf")); 255 256 // Test that empty matches are handled correctly for multiline global 257 // regexps. 258 re = /^(.*)/mg; 259 assertEquals(3, "a\n\rb".match(re).length); 260 assertEquals("*a\n*b\r*c\n*\r*d\r*\n*e", "a\nb\rc\n\rd\r\ne".replace(re, "*$1")); 261 262 // Test that empty matches advance one character 263 re = new RegExp("", "g"); 264 assertEquals("xAx", "A".replace(re, "x")); 265 assertEquals(3, String.fromCharCode(161).replace(re, "x").length); 266 267 // Test that we match the KJS behavior with regard to undefined constructor 268 // arguments: 269 re = new RegExp(); 270 // KJS actually shows this as '//'. Here we match the Firefox behavior (ie, 271 // giving a syntactically legal regexp literal). 272 assertEquals('/(?:)/', re.toString()); 273 re = new RegExp(void 0); 274 assertEquals('/(?:)/', re.toString()); 275 re.compile(); 276 assertEquals('/(?:)/', re.toString()); 277 re.compile(void 0); 278 assertEquals('/undefined/', re.toString()); 279 280 281 // Check for lazy RegExp literal creation 282 function lazyLiteral(doit) { 283 if (doit) return "".replace(/foo(/gi, ""); 284 return true; 285 } 286 287 assertTrue(lazyLiteral(false)); 288 assertThrows("lazyLiteral(true)"); 289 290 // Check $01 and $10 291 re = new RegExp("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)"); 292 assertEquals("t", "123456789t".replace(re, "$10"), "$10"); 293 assertEquals("15", "123456789t".replace(re, "$15"), "$10"); 294 assertEquals("1", "123456789t".replace(re, "$01"), "$01"); 295 assertEquals("$001", "123456789t".replace(re, "$001"), "$001"); 296 re = new RegExp("foo(.)"); 297 assertEquals("bar$0", "foox".replace(re, "bar$0"), "$0"); 298 assertEquals("bar$00", "foox".replace(re, "bar$00"), "$00"); 299 assertEquals("bar$000", "foox".replace(re, "bar$000"), "$000"); 300 assertEquals("barx", "foox".replace(re, "bar$01"), "$01 2"); 301 assertEquals("barx5", "foox".replace(re, "bar$15"), "$15"); 302 303 assertFalse(/()foo$\1/.test("football"), "football1"); 304 assertFalse(/foo$(?=ball)/.test("football"), "football2"); 305 assertFalse(/foo$(?!bar)/.test("football"), "football3"); 306 assertTrue(/()foo$\1/.test("foo"), "football4"); 307 assertTrue(/foo$(?=(ball)?)/.test("foo"), "football5"); 308 assertTrue(/()foo$(?!bar)/.test("foo"), "football6"); 309 assertFalse(/(x?)foo$\1/.test("football"), "football7"); 310 assertFalse(/foo$(?=ball)/.test("football"), "football8"); 311 assertFalse(/foo$(?!bar)/.test("football"), "football9"); 312 assertTrue(/(x?)foo$\1/.test("foo"), "football10"); 313 assertTrue(/foo$(?=(ball)?)/.test("foo"), "football11"); 314 assertTrue(/foo$(?!bar)/.test("foo"), "football12"); 315 316 // Check that the back reference has two successors. See 317 // BackReferenceNode::PropagateForward. 318 assertFalse(/f(o)\b\1/.test('foo')); 319 assertTrue(/f(o)\B\1/.test('foo')); 320 321 // Back-reference, ignore case: 322 // ASCII 323 assertEquals("xaAx,a", String(/x(a)\1x/i.exec("xaAx")), "backref-ASCII"); 324 assertFalse(/x(...)\1/i.test("xaaaaa"), "backref-ASCII-short"); 325 assertTrue(/x((?:))\1\1x/i.test("xx"), "backref-ASCII-empty"); 326 assertTrue(/x(?:...|(...))\1x/i.test("xabcx"), "backref-ASCII-uncaptured"); 327 assertTrue(/x(?:...|(...))\1x/i.test("xabcABCx"), "backref-ASCII-backtrack"); 328 assertEquals("xaBcAbCABCx,aBc", 329 String(/x(...)\1\1x/i.exec("xaBcAbCABCx")), 330 "backref-ASCII-twice"); 331 332 for (var i = 0; i < 128; i++) { 333 var testName = "backref-ASCII-char-" + i + "," + (i^0x20); 334 var test = /^(.)\1$/i.test(String.fromCharCode(i, i ^ 0x20)) 335 var c = String.fromCharCode(i); 336 if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) { 337 assertTrue(test, testName); 338 } else { 339 assertFalse(test, testName); 340 } 341 } 342 343 assertFalse(/f(o)$\1/.test('foo'), "backref detects at_end"); 344 345 // Check decimal escapes doesn't overflow. 346 // (Note: \214 is interpreted as octal). 347 assertArrayEquals(["\x8c7483648"], 348 /\2147483648/.exec("\x8c7483648"), 349 "Overflow decimal escape"); 350 351 352 // Check numbers in quantifiers doesn't overflow and doesn't throw on 353 // too large numbers. 354 assertFalse(/a{111111111111111111111111111111111111111111111}/.test('b'), 355 "overlarge1"); 356 assertFalse(/a{999999999999999999999999999999999999999999999}/.test('b'), 357 "overlarge2"); 358 assertFalse(/a{1,111111111111111111111111111111111111111111111}/.test('b'), 359 "overlarge3"); 360 assertFalse(/a{1,999999999999999999999999999999999999999999999}/.test('b'), 361 "overlarge4"); 362 assertFalse(/a{2147483648}/.test('b'), 363 "overlarge5"); 364 assertFalse(/a{21474836471}/.test('b'), 365 "overlarge6"); 366 assertFalse(/a{1,2147483648}/.test('b'), 367 "overlarge7"); 368 assertFalse(/a{1,21474836471}/.test('b'), 369 "overlarge8"); 370 assertFalse(/a{2147483648,2147483648}/.test('b'), 371 "overlarge9"); 372 assertFalse(/a{21474836471,21474836471}/.test('b'), 373 "overlarge10"); 374 assertFalse(/a{2147483647}/.test('b'), 375 "overlarge11"); 376 assertFalse(/a{1,2147483647}/.test('b'), 377 "overlarge12"); 378 assertTrue(/a{1,2147483647}/.test('a'), 379 "overlarge13"); 380 assertFalse(/a{2147483647,2147483647}/.test('a'), 381 "overlarge14"); 382 383 384 // Check that we don't read past the end of the string. 385 assertFalse(/f/.test('b')); 386 assertFalse(/[abc]f/.test('x')); 387 assertFalse(/[abc]f/.test('xa')); 388 assertFalse(/[abc]</.test('x')); 389 assertFalse(/[abc]</.test('xa')); 390 assertFalse(/f/i.test('b')); 391 assertFalse(/[abc]f/i.test('x')); 392 assertFalse(/[abc]f/i.test('xa')); 393 assertFalse(/[abc]</i.test('x')); 394 assertFalse(/[abc]</i.test('xa')); 395 assertFalse(/f[abc]/.test('x')); 396 assertFalse(/f[abc]/.test('xa')); 397 assertFalse(/<[abc]/.test('x')); 398 assertFalse(/<[abc]/.test('xa')); 399 assertFalse(/f[abc]/i.test('x')); 400 assertFalse(/f[abc]/i.test('xa')); 401 assertFalse(/<[abc]/i.test('x')); 402 assertFalse(/<[abc]/i.test('xa')); 403 404 // Test that merging of quick test masks gets it right. 405 assertFalse(/x([0-7]%%x|[0-6]%%y)/.test('x7%%y'), 'qt'); 406 assertFalse(/()x\1(y([0-7]%%%x|[0-6]%%%y)|dkjasldkas)/.test('xy7%%%y'), 'qt2'); 407 assertFalse(/()x\1(y([0-7]%%%x|[0-6]%%%y)|dkjasldkas)/.test('xy%%%y'), 'qt3'); 408 assertFalse(/()x\1y([0-7]%%%x|[0-6]%%%y)/.test('xy7%%%y'), 'qt4'); 409 assertFalse(/()x\1(y([0-7]%%%x|[0-6]%%%y)|dkjasldkas)/.test('xy%%%y'), 'qt5'); 410 assertFalse(/()x\1y([0-7]%%%x|[0-6]%%%y)/.test('xy7%%%y'), 'qt6'); 411 assertFalse(/xy([0-7]%%%x|[0-6]%%%y)/.test('xy7%%%y'), 'qt7'); 412 assertFalse(/x([0-7]%%%x|[0-6]%%%y)/.test('x7%%%y'), 'qt8'); 413 414 415 // Don't hang on this one. 416 /[^\xfe-\xff]*/.test(""); 417 418 419 var long = "a"; 420 for (var i = 0; i < 100000; i++) { 421 long = "a?" + long; 422 } 423 // Don't crash on this one, but maybe throw an exception. 424 try { 425 RegExp(long).exec("a"); 426 } catch (e) { 427 assertTrue(String(e).indexOf("Stack overflow") >= 0, "overflow"); 428 } 429 430 431 // Test that compile works on modified objects 432 var re = /re+/; 433 assertEquals("re+", re.source); 434 assertFalse(re.global); 435 assertFalse(re.ignoreCase); 436 assertFalse(re.multiline); 437 assertEquals(0, re.lastIndex); 438 439 re.compile("ro+", "gim"); 440 assertEquals("ro+", re.source); 441 assertTrue(re.global); 442 assertTrue(re.ignoreCase); 443 assertTrue(re.multiline); 444 assertEquals(0, re.lastIndex); 445 446 re.lastIndex = 42; 447 re.someOtherProperty = 42; 448 re.someDeletableProperty = 42; 449 re[37] = 37; 450 re[42] = 42; 451 452 re.compile("ra+", "i"); 453 assertEquals("ra+", re.source); 454 assertFalse(re.global); 455 assertTrue(re.ignoreCase); 456 assertFalse(re.multiline); 457 assertEquals(0, re.lastIndex); 458 459 assertEquals(42, re.someOtherProperty); 460 assertEquals(42, re.someDeletableProperty); 461 assertEquals(37, re[37]); 462 assertEquals(42, re[42]); 463 464 re.lastIndex = -1; 465 re.someOtherProperty = 37; 466 re[42] = 37; 467 assertTrue(delete re[37]); 468 assertTrue(delete re.someDeletableProperty); 469 re.compile("ri+", "gm"); 470 471 assertEquals("ri+", re.source); 472 assertTrue(re.global); 473 assertFalse(re.ignoreCase); 474 assertTrue(re.multiline); 475 assertEquals(0, re.lastIndex); 476 assertEquals(37, re.someOtherProperty); 477 assertEquals(37, re[42]); 478 479 // Test boundary-checks. 480 function assertRegExpTest(re, input, test) { 481 assertEquals(test, re.test(input), "test:" + re + ":" + input); 482 } 483 484 assertRegExpTest(/b\b/, "b", true); 485 assertRegExpTest(/b\b$/, "b", true); 486 assertRegExpTest(/\bb/, "b", true); 487 assertRegExpTest(/^\bb/, "b", true); 488 assertRegExpTest(/,\b/, ",", false); 489 assertRegExpTest(/,\b$/, ",", false); 490 assertRegExpTest(/\b,/, ",", false); 491 assertRegExpTest(/^\b,/, ",", false); 492 493 assertRegExpTest(/b\B/, "b", false); 494 assertRegExpTest(/b\B$/, "b", false); 495 assertRegExpTest(/\Bb/, "b", false); 496 assertRegExpTest(/^\Bb/, "b", false); 497 assertRegExpTest(/,\B/, ",", true); 498 assertRegExpTest(/,\B$/, ",", true); 499 assertRegExpTest(/\B,/, ",", true); 500 assertRegExpTest(/^\B,/, ",", true); 501 502 assertRegExpTest(/b\b/, "b,", true); 503 assertRegExpTest(/b\b/, "ba", false); 504 assertRegExpTest(/b\B/, "b,", false); 505 assertRegExpTest(/b\B/, "ba", true); 506 507 assertRegExpTest(/b\Bb/, "bb", true); 508 assertRegExpTest(/b\bb/, "bb", false); 509 510 assertRegExpTest(/b\b[,b]/, "bb", false); 511 assertRegExpTest(/b\B[,b]/, "bb", true); 512 assertRegExpTest(/b\b[,b]/, "b,", true); 513 assertRegExpTest(/b\B[,b]/, "b,", false); 514 515 assertRegExpTest(/[,b]\bb/, "bb", false); 516 assertRegExpTest(/[,b]\Bb/, "bb", true); 517 assertRegExpTest(/[,b]\bb/, ",b", true); 518 assertRegExpTest(/[,b]\Bb/, ",b", false); 519 520 assertRegExpTest(/[,b]\b[,b]/, "bb", false); 521 assertRegExpTest(/[,b]\B[,b]/, "bb", true); 522 assertRegExpTest(/[,b]\b[,b]/, ",b", true); 523 assertRegExpTest(/[,b]\B[,b]/, ",b", false); 524 assertRegExpTest(/[,b]\b[,b]/, "b,", true); 525 assertRegExpTest(/[,b]\B[,b]/, "b,", false); 526 527 // Test that caching of result doesn't share result objects. 528 // More iterations increases the chance of hitting a GC. 529 for (var i = 0; i < 100; i++) { 530 var re = /x(y)z/; 531 var res = re.exec("axyzb"); 532 assertTrue(!!res); 533 assertEquals(2, res.length); 534 assertEquals("xyz", res[0]); 535 assertEquals("y", res[1]); 536 assertEquals(1, res.index); 537 assertEquals("axyzb", res.input); 538 assertEquals(undefined, res.foobar); 539 540 res.foobar = "Arglebargle"; 541 res[3] = "Glopglyf"; 542 assertEquals("Arglebargle", res.foobar); 543 } 544 545 // Test that we perform the spec required conversions in the correct order. 546 var log; 547 var string = "the string"; 548 var fakeLastIndex = { 549 valueOf: function() { 550 log.push("li"); 551 return 0; 552 } 553 }; 554 var fakeString = { 555 toString: function() { 556 log.push("ts"); 557 return string; 558 }, 559 length: 0 560 }; 561 562 var re = /str/; 563 log = []; 564 re.lastIndex = fakeLastIndex; 565 var result = re.exec(fakeString); 566 assertEquals(["str"], result); 567 assertEquals(["ts", "li"], log); 568 569 // Again, to check if caching interferes. 570 log = []; 571 re.lastIndex = fakeLastIndex; 572 result = re.exec(fakeString); 573 assertEquals(["str"], result); 574 assertEquals(["ts", "li"], log); 575 576 // And one more time, just to be certain. 577 log = []; 578 re.lastIndex = fakeLastIndex; 579 result = re.exec(fakeString); 580 assertEquals(["str"], result); 581 assertEquals(["ts", "li"], log); 582 583 // Now with a global regexp, where lastIndex is actually used. 584 re = /str/g; 585 log = []; 586 re.lastIndex = fakeLastIndex; 587 var result = re.exec(fakeString); 588 assertEquals(["str"], result); 589 assertEquals(["ts", "li"], log); 590 591 // Again, to check if caching interferes. 592 log = []; 593 re.lastIndex = fakeLastIndex; 594 result = re.exec(fakeString); 595 assertEquals(["str"], result); 596 assertEquals(["ts", "li"], log); 597 598 // And one more time, just to be certain. 599 log = []; 600 re.lastIndex = fakeLastIndex; 601 result = re.exec(fakeString); 602 assertEquals(["str"], result); 603 assertEquals(["ts", "li"], log); 604 605 606 // Check that properties of RegExp have the correct permissions. 607 var re = /x/g; 608 var desc = Object.getOwnPropertyDescriptor(re, "global"); 609 assertEquals(true, desc.value); 610 assertEquals(false, desc.configurable); 611 assertEquals(false, desc.enumerable); 612 assertEquals(false, desc.writable); 613 614 desc = Object.getOwnPropertyDescriptor(re, "multiline"); 615 assertEquals(false, desc.value); 616 assertEquals(false, desc.configurable); 617 assertEquals(false, desc.enumerable); 618 assertEquals(false, desc.writable); 619 620 desc = Object.getOwnPropertyDescriptor(re, "ignoreCase"); 621 assertEquals(false, desc.value); 622 assertEquals(false, desc.configurable); 623 assertEquals(false, desc.enumerable); 624 assertEquals(false, desc.writable); 625 626 desc = Object.getOwnPropertyDescriptor(re, "lastIndex"); 627 assertEquals(0, desc.value); 628 assertEquals(false, desc.configurable); 629 assertEquals(false, desc.enumerable); 630 assertEquals(true, desc.writable); 631 632 633 // Check that end-anchored regexps are optimized correctly. 634 var re = /(?:a|bc)g$/; 635 assertTrue(re.test("ag")); 636 assertTrue(re.test("bcg")); 637 assertTrue(re.test("abcg")); 638 assertTrue(re.test("zimbag")); 639 assertTrue(re.test("zimbcg")); 640 641 assertFalse(re.test("g")); 642 assertFalse(re.test("")); 643 644 // Global regexp (non-zero start). 645 var re = /(?:a|bc)g$/g; 646 assertTrue(re.test("ag")); 647 re.lastIndex = 1; // Near start of string. 648 assertTrue(re.test("zimbag")); 649 re.lastIndex = 6; // At end of string. 650 assertFalse(re.test("zimbag")); 651 re.lastIndex = 5; // Near end of string. 652 assertFalse(re.test("zimbag")); 653 re.lastIndex = 4; 654 assertTrue(re.test("zimbag")); 655 656 // Anchored at both ends. 657 var re = /^(?:a|bc)g$/g; 658 assertTrue(re.test("ag")); 659 re.lastIndex = 1; 660 assertFalse(re.test("ag")); 661 re.lastIndex = 1; 662 assertFalse(re.test("zag")); 663 664 // Long max_length of RegExp. 665 var re = /VeryLongRegExp!{1,1000}$/; 666 assertTrue(re.test("BahoolaVeryLongRegExp!!!!!!")); 667 assertFalse(re.test("VeryLongRegExp")); 668 assertFalse(re.test("!")); 669 670 // End anchor inside disjunction. 671 var re = /(?:a$|bc$)/; 672 assertTrue(re.test("a")); 673 assertTrue(re.test("bc")); 674 assertTrue(re.test("abc")); 675 assertTrue(re.test("zimzamzumba")); 676 assertTrue(re.test("zimzamzumbc")); 677 assertFalse(re.test("c")); 678 assertFalse(re.test("")); 679 680 // Only partially anchored. 681 var re = /(?:a|bc$)/; 682 assertTrue(re.test("a")); 683 assertTrue(re.test("bc")); 684 assertEquals(["a"], re.exec("abc")); 685 assertEquals(4, re.exec("zimzamzumba").index); 686 assertEquals(["bc"], re.exec("zimzomzumbc")); 687 assertFalse(re.test("c")); 688 assertFalse(re.test("")); 689 690 // Valid syntax in ES5. 691 re = RegExp("(?:x)*"); 692 re = RegExp("(x)*"); 693 694 // Syntax extension relative to ES5, for matching JSC (and ES3). 695 // Shouldn't throw. 696 re = RegExp("(?=x)*"); 697 re = RegExp("(?!x)*"); 698 699 // Should throw. Shouldn't hit asserts in debug mode. 700 assertThrows("RegExp('(*)')"); 701 assertThrows("RegExp('(?:*)')"); 702 assertThrows("RegExp('(?=*)')"); 703 assertThrows("RegExp('(?!*)')"); 704 705 // Test trimmed regular expression for RegExp.test(). 706 assertTrue(/.*abc/.test("abc")); 707 assertFalse(/.*\d+/.test("q")); 708