| // Copyright (c) 2014, the Dart project authors. All rights reserved. |
| // Copyright 2012 the V8 project authors. All rights reserved. |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following |
| // disclaimer in the documentation and/or other materials provided |
| // with the distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived |
| // from this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| import "package:expect/expect.dart"; |
| |
| void testEscape(str, regexp) { |
| assertEquals("foo:bar:baz", str.split(regexp).join(":")); |
| } |
| |
| void assertEquals(actual, expected, [String message = ""]) => |
| Expect.equals(actual, expected, message); |
| void assertTrue(actual, [String message = ""]) => |
| Expect.isTrue(actual, message); |
| void assertFalse(actual, [String message = ""]) => |
| Expect.isFalse(actual, message); |
| void assertThrows(fn) => Expect.throws(fn); |
| |
| void main() { |
| testEscape("foo\nbar\nbaz", new RegExp(r"\n")); |
| testEscape("foo bar baz", new RegExp(r"\s")); |
| testEscape("foo\tbar\tbaz", new RegExp(r"\s")); |
| testEscape("foo-bar-baz", new RegExp(r"\u002D")); |
| |
| // Test containing null char in regexp. |
| var s = '[' + new String.fromCharCode(0) + ']'; |
| var regexp = new RegExp(s); |
| assertEquals(regexp.allMatches(s).length, 1); |
| assertEquals(regexp.stringMatch(s), new String.fromCharCode(0)); |
| |
| final _vmFrame = new RegExp(r'^#\d+\s+(\S.*) \((.+?):(\d+)(?::(\d+))?\)$'); |
| final _traceLine = |
| "#0 Trace.Trace.parse (package:stack_trace/src/trace.dart:130:7)"; |
| Expect.equals(_vmFrame.firstMatch(_traceLine)!.group(0), _traceLine); |
| |
| // Test the UTF16 case insensitive comparison. |
| regexp = new RegExp(r"x(a)\1x", caseSensitive: false); |
| Expect.equals(regexp.firstMatch("xaAx\u1234")!.group(0), "xaAx"); |
| |
| // Test strings containing all line separators |
| s = 'aA\nbB\rcC\r\ndD\u2028eE\u2029fF'; |
| // any non-newline character at the beginning of a line |
| regexp = new RegExp(r"^.", multiLine: true); |
| var result = regexp.allMatches(s).toList(); |
| assertEquals(result.length, 6); |
| assertEquals(result[0][0], 'a'); |
| assertEquals(result[1][0], 'b'); |
| assertEquals(result[2][0], 'c'); |
| assertEquals(result[3][0], 'd'); |
| assertEquals(result[4][0], 'e'); |
| assertEquals(result[5][0], 'f'); |
| |
| // any non-newline character at the end of a line |
| regexp = new RegExp(r".$", multiLine: true); |
| result = regexp.allMatches(s).toList(); |
| assertEquals(result.length, 6); |
| assertEquals(result[0][0], 'A'); |
| assertEquals(result[1][0], 'B'); |
| assertEquals(result[2][0], 'C'); |
| assertEquals(result[3][0], 'D'); |
| assertEquals(result[4][0], 'E'); |
| assertEquals(result[5][0], 'F'); |
| |
| // *any* character at the beginning of a line |
| regexp = new RegExp(r"^[^]", multiLine: true); |
| result = regexp.allMatches(s).toList(); |
| assertEquals(result.length, 7); |
| assertEquals(result[0][0], 'a'); |
| assertEquals(result[1][0], 'b'); |
| assertEquals(result[2][0], 'c'); |
| assertEquals(result[3][0], '\n'); |
| assertEquals(result[4][0], 'd'); |
| assertEquals(result[5][0], 'e'); |
| assertEquals(result[6][0], 'f'); |
| |
| // *any* character at the end of a line |
| regexp = new RegExp(r"[^]$", multiLine: true); |
| result = regexp.allMatches(s).toList(); |
| assertEquals(result.length, 7); |
| assertEquals(result[0][0], 'A'); |
| assertEquals(result[1][0], 'B'); |
| assertEquals(result[2][0], 'C'); |
| assertEquals(result[3][0], '\r'); |
| assertEquals(result[4][0], 'D'); |
| assertEquals(result[5][0], 'E'); |
| assertEquals(result[6][0], 'F'); |
| |
| // Some tests from the Mozilla tests, where our behavior used to differ |
| // from SpiderMonkey. |
| // From ecma_3/RegExp/regress-334158.js |
| assertTrue("\x01".contains(new RegExp(r"\ca"))); |
| assertFalse("\\ca".contains(new RegExp(r"\ca"))); |
| assertFalse("ca".contains(new RegExp(r"\ca"))); |
| assertTrue("\\ca".contains(new RegExp(r"\c[a/]"))); |
| assertTrue("\\c/".contains(new RegExp(r"\c[a/]"))); |
| |
| // Test \c in character class |
| var re = r"^[\cM]$"; |
| assertTrue("\r".contains(new RegExp(re))); |
| assertFalse("M".contains(new RegExp(re))); |
| assertFalse("c".contains(new RegExp(re))); |
| assertFalse("\\".contains(new RegExp(re))); |
| assertFalse("\x03".contains(new RegExp(re))); // I.e., read as \cc |
| |
| re = r"^[\c]]$"; |
| assertTrue("c]".contains(new RegExp(re))); |
| assertTrue("\\]".contains(new RegExp(re))); |
| assertFalse("\x1d".contains(new RegExp(re))); // ']' & 0x1f |
| assertFalse("\x03]".contains(new RegExp(re))); // I.e., read as \cc |
| |
| // Digit control characters are masked in character classes. |
| re = r"^[\c1]$"; |
| assertTrue("\x11".contains(new RegExp(re))); |
| assertFalse("\\".contains(new RegExp(re))); |
| assertFalse("c".contains(new RegExp(re))); |
| assertFalse("1".contains(new RegExp(re))); |
| |
| // Underscore control character is masked in character classes. |
| re = r"^[\c_]$"; |
| assertTrue("\x1f".contains(new RegExp(re))); |
| assertFalse("\\".contains(new RegExp(re))); |
| assertFalse("c".contains(new RegExp(re))); |
| assertFalse("_".contains(new RegExp(re))); |
| |
| re = r"^[\c$]$"; // Other characters are interpreted literally. |
| assertFalse("\x04".contains(new RegExp(re))); |
| assertTrue("\\".contains(new RegExp(re))); |
| assertTrue("c".contains(new RegExp(re))); |
| assertTrue(r"$".contains(new RegExp(re))); |
| |
| assertTrue("Z[\\cde".contains(new RegExp(r"^[Z-\c-e]*$"))); |
| |
| // Test that we handle \s and \S correctly on special Unicode characters. |
| re = r"\s"; |
| assertTrue("\u2028".contains(new RegExp(re))); |
| assertTrue("\u2029".contains(new RegExp(re))); |
| assertTrue("\uFEFF".contains(new RegExp(re))); |
| |
| re = r"\S"; |
| assertFalse("\u2028".contains(new RegExp(re))); |
| assertFalse("\u2029".contains(new RegExp(re))); |
| assertFalse("\uFEFF".contains(new RegExp(re))); |
| |
| // Test that we handle \s and \S correctly inside some bizarre |
| // character classes. |
| re = r"[\s-:]"; |
| assertTrue('-'.contains(new RegExp(re))); |
| assertTrue(':'.contains(new RegExp(re))); |
| assertTrue(' '.contains(new RegExp(re))); |
| assertTrue('\t'.contains(new RegExp(re))); |
| assertTrue('\n'.contains(new RegExp(re))); |
| assertFalse('a'.contains(new RegExp(re))); |
| assertFalse('Z'.contains(new RegExp(re))); |
| |
| re = r"[\S-:]"; |
| assertTrue('-'.contains(new RegExp(re))); |
| assertTrue(':'.contains(new RegExp(re))); |
| assertFalse(' '.contains(new RegExp(re))); |
| assertFalse('\t'.contains(new RegExp(re))); |
| assertFalse('\n'.contains(new RegExp(re))); |
| assertTrue('a'.contains(new RegExp(re))); |
| assertTrue('Z'.contains(new RegExp(re))); |
| |
| re = r"[^\s-:]"; |
| assertFalse('-'.contains(new RegExp(re))); |
| assertFalse(':'.contains(new RegExp(re))); |
| assertFalse(' '.contains(new RegExp(re))); |
| assertFalse('\t'.contains(new RegExp(re))); |
| assertFalse('\n'.contains(new RegExp(re))); |
| assertTrue('a'.contains(new RegExp(re))); |
| assertTrue('Z'.contains(new RegExp(re))); |
| |
| re = r"[^\S-:]"; |
| assertFalse('-'.contains(new RegExp(re))); |
| assertFalse(':'.contains(new RegExp(re))); |
| assertTrue(' '.contains(new RegExp(re))); |
| assertTrue('\t'.contains(new RegExp(re))); |
| assertTrue('\n'.contains(new RegExp(re))); |
| assertFalse('a'.contains(new RegExp(re))); |
| assertFalse('Z'.contains(new RegExp(re))); |
| |
| re = r"[\s]"; |
| assertFalse('-'.contains(new RegExp(re))); |
| assertFalse(':'.contains(new RegExp(re))); |
| assertTrue(' '.contains(new RegExp(re))); |
| assertTrue('\t'.contains(new RegExp(re))); |
| assertTrue('\n'.contains(new RegExp(re))); |
| assertFalse('a'.contains(new RegExp(re))); |
| assertFalse('Z'.contains(new RegExp(re))); |
| |
| re = r"[^\s]"; |
| assertTrue('-'.contains(new RegExp(re))); |
| assertTrue(':'.contains(new RegExp(re))); |
| assertFalse(' '.contains(new RegExp(re))); |
| assertFalse('\t'.contains(new RegExp(re))); |
| assertFalse('\n'.contains(new RegExp(re))); |
| assertTrue('a'.contains(new RegExp(re))); |
| assertTrue('Z'.contains(new RegExp(re))); |
| |
| re = r"[\S]"; |
| assertTrue('-'.contains(new RegExp(re))); |
| assertTrue(':'.contains(new RegExp(re))); |
| assertFalse(' '.contains(new RegExp(re))); |
| assertFalse('\t'.contains(new RegExp(re))); |
| assertFalse('\n'.contains(new RegExp(re))); |
| assertTrue('a'.contains(new RegExp(re))); |
| assertTrue('Z'.contains(new RegExp(re))); |
| |
| re = r"[^\S]"; |
| assertFalse('-'.contains(new RegExp(re))); |
| assertFalse(':'.contains(new RegExp(re))); |
| assertTrue(' '.contains(new RegExp(re))); |
| assertTrue('\t'.contains(new RegExp(re))); |
| assertTrue('\n'.contains(new RegExp(re))); |
| assertFalse('a'.contains(new RegExp(re))); |
| assertFalse('Z'.contains(new RegExp(re))); |
| |
| re = r"[\s\S]"; |
| assertTrue('-'.contains(new RegExp(re))); |
| assertTrue(':'.contains(new RegExp(re))); |
| assertTrue(' '.contains(new RegExp(re))); |
| assertTrue('\t'.contains(new RegExp(re))); |
| assertTrue('\n'.contains(new RegExp(re))); |
| assertTrue('a'.contains(new RegExp(re))); |
| assertTrue('Z'.contains(new RegExp(re))); |
| |
| re = r"[^\s\S]"; |
| assertFalse('-'.contains(new RegExp(re))); |
| assertFalse(':'.contains(new RegExp(re))); |
| assertFalse(' '.contains(new RegExp(re))); |
| assertFalse('\t'.contains(new RegExp(re))); |
| assertFalse('\n'.contains(new RegExp(re))); |
| assertFalse('a'.contains(new RegExp(re))); |
| assertFalse('Z'.contains(new RegExp(re))); |
| |
| // First - is treated as range operator, second as literal minus. |
| // This follows the specification in parsing, but doesn't throw on |
| // the \s at the beginning of the range. |
| re = r"[\s-0-9]"; |
| assertTrue(' '.contains(new RegExp(re))); |
| assertTrue('\xA0'.contains(new RegExp(re))); |
| assertTrue('-'.contains(new RegExp(re))); |
| assertTrue('0'.contains(new RegExp(re))); |
| assertTrue('9'.contains(new RegExp(re))); |
| assertFalse('1'.contains(new RegExp(re))); |
| |
| // Test beginning and end of line assertions with or without the |
| // multiline flag. |
| re = r"^\d+"; |
| assertFalse("asdf\n123".contains(new RegExp(re))); |
| regexp = new RegExp(r"^\d+", multiLine: true); |
| assertTrue("asdf\n123".contains(regexp)); |
| |
| re = r"\d+$"; |
| assertFalse("123\nasdf".contains(new RegExp(re))); |
| regexp = new RegExp(r"\d+$", multiLine: true); |
| assertTrue("123\nasdf".contains(regexp)); |
| |
| // Test that empty matches are handled correctly for multiline global |
| // regexps. |
| regexp = new RegExp(r"^(.*)", multiLine: true); |
| assertEquals(3, regexp.allMatches("a\n\rb").length); |
| assertEquals( |
| "*a\n*b\r*c\n*\r*d\r*\n*e", |
| "a\nb\rc\n\rd\r\ne" |
| .replaceAllMapped(regexp, (Match m) => "*${m.group(1)}")); |
| |
| // Test that empty matches advance one character |
| regexp = new RegExp(""); |
| assertEquals("xAx", "A".replaceAll(regexp, "x")); |
| assertEquals(3, new String.fromCharCode(161).replaceAll(regexp, "x").length); |
| |
| // Check for lazy RegExp literal cregexpation |
| lazyLiteral(doit) { |
| if (doit) |
| return "".replaceAll(new RegExp(r"foo(", caseSensitive: false), ""); |
| return true; |
| } |
| |
| assertTrue(lazyLiteral(false)); |
| assertThrows(() => lazyLiteral(true)); |
| |
| // Check $01 and $10 |
| regexp = new RegExp("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)"); |
| assertEquals( |
| "t", "123456789t".replaceAllMapped(regexp, (Match m) => m.group(10)!)); |
| assertEquals("15", |
| "123456789t".replaceAllMapped(regexp, (Match m) => "${m.group(1)}5")); |
| assertEquals( |
| "1", "123456789t".replaceAllMapped(regexp, (Match m) => m.group(1)!)); |
| |
| assertFalse("football".contains(new RegExp(r"()foo$\1")), "football1"); |
| assertFalse("football".contains(new RegExp(r"foo$(?=ball)")), "football2"); |
| assertFalse("football".contains(new RegExp(r"foo$(?!bar)")), "football3"); |
| assertTrue("foo".contains(new RegExp(r"()foo$\1")), "football4"); |
| assertTrue("foo".contains(new RegExp(r"foo$(?=(ball)?)")), "football5"); |
| assertTrue("foo".contains(new RegExp(r"()foo$(?!bar)")), "football6"); |
| assertFalse("football".contains(new RegExp(r"(x?)foo$\1")), "football7"); |
| assertFalse("football".contains(new RegExp(r"foo$(?=ball)")), "football8"); |
| assertFalse("football".contains(new RegExp(r"foo$(?!bar)")), "football9"); |
| assertTrue("foo".contains(new RegExp(r"(x?)foo$\1")), "football10"); |
| assertTrue("foo".contains(new RegExp(r"foo$(?=(ball)?)")), "football11"); |
| assertTrue("foo".contains(new RegExp(r"foo$(?!bar)")), "football12"); |
| |
| // Check that the back reference has two successors. See |
| // BackReferenceNode::PropagateForward. |
| assertFalse('foo'.contains(new RegExp(r"f(o)\b\1"))); |
| assertTrue('foo'.contains(new RegExp(r"f(o)\B\1"))); |
| |
| // Back-reference, ignore case: |
| // ASCII |
| assertEquals( |
| "a", |
| new RegExp(r"x(a)\1x", caseSensitive: false).firstMatch("xaAx")!.group(1), |
| "backref-ASCII"); |
| assertFalse("xaaaaa".contains(new RegExp(r"x(...)\1", caseSensitive: false)), |
| "backref-ASCII-short"); |
| assertTrue("xx".contains(new RegExp(r"x((?:))\1\1x", caseSensitive: false)), |
| "backref-ASCII-empty"); |
| assertTrue( |
| "xabcx".contains(new RegExp(r"x(?:...|(...))\1x", caseSensitive: false)), |
| "backref-ASCII-uncaptured"); |
| assertTrue( |
| "xabcABCx" |
| .contains(new RegExp(r"x(?:...|(...))\1x", caseSensitive: false)), |
| "backref-ASCII-backtrack"); |
| assertEquals( |
| "aBc", |
| new RegExp(r"x(...)\1\1x", caseSensitive: false) |
| .firstMatch("xaBcAbCABCx")! |
| .group(1), |
| "backref-ASCII-twice"); |
| |
| for (var i = 0; i < 128; i++) { |
| var testName = "backref-ASCII-char-$i,,${i^0x20}"; |
| var test = new String.fromCharCodes([i, i ^ 0x20]) |
| .contains(new RegExp(r"^(.)\1$", caseSensitive: false)); |
| if (('A'.codeUnitAt(0) <= i && i <= 'Z'.codeUnitAt(0)) || |
| ('a'.codeUnitAt(0) <= i && i <= 'z'.codeUnitAt(0))) { |
| assertTrue(test, testName); |
| } else { |
| assertFalse(test, testName); |
| } |
| } |
| |
| assertFalse('foo'.contains(new RegExp(r"f(o)$\1")), "backref detects at_end"); |
| |
| // Check decimal escapes doesn't overflow. |
| // (Note: \214 is interpreted as octal). |
| assertEquals( |
| "\x8c7483648", |
| new RegExp(r"\2147483648").firstMatch("\x8c7483648")!.group(0), |
| "Overflow decimal escape"); |
| |
| // Check numbers in quantifiers doesn't overflow and doesn't throw on |
| // too large numbers. |
| assertFalse( |
| 'b'.contains( |
| new RegExp(r"a{111111111111111111111111111111111111111111111}")), |
| "overlarge1"); |
| assertFalse( |
| 'b'.contains( |
| new RegExp(r"a{999999999999999999999999999999999999999999999}")), |
| "overlarge2"); |
| assertFalse( |
| 'b'.contains( |
| new RegExp(r"a{1,111111111111111111111111111111111111111111111}")), |
| "overlarge3"); |
| assertFalse( |
| 'b'.contains( |
| new RegExp(r"a{1,999999999999999999999999999999999999999999999}")), |
| "overlarge4"); |
| assertFalse('b'.contains(new RegExp(r"a{2147483648}")), "overlarge5"); |
| assertFalse('b'.contains(new RegExp(r"a{21474836471}")), "overlarge6"); |
| assertFalse('b'.contains(new RegExp(r"a{1,2147483648}")), "overlarge7"); |
| assertFalse('b'.contains(new RegExp(r"a{1,21474836471}")), "overlarge8"); |
| assertFalse( |
| 'b'.contains(new RegExp(r"a{2147483648,2147483648}")), "overlarge9"); |
| assertFalse( |
| 'b'.contains(new RegExp(r"a{21474836471,21474836471}")), "overlarge10"); |
| assertFalse('b'.contains(new RegExp(r"a{2147483647}")), "overlarge11"); |
| assertFalse('b'.contains(new RegExp(r"a{1,2147483647}")), "overlarge12"); |
| assertTrue('a'.contains(new RegExp(r"a{1,2147483647}")), "overlarge13"); |
| assertFalse( |
| 'a'.contains(new RegExp(r"a{2147483647,2147483647}")), "overlarge14"); |
| |
| // Check that we don't repad past the end of the string. |
| assertFalse('b'.contains(new RegExp(r"f"))); |
| assertFalse('x'.contains(new RegExp(r"[abc]f"))); |
| assertFalse('xa'.contains(new RegExp(r"[abc]f"))); |
| assertFalse('x'.contains(new RegExp(r"[abc]<"))); |
| assertFalse('xa'.contains(new RegExp(r"[abc]<"))); |
| assertFalse('b'.contains(new RegExp(r"f", caseSensitive: false))); |
| assertFalse('x'.contains(new RegExp(r"[abc]f", caseSensitive: false))); |
| assertFalse('xa'.contains(new RegExp(r"[abc]f", caseSensitive: false))); |
| assertFalse('x'.contains(new RegExp(r"[abc]<", caseSensitive: false))); |
| assertFalse('xa'.contains(new RegExp(r"[abc]<", caseSensitive: false))); |
| assertFalse('x'.contains(new RegExp(r"f[abc]"))); |
| assertFalse('xa'.contains(new RegExp(r"f[abc]"))); |
| assertFalse('x'.contains(new RegExp(r"<[abc]"))); |
| assertFalse('xa'.contains(new RegExp(r"<[abc]"))); |
| assertFalse('x'.contains(new RegExp(r"f[abc]", caseSensitive: false))); |
| assertFalse('xa'.contains(new RegExp(r"f[abc]", caseSensitive: false))); |
| assertFalse('x'.contains(new RegExp(r"<[abc]", caseSensitive: false))); |
| assertFalse('xa'.contains(new RegExp(r"<[abc]", caseSensitive: false))); |
| |
| // Test that merging of quick test masks gets it right. |
| assertFalse('x7%%y'.contains(new RegExp(r"x([0-7]%%x|[0-6]%%y)")), 'qt'); |
| assertFalse( |
| 'xy7%%%y' |
| .contains(new RegExp(r"()x\1(y([0-7]%%%x|[0-6]%%%y)|dkjasldkas)")), |
| 'qt2'); |
| assertFalse( |
| 'xy%%%y' |
| .contains(new RegExp(r"()x\1(y([0-7]%%%x|[0-6]%%%y)|dkjasldkas)")), |
| 'qt3'); |
| assertFalse( |
| 'xy7%%%y'.contains(new RegExp(r"()x\1y([0-7]%%%x|[0-6]%%%y)")), 'qt4'); |
| assertFalse( |
| 'xy%%%y' |
| .contains(new RegExp(r"()x\1(y([0-7]%%%x|[0-6]%%%y)|dkjasldkas)")), |
| 'qt5'); |
| assertFalse( |
| 'xy7%%%y'.contains(new RegExp(r"()x\1y([0-7]%%%x|[0-6]%%%y)")), 'qt6'); |
| assertFalse( |
| 'xy7%%%y'.contains(new RegExp(r"xy([0-7]%%%x|[0-6]%%%y)")), 'qt7'); |
| assertFalse('x7%%%y'.contains(new RegExp(r"x([0-7]%%%x|[0-6]%%%y)")), 'qt8'); |
| |
| // Don't hang on this one. |
| "".contains(new RegExp(r"[^\xfe-\xff]*")); |
| |
| var longbuffer = new StringBuffer("a"); |
| for (var i = 0; i < 100000; i++) { |
| longbuffer.write("a?"); |
| } |
| var long = longbuffer.toString(); |
| |
| // Don't crash on this one, but maybe throw an exception. |
| try { |
| new RegExp(long).allMatches("a"); |
| } catch (e) { |
| assertTrue(e.toString().indexOf("Stack overflow") >= 0, "overflow"); |
| } |
| |
| // Test boundary-checks. |
| void assertRegExpTest(re, input, test) { |
| assertEquals( |
| test, input.contains(new RegExp(re)), "test:" + re + ":" + input); |
| } |
| |
| assertRegExpTest(r"b\b", "b", true); |
| assertRegExpTest(r"b\b$", "b", true); |
| assertRegExpTest(r"\bb", "b", true); |
| assertRegExpTest(r"^\bb", "b", true); |
| assertRegExpTest(r",\b", ",", false); |
| assertRegExpTest(r",\b$", ",", false); |
| assertRegExpTest(r"\b,", ",", false); |
| assertRegExpTest(r"^\b,", ",", false); |
| |
| assertRegExpTest(r"b\B", "b", false); |
| assertRegExpTest(r"b\B$", "b", false); |
| assertRegExpTest(r"\Bb", "b", false); |
| assertRegExpTest(r"^\Bb", "b", false); |
| assertRegExpTest(r",\B", ",", true); |
| assertRegExpTest(r",\B$", ",", true); |
| assertRegExpTest(r"\B,", ",", true); |
| assertRegExpTest(r"^\B,", ",", true); |
| |
| assertRegExpTest(r"b\b", "b,", true); |
| assertRegExpTest(r"b\b", "ba", false); |
| assertRegExpTest(r"b\B", "b,", false); |
| assertRegExpTest(r"b\B", "ba", true); |
| |
| assertRegExpTest(r"b\Bb", "bb", true); |
| assertRegExpTest(r"b\bb", "bb", false); |
| |
| assertRegExpTest(r"b\b[,b]", "bb", false); |
| assertRegExpTest(r"b\B[,b]", "bb", true); |
| assertRegExpTest(r"b\b[,b]", "b,", true); |
| assertRegExpTest(r"b\B[,b]", "b,", false); |
| |
| assertRegExpTest(r"[,b]\bb", "bb", false); |
| assertRegExpTest(r"[,b]\Bb", "bb", true); |
| assertRegExpTest(r"[,b]\bb", ",b", true); |
| assertRegExpTest(r"[,b]\Bb", ",b", false); |
| |
| assertRegExpTest(r"[,b]\b[,b]", "bb", false); |
| assertRegExpTest(r"[,b]\B[,b]", "bb", true); |
| assertRegExpTest(r"[,b]\b[,b]", ",b", true); |
| assertRegExpTest(r"[,b]\B[,b]", ",b", false); |
| assertRegExpTest(r"[,b]\b[,b]", "b,", true); |
| assertRegExpTest(r"[,b]\B[,b]", "b,", false); |
| |
| // Skipped tests from V8: |
| |
| // Test that caching of result doesn't share result objects. |
| // More iterations increases the chance of hitting a GC. |
| |
| // Test that we perform the spec required conversions in the correct order. |
| |
| // Check that properties of RegExp have the correct permissions. |
| |
| // Check that end-anchored regexps are optimized correctly. |
| re = r"(?:a|bc)g$"; |
| assertTrue("ag".contains(new RegExp(re))); |
| assertTrue("bcg".contains(new RegExp(re))); |
| assertTrue("abcg".contains(new RegExp(re))); |
| assertTrue("zimbag".contains(new RegExp(re))); |
| assertTrue("zimbcg".contains(new RegExp(re))); |
| |
| assertFalse("g".contains(new RegExp(re))); |
| assertFalse("".contains(new RegExp(re))); |
| |
| // Global regexp (non-zero start). |
| re = r"(?:a|bc)g$"; |
| assertTrue("ag".contains(new RegExp(re))); |
| // Near start of string. |
| assertTrue(new RegExp(re).allMatches("zimbag", 1).isNotEmpty); |
| // At end of string. |
| assertTrue(new RegExp(re).allMatches("zimbag", 6).isEmpty); |
| // Near end of string. |
| assertTrue(new RegExp(re).allMatches("zimbag", 5).isEmpty); |
| assertTrue(new RegExp(re).allMatches("zimbag", 4).isNotEmpty); |
| |
| // Anchored at both ends. |
| re = r"^(?:a|bc)g$"; |
| assertTrue("ag".contains(new RegExp(re))); |
| assertTrue(new RegExp(re).allMatches("ag", 1).isEmpty); |
| assertTrue(new RegExp(re).allMatches("zag", 1).isEmpty); |
| |
| // Long max_length of RegExp. |
| re = r"VeryLongRegExp!{1,1000}$"; |
| assertTrue("BahoolaVeryLongRegExp!!!!!!".contains(new RegExp(re))); |
| assertFalse("VeryLongRegExp".contains(new RegExp(re))); |
| assertFalse("!".contains(new RegExp(re))); |
| |
| // End anchor inside disjunction. |
| re = r"(?:a$|bc$)"; |
| assertTrue("a".contains(new RegExp(re))); |
| assertTrue("bc".contains(new RegExp(re))); |
| assertTrue("abc".contains(new RegExp(re))); |
| assertTrue("zimzamzumba".contains(new RegExp(re))); |
| assertTrue("zimzamzumbc".contains(new RegExp(re))); |
| assertFalse("c".contains(new RegExp(re))); |
| assertFalse("".contains(new RegExp(re))); |
| |
| // Only partially anchored. |
| re = r"(?:a|bc$)"; |
| assertTrue("a".contains(new RegExp(re))); |
| assertTrue("bc".contains(new RegExp(re))); |
| assertEquals("a", new RegExp(re).firstMatch("abc")!.group(0)); |
| assertEquals(4, new RegExp(re).firstMatch("zimzamzumba")!.start); |
| assertEquals("bc", new RegExp(re).firstMatch("zimzomzumbc")!.group(0)); |
| assertFalse("c".contains(new RegExp(re))); |
| assertFalse("".contains(new RegExp(re))); |
| |
| // Valid syntax in ES5. |
| regexp = new RegExp("(?:x)*"); |
| regexp = new RegExp("(x)*"); |
| |
| // Syntax extension relative to ES5, for matching JSC (and ES3). |
| // Shouldn't throw. |
| regexp = new RegExp("(?=x)*"); |
| regexp = new RegExp("(?!x)*"); |
| |
| // Should throw. Shouldn't hit asserts in debug mode. |
| assertThrows(() => new RegExp('(*)')); |
| assertThrows(() => new RegExp('(?:*)')); |
| assertThrows(() => new RegExp('(?=*)')); |
| assertThrows(() => new RegExp('(?!*)')); |
| |
| // Test trimmed regular expression for RegExp.test(). |
| assertTrue("abc".contains(new RegExp(r".*abc"))); |
| assertFalse("q".contains(new RegExp(r".*\d+"))); |
| |
| // Tests skipped from V8: |
| // Test that RegExp.prototype.toString() throws TypeError for |
| // incompatible receivers (ES5 section 15.10.6 and 15.10.6.4). |
| testSticky(); |
| } |
| |
| testSticky() { |
| var regexp = new RegExp(r"foo.bar"); |
| Expect.isNotNull(regexp.matchAsPrefix("foo_bar", 0)); |
| Expect.isNull(regexp.matchAsPrefix("..foo_bar", 0)); |
| Expect.isNotNull(regexp.matchAsPrefix("..foo_bar", 2)); |
| |
| regexp = new RegExp(r"^foo"); |
| Expect.isNotNull(regexp.matchAsPrefix("foobar", 0)); |
| Expect.isNull(regexp.matchAsPrefix("..foo", 0)); |
| Expect.isNull(regexp.matchAsPrefix("..foo", 2)); |
| |
| regexp = new RegExp(r"^foo", multiLine: true); |
| Expect.isNotNull(regexp.matchAsPrefix("foobar", 0)); |
| Expect.isNull(regexp.matchAsPrefix("..\nfoo", 0)); |
| Expect.isNotNull(regexp.matchAsPrefix("..\nfoo", 3)); |
| Expect.isNull(regexp.matchAsPrefix("..\nfoofoo", 6)); |
| |
| regexp = new RegExp(r"bar$"); |
| Expect.isNull(regexp.matchAsPrefix("foobar", 0)); |
| Expect.isNotNull(regexp.matchAsPrefix("foobar", 3)); |
| } |