| // 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(); |