Home | History | Annotate | Download | only in mjsunit
      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 oneMatch(re) {
     29   "abcd".replace(re, function() { });
     30   assertEquals("abcd", RegExp.input);
     31   assertEquals("a", RegExp.leftContext);
     32   assertEquals("b", RegExp.lastMatch);
     33   assertEquals("", RegExp.lastParen);
     34   assertEquals(undefined, RegExp.lastIndex);
     35   assertEquals(undefined, RegExp.index);
     36   assertEquals("cd", RegExp.rightContext);
     37   for (var i = 1; i < 10; i++) {
     38     assertEquals("", RegExp['$' + i]);
     39   }
     40 }
     41 
     42 oneMatch(/b/);
     43 oneMatch(/b/g);
     44 
     45 "abcdabcd".replace(/b/g, function() { });
     46 assertEquals("abcdabcd", RegExp.input);
     47 assertEquals("abcda", RegExp.leftContext);
     48 assertEquals("b", RegExp.lastMatch);
     49 assertEquals("", RegExp.lastParen);
     50 assertEquals(undefined, RegExp.lastIndex);
     51 assertEquals(undefined, RegExp.index);
     52 assertEquals("cd", RegExp.rightContext);
     53 for (var i = 1; i < 10; i++) {
     54   assertEquals("", RegExp['$' + i]);
     55 }
     56 
     57 function captureMatch(re) {
     58   "abcd".replace(re, function() { });
     59   assertEquals("abcd", RegExp.input);
     60   assertEquals("a", RegExp.leftContext);
     61   assertEquals("bc", RegExp.lastMatch);
     62   assertEquals("c", RegExp.lastParen);
     63   assertEquals(undefined, RegExp.lastIndex);
     64   assertEquals(undefined, RegExp.index);
     65   assertEquals("d", RegExp.rightContext);
     66   assertEquals('b', RegExp.$1);
     67   assertEquals('c', RegExp.$2);
     68   for (var i = 3; i < 10; i++) {
     69     assertEquals("", RegExp['$' + i]);
     70   }
     71 }
     72 
     73 captureMatch(/(b)(c)/);
     74 captureMatch(/(b)(c)/g);
     75 
     76 "abcdabcd".replace(/(b)(c)/g, function() { });
     77 assertEquals("abcdabcd", RegExp.input);
     78 assertEquals("abcda", RegExp.leftContext);
     79 assertEquals("bc", RegExp.lastMatch);
     80 assertEquals("c", RegExp.lastParen);
     81 assertEquals(undefined, RegExp.lastIndex);
     82 assertEquals(undefined, RegExp.index);
     83 assertEquals("d", RegExp.rightContext);
     84 assertEquals('b', RegExp.$1);
     85 assertEquals('c', RegExp.$2);
     86 for (var i = 3; i < 10; i++) {
     87   assertEquals("", RegExp['$' + i]);
     88 }
     89 
     90 
     91 function Override() {
     92   // Set the internal lastMatchInfoOverride.  After calling this we do a normal
     93   // match and verify the override was cleared and that we record the new
     94   // captures.
     95   "abcdabcd".replace(/(b)(c)/g, function() { });
     96 }
     97 
     98 
     99 function TestOverride(input, expect, property, re_src) {
    100   var re = new RegExp(re_src);
    101   var re_g = new RegExp(re_src, "g");
    102 
    103   function OverrideCase(fn) {
    104     Override();
    105     fn();
    106     assertEquals(expect, RegExp[property]);
    107   }
    108 
    109   OverrideCase(function() { return input.replace(re, "x"); });
    110   OverrideCase(function() { return input.replace(re_g, "x"); });
    111   OverrideCase(function() { return input.replace(re, ""); });
    112   OverrideCase(function() { return input.replace(re_g, ""); });
    113   OverrideCase(function() { return input.match(re); });
    114   OverrideCase(function() { return input.match(re_g); });
    115   OverrideCase(function() { return re.test(input); });
    116   OverrideCase(function() { return re_g.test(input); });
    117 }
    118 
    119 var input = "bar.foo baz......";
    120 var re_str = "(ba.).*?f";
    121 TestOverride(input, "bar", "$1", re_str);
    122 
    123 input = "foo bar baz";
    124 var re_str = "bar";
    125 TestOverride(input, "bar", "$&", re_str);
    126 
    127 
    128 function no_last_match(fn) {
    129   fn();
    130   assertEquals("hestfisk", RegExp.$1);
    131 }
    132 
    133 /(hestfisk)/.test("There's no such thing as a hestfisk!");
    134 
    135 no_last_match(function() { "foo".replace("f", ""); });
    136 no_last_match(function() { "foo".replace("f", "f"); });
    137 no_last_match(function() { "foo".split("o"); });
    138 
    139 var base = "In the music.  In the music.  ";
    140 var cons = base + base + base + base;
    141 no_last_match(function() { cons.replace("x", "y"); });
    142 no_last_match(function() { cons.replace("e", "E"); });
    143 
    144 
    145 // Here's one that matches once, then tries to match again, but fails.
    146 // Verify that the last match info is from the last match, not from the
    147 // failure that came after.
    148 "bar.foo baz......".replace(/(ba.).*?f/g, function() { return "x";});
    149 assertEquals("bar", RegExp.$1);
    150 
    151 
    152 // A test that initially does a zero width match, but later does a non-zero
    153 // width match.
    154 var a = "foo bar baz".replace(/^|bar/g, "");
    155 assertEquals("foo  baz", a);
    156 
    157 a = "foo bar baz".replace(/^|bar/g, "*");
    158 assertEquals("*foo * baz", a);
    159 
    160 // We test FilterASCII using regexps that will backtrack forever.  Since
    161 // a regexp with a non-ASCII character in it can never match an ASCII
    162 // string we can test that the relevant node is removed by verifying that
    163 // there is no hang.
    164 function NoHang(re) {
    165   "This is an ASCII string that could take forever".match(re);
    166 }
    167 
    168 NoHang(/(((.*)*)*x)/);  // Continuation after loop is filtered, so is loop.
    169 NoHang(/(((.*)*)*)foo/);  // Body of loop filtered.
    170 NoHang(/(((.*)*)*x)/);   // Everything after a filtered character is filtered.
    171 NoHang(/(((.*)*)*x)/);   // Everything before a filtered character is filtered.
    172 NoHang(/[](((.*)*)*x)/);   // Everything after a filtered class is filtered.
    173 NoHang(/(((.*)*)*x)[]/);   // Everything before a filtered class is filtered.
    174 NoHang(/[^\x00-\xff](((.*)*)*x)/);   // After negated class.
    175 NoHang(/(((.*)*)*x)[^\x00-\xff]/);   // Before negated class.
    176 NoHang(/(?!(((.*)*)*x))foo/);  // Negative lookahead is filtered.
    177 NoHang(/(?!(((.*)*)*x))/);  // Continuation branch of negative lookahead.
    178 NoHang(/(?=(((.*)*)*x))foo/);  // Positive lookahead is filtered.
    179 NoHang(/(?=(((.*)*)*x))/);  // Continuation branch of positive lookahead.
    180 NoHang(/(?=)(((.*)*)*x)/);  // Positive lookahead also prunes continuation.
    181 NoHang(/(||)(((.*)*)*x)/);  // All branches of alternation are filtered.
    182 NoHang(/(a|b|(((.*)*)*x))/);  // 1 out of 3 branches pruned.
    183 NoHang(/(a|(((.*)*)*x)|(((.*)*)*x))/);  // 2 out of 3 branches pruned.
    184 
    185 var s = "Don't prune based on a repetition of length 0";
    186 assertEquals(null, s.match(/{1,1}prune/));
    187 assertEquals("prune", (s.match(/{0,0}prune/)[0]));
    188 
    189 // Some very deep regexps where FilterASCII gives up in order not to make the
    190 // stack overflow.
    191 var regex6 = /a*\u0100*\w/;
    192 var input0 = "a";
    193 regex6.exec(input0);
    194 
    195 var re = "\u0100*\\w";
    196 
    197 for (var i = 0; i < 200; i++) re = "a*" + re;
    198 
    199 var regex7 = new RegExp(re);
    200 regex7.exec(input0);
    201 
    202 var regex8 = new RegExp(re, "i");
    203 regex8.exec(input0);
    204 
    205 re = "[\u0100]*\\w";
    206 for (var i = 0; i < 200; i++) re = "a*" + re;
    207 
    208 var regex9 = new RegExp(re);
    209 regex9.exec(input0);
    210 
    211 var regex10 = new RegExp(re, "i");
    212 regex10.exec(input0);
    213 
    214 var regex11 = /^(?:[^\u0000-\u0080]|[0-9a-z?,.!&\s#()])+$/i;
    215 regex11.exec(input0);
    216 
    217 var regex12 = /u(\xf0{8}?\D*?|( ? !)$h??(|)*?(||)+?\6((?:\W\B|--\d-*-|)?$){0, }?|^Y( ? !1)\d+)+a/;
    218 regex12.exec("");
    219