1// Copyright 2009 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// Tests captures in positive and negative look-ahead in regular expressions. 29 30function stringEscape(string) { 31 // Converts string to source literal. 32 return '"' + string.replace(/["\\]/g, "\\$1") + '"'; 33} 34 35function testRE(re, input, expected_result) { 36 var testName = re + ".test(" + stringEscape(input) +")"; 37 if (expected_result) { 38 assertTrue(re.test(input), testName); 39 } else { 40 assertFalse(re.test(input), testName); 41 } 42} 43 44function execRE(re, input, expected_result) { 45 var testName = re + ".exec('" + stringEscape(input) +"')"; 46 assertEquals(expected_result, re.exec(input), testName); 47} 48 49// Test of simple positive lookahead. 50 51var re = /^(?=a)/; 52testRE(re, "a", true); 53testRE(re, "b", false); 54execRE(re, "a", [""]); 55 56re = /^(?=\woo)f\w/; 57testRE(re, "foo", true); 58testRE(re, "boo", false); 59testRE(re, "fao", false); 60testRE(re, "foa", false); 61execRE(re, "foo", ["fo"]); 62 63re = /(?=\w).(?=\W)/; 64testRE(re, ".a! ", true); 65testRE(re, ".! ", false); 66testRE(re, ".ab! ", true); 67execRE(re, ".ab! ", ["b"]); 68 69re = /(?=f(?=[^f]o))../; 70testRE(re, ", foo!", true); 71testRE(re, ", fo!", false); 72testRE(re, ", ffo", false); 73execRE(re, ", foo!", ["fo"]); 74 75// Positive lookahead with captures. 76re = /^[^\'\"]*(?=([\'\"])).*\1(\w+)\1/; 77testRE(re, " 'foo' ", true); 78testRE(re, ' "foo" ', true); 79testRE(re, " \" 'foo' ", false); 80testRE(re, " ' \"foo\" ", false); 81testRE(re, " 'foo\" ", false); 82testRE(re, " \"foo' ", false); 83execRE(re, " 'foo' ", [" 'foo'", "'", "foo"]); 84execRE(re, ' "foo" ', [' "foo"', '"', 'foo']); 85 86// Captures are cleared on backtrack past the look-ahead. 87re = /^(?:(?=(.))a|b)\1$/; 88testRE(re, "aa", true); 89testRE(re, "b", true); 90testRE(re, "bb", false); 91testRE(re, "a", false); 92execRE(re, "aa", ["aa", "a"]); 93execRE(re, "b", ["b", undefined]); 94 95re = /^(?=(.)(?=(.)\1\2)\2\1)\1\2/; 96testRE(re, "abab", true); 97testRE(re, "ababxxxxxxxx", true); 98testRE(re, "aba", false); 99execRE(re, "abab", ["ab", "a", "b"]); 100 101re = /^(?:(?=(.))a|b|c)$/; 102testRE(re, "a", true); 103testRE(re, "b", true); 104testRE(re, "c", true); 105testRE(re, "d", false); 106execRE(re, "a", ["a", "a"]); 107execRE(re, "b", ["b", undefined]); 108execRE(re, "c", ["c", undefined]); 109 110execRE(/^(?=(b))b/, "b", ["b", "b"]); 111execRE(/^(?:(?=(b))|a)b/, "ab", ["ab", undefined]); 112execRE(/^(?:(?=(b)(?:(?=(c))|d))|)bd/, "bd", ["bd", "b", undefined]); 113 114 115 116// Test of Negative Look-Ahead. 117 118re = /(?!x)./; 119testRE(re, "y", true); 120testRE(re, "x", false); 121execRE(re, "y", ["y"]); 122 123re = /(?!(\d))|\d/; 124testRE(re, "4", true); 125execRE(re, "4", ["4", undefined]); 126execRE(re, "x", ["", undefined]); 127 128 129// Test mixed nested look-ahead with captures. 130 131re = /^(?=(x)(?=(y)))/; 132testRE(re, "xy", true); 133testRE(re, "xz", false); 134execRE(re, "xy", ["", "x", "y"]); 135 136re = /^(?!(x)(?!(y)))/; 137testRE(re, "xy", true); 138testRE(re, "xz", false); 139execRE(re, "xy", ["", undefined, undefined]); 140 141re = /^(?=(x)(?!(y)))/; 142testRE(re, "xz", true); 143testRE(re, "xy", false) 144execRE(re, "xz", ["", "x", undefined]); 145 146re = /^(?!(x)(?=(y)))/; 147testRE(re, "xz", true); 148testRE(re, "xy", false); 149execRE(re, "xz", ["", undefined, undefined]); 150 151re = /^(?=(x)(?!(y)(?=(z))))/; 152testRE(re, "xaz", true); 153testRE(re, "xya", true); 154testRE(re, "xyz", false); 155testRE(re, "a", false); 156execRE(re, "xaz", ["", "x", undefined, undefined]); 157execRE(re, "xya", ["", "x", undefined, undefined]); 158 159re = /^(?!(x)(?=(y)(?!(z))))/; 160testRE(re, "a", true); 161testRE(re, "xa", true); 162testRE(re, "xyz", true); 163testRE(re, "xya", false); 164execRE(re, "a", ["", undefined, undefined, undefined]); 165execRE(re, "xa", ["", undefined, undefined, undefined]); 166execRE(re, "xyz", ["", undefined, undefined, undefined]); 167