|
|
|
// Copyright 2008 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.
|
|
|
|
|
|
|
|
var s = "test";
|
|
|
|
|
|
|
|
function getTwoByteString() { return "\u1234t"; }
|
|
|
|
function getCons() { return "testtesttesttest" + getTwoByteString() }
|
|
|
|
|
|
|
|
var slowIndex1 = { valueOf: function() { return 1; } };
|
|
|
|
var slowIndex2 = { toString: function() { return "2"; } };
|
|
|
|
var slowIndexOutOfRange = { valueOf: function() { return -1; } };
|
|
|
|
|
|
|
|
function basicTest(s, len) {
|
|
|
|
assertEquals("t", s().charAt());
|
|
|
|
assertEquals("t", s().charAt("string"));
|
|
|
|
assertEquals("t", s().charAt(null));
|
|
|
|
assertEquals("t", s().charAt(void 0));
|
|
|
|
assertEquals("t", s().charAt(false));
|
|
|
|
assertEquals("e", s().charAt(true));
|
|
|
|
assertEquals("", s().charAt(-1));
|
|
|
|
assertEquals("", s().charAt(len));
|
|
|
|
assertEquals("", s().charAt(slowIndexOutOfRange));
|
|
|
|
assertEquals("", s().charAt(1/0));
|
|
|
|
assertEquals("", s().charAt(-1/0));
|
|
|
|
assertEquals("t", s().charAt(0));
|
|
|
|
assertEquals("t", s().charAt(-0.0));
|
|
|
|
assertEquals("t", s().charAt(-0.1));
|
|
|
|
assertEquals("t", s().charAt(0.4));
|
|
|
|
assertEquals("e", s().charAt(slowIndex1));
|
|
|
|
assertEquals("s", s().charAt(slowIndex2));
|
|
|
|
assertEquals("t", s().charAt(3));
|
|
|
|
assertEquals("t", s().charAt(3.4));
|
|
|
|
assertEquals("t", s().charAt(NaN));
|
|
|
|
|
|
|
|
assertEquals(116, s().charCodeAt());
|
|
|
|
assertEquals(116, s().charCodeAt("string"));
|
|
|
|
assertEquals(116, s().charCodeAt(null));
|
|
|
|
assertEquals(116, s().charCodeAt(void 0));
|
|
|
|
assertEquals(116, s().charCodeAt(false));
|
|
|
|
assertEquals(101, s().charCodeAt(true));
|
|
|
|
assertEquals(116, s().charCodeAt(0));
|
|
|
|
assertEquals(116, s().charCodeAt(-0.0));
|
|
|
|
assertEquals(116, s().charCodeAt(-0.1));
|
|
|
|
assertEquals(116, s().charCodeAt(0.4));
|
|
|
|
assertEquals(101, s().charCodeAt(slowIndex1));
|
|
|
|
assertEquals(115, s().charCodeAt(slowIndex2));
|
|
|
|
assertEquals(116, s().charCodeAt(3));
|
|
|
|
assertEquals(116, s().charCodeAt(3.4));
|
|
|
|
assertEquals(116, s().charCodeAt(NaN));
|
|
|
|
assertTrue(isNaN(s().charCodeAt(-1)));
|
|
|
|
assertTrue(isNaN(s().charCodeAt(len)));
|
|
|
|
assertTrue(isNaN(s().charCodeAt(slowIndexOutOfRange)));
|
|
|
|
assertTrue(isNaN(s().charCodeAt(1/0)));
|
|
|
|
assertTrue(isNaN(s().charCodeAt(-1/0)));
|
|
|
|
}
|
|
|
|
basicTest(function() { return s; }, s.length);
|
|
|
|
basicTest(getCons, getCons().length);
|
|
|
|
|
|
|
|
// Make sure enough of the one-char string cache is filled.
|
|
|
|
var alpha = ['@'];
|
|
|
|
for (var i = 1; i < 128; i++) {
|
|
|
|
var c = String.fromCharCode(i);
|
|
|
|
alpha[i] = c.charAt(0);
|
|
|
|
}
|
|
|
|
var alphaStr = alpha.join("");
|
|
|
|
|
|
|
|
// Now test chars.
|
|
|
|
for (var i = 1; i < 128; i++) {
|
|
|
|
assertEquals(alpha[i], alphaStr.charAt(i));
|
|
|
|
assertEquals(String.fromCharCode(i), alphaStr.charAt(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test stealing String.prototype.{charAt,charCodeAt}.
|
|
|
|
var o = {
|
|
|
|
charAt: String.prototype.charAt,
|
|
|
|
charCodeAt: String.prototype.charCodeAt,
|
|
|
|
toString: function() { return "012"; },
|
|
|
|
valueOf: function() { return "should not be called"; }
|
|
|
|
};
|
|
|
|
|
|
|
|
function stealTest() {
|
|
|
|
assertEquals("0", o.charAt(0));
|
|
|
|
assertEquals("1", o.charAt(1));
|
|
|
|
assertEquals("1", o.charAt(1.4));
|
|
|
|
assertEquals("1", o.charAt(slowIndex1));
|
|
|
|
assertEquals("2", o.charAt(2));
|
|
|
|
assertEquals("2", o.charAt(slowIndex2));
|
|
|
|
assertEquals(48, o.charCodeAt(0));
|
|
|
|
assertEquals(49, o.charCodeAt(1));
|
|
|
|
assertEquals(49, o.charCodeAt(1.4));
|
|
|
|
assertEquals(49, o.charCodeAt(slowIndex1));
|
|
|
|
assertEquals(50, o.charCodeAt(2));
|
|
|
|
assertEquals(50, o.charCodeAt(slowIndex2));
|
|
|
|
assertEquals("", o.charAt(-1));
|
|
|
|
assertEquals("", o.charAt(-1.4));
|
|
|
|
assertEquals("", o.charAt(10));
|
|
|
|
assertEquals("", o.charAt(slowIndexOutOfRange));
|
|
|
|
assertTrue(isNaN(o.charCodeAt(-1)));
|
|
|
|
assertTrue(isNaN(o.charCodeAt(-1.4)));
|
|
|
|
assertTrue(isNaN(o.charCodeAt(10)));
|
|
|
|
assertTrue(isNaN(o.charCodeAt(slowIndexOutOfRange)));
|
|
|
|
}
|
|
|
|
stealTest();
|
|
|
|
|
|
|
|
// Test custom string IC-s.
|
|
|
|
for (var i = 0; i < 20; i++) {
|
|
|
|
basicTest(function() { return s; }, s.length);
|
|
|
|
basicTest(getCons, getCons().length);
|
|
|
|
stealTest();
|
|
|
|
}
|
|
|
|
|
|
|
|
var badToString = function() { return []; };
|
|
|
|
|
|
|
|
function testBadToString_charAt() {
|
|
|
|
var goodToString = o.toString;
|
|
|
|
var hasCaught = false;
|
|
|
|
var numCalls = 0;
|
|
|
|
var result;
|
|
|
|
try {
|
|
|
|
for (var i = 0; i < 20; i++) {
|
|
|
|
if (i == 10) o.toString = o.valueOf = badToString;
|
|
|
|
result = o.charAt(1);
|
|
|
|
numCalls++;
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
hasCaught = true;
|
|
|
|
} finally {
|
|
|
|
o.toString = goodToString;
|
|
|
|
}
|
|
|
|
assertTrue(hasCaught);
|
|
|
|
assertEquals("1", result);
|
|
|
|
assertEquals(10, numCalls);
|
|
|
|
}
|
|
|
|
testBadToString_charAt();
|
|
|
|
|
|
|
|
function testBadToString_charCodeAt() {
|
|
|
|
var goodToString = o.toString;
|
|
|
|
var hasCaught = false;
|
|
|
|
var numCalls = 0;
|
|
|
|
var result;
|
|
|
|
try {
|
|
|
|
for (var i = 0; i < 20; i++) {
|
|
|
|
if (i == 10) o.toString = o.valueOf = badToString;
|
|
|
|
result = o.charCodeAt(1);
|
|
|
|
numCalls++;
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
hasCaught = true;
|
|
|
|
} finally {
|
|
|
|
o.toString = goodToString;
|
|
|
|
}
|
|
|
|
assertTrue(hasCaught);
|
|
|
|
assertEquals(49, result);
|
|
|
|
assertEquals(10, numCalls);
|
|
|
|
}
|
|
|
|
testBadToString_charCodeAt();
|
|
|
|
|
|
|
|
var badIndex = {
|
|
|
|
toString: badToString,
|
|
|
|
valueOf: badToString
|
|
|
|
};
|
|
|
|
|
|
|
|
function testBadIndex_charAt() {
|
|
|
|
var index = 1;
|
|
|
|
var hasCaught = false;
|
|
|
|
var numCalls = 0;
|
|
|
|
var result;
|
|
|
|
try {
|
|
|
|
for (var i = 0; i < 20; i++) {
|
|
|
|
if (i == 10) index = badIndex;
|
|
|
|
result = o.charAt(index);
|
|
|
|
numCalls++;
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
hasCaught = true;
|
|
|
|
}
|
|
|
|
assertTrue(hasCaught);
|
|
|
|
assertEquals("1", result);
|
|
|
|
assertEquals(10, numCalls);
|
|
|
|
}
|
|
|
|
testBadIndex_charAt();
|
|
|
|
|
|
|
|
function testBadIndex_charCodeAt() {
|
|
|
|
var index = 1;
|
|
|
|
var hasCaught = false;
|
|
|
|
var numCalls = 0;
|
|
|
|
var result;
|
|
|
|
try {
|
|
|
|
for (var i = 0; i < 20; i++) {
|
|
|
|
if (i == 10) index = badIndex;
|
|
|
|
result = o.charCodeAt(index);
|
|
|
|
numCalls++;
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
hasCaught = true;
|
|
|
|
}
|
|
|
|
assertTrue(hasCaught);
|
|
|
|
assertEquals(49, result);
|
|
|
|
assertEquals(10, numCalls);
|
|
|
|
}
|
|
|
|
testBadIndex_charCodeAt();
|
|
|
|
|
|
|
|
function testPrototypeChange_charAt() {
|
|
|
|
var result, oldResult;
|
|
|
|
for (var i = 0; i < 20; i++) {
|
|
|
|
if (i == 10) {
|
|
|
|
oldResult = result;
|
|
|
|
String.prototype.charAt = function() { return "%"; };
|
|
|
|
}
|
|
|
|
result = s.charAt(1);
|
|
|
|
}
|
|
|
|
assertEquals("%", result);
|
|
|
|
assertEquals("e", oldResult);
|
|
|
|
delete String.prototype.charAt; // Restore the default.
|
|
|
|
}
|
|
|
|
testPrototypeChange_charAt();
|
|
|
|
|
|
|
|
function testPrototypeChange_charCodeAt() {
|
|
|
|
var result, oldResult;
|
|
|
|
for (var i = 0; i < 20; i++) {
|
|
|
|
if (i == 10) {
|
|
|
|
oldResult = result;
|
|
|
|
String.prototype.charCodeAt = function() { return 42; };
|
|
|
|
}
|
|
|
|
result = s.charCodeAt(1);
|
|
|
|
}
|
|
|
|
assertEquals(42, result);
|
|
|
|
assertEquals(101, oldResult);
|
|
|
|
delete String.prototype.charCodeAt; // Restore the default.
|
|
|
|
}
|
|
|
|
testPrototypeChange_charCodeAt();
|