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