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