1 // Copyright 2008 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 var s = "test"; 29 30 function getTwoByteString() { return "\u1234t"; } 31 function getCons() { return "testtesttesttest" + getTwoByteString() } 32 33 var slowIndex1 = { valueOf: function() { return 1; } }; 34 var slowIndex2 = { toString: function() { return "2"; } }; 35 var slowIndexOutOfRange = { valueOf: function() { return -1; } }; 36 37 function basicTest(s, len) { 38 assertEquals("t", s().charAt()); 39 assertEquals("t", s().charAt("string")); 40 assertEquals("t", s().charAt(null)); 41 assertEquals("t", s().charAt(void 0)); 42 assertEquals("t", s().charAt(false)); 43 assertEquals("e", s().charAt(true)); 44 assertEquals("", s().charAt(-1)); 45 assertEquals("", s().charAt(len)); 46 assertEquals("", s().charAt(slowIndexOutOfRange)); 47 assertEquals("", s().charAt(1/0)); 48 assertEquals("", s().charAt(-1/0)); 49 assertEquals("t", s().charAt(0)); 50 assertEquals("t", s().charAt(-0.0)); 51 assertEquals("t", s().charAt(-0.1)); 52 assertEquals("t", s().charAt(0.4)); 53 assertEquals("e", s().charAt(slowIndex1)); 54 assertEquals("s", s().charAt(slowIndex2)); 55 assertEquals("t", s().charAt(3)); 56 assertEquals("t", s().charAt(3.4)); 57 assertEquals("t", s().charAt(NaN)); 58 59 assertEquals(116, s().charCodeAt()); 60 assertEquals(116, s().charCodeAt("string")); 61 assertEquals(116, s().charCodeAt(null)); 62 assertEquals(116, s().charCodeAt(void 0)); 63 assertEquals(116, s().charCodeAt(false)); 64 assertEquals(101, s().charCodeAt(true)); 65 assertEquals(116, s().charCodeAt(0)); 66 assertEquals(116, s().charCodeAt(-0.0)); 67 assertEquals(116, s().charCodeAt(-0.1)); 68 assertEquals(116, s().charCodeAt(0.4)); 69 assertEquals(101, s().charCodeAt(slowIndex1)); 70 assertEquals(115, s().charCodeAt(slowIndex2)); 71 assertEquals(116, s().charCodeAt(3)); 72 assertEquals(116, s().charCodeAt(3.4)); 73 assertEquals(116, s().charCodeAt(NaN)); 74 assertTrue(isNaN(s().charCodeAt(-1))); 75 assertTrue(isNaN(s().charCodeAt(len))); 76 assertTrue(isNaN(s().charCodeAt(slowIndexOutOfRange))); 77 assertTrue(isNaN(s().charCodeAt(1/0))); 78 assertTrue(isNaN(s().charCodeAt(-1/0))); 79 } 80 basicTest(function() { return s; }, s.length); 81 basicTest(getCons, getCons().length); 82 83 // Make sure enough of the one-char string cache is filled. 84 var alpha = ['@']; 85 for (var i = 1; i < 128; i++) { 86 var c = String.fromCharCode(i); 87 alpha[i] = c.charAt(0); 88 } 89 var alphaStr = alpha.join(""); 90 91 // Now test chars. 92 for (var i = 1; i < 128; i++) { 93 assertEquals(alpha[i], alphaStr.charAt(i)); 94 assertEquals(String.fromCharCode(i), alphaStr.charAt(i)); 95 } 96 97 // Test stealing String.prototype.{charAt,charCodeAt}. 98 var o = { 99 charAt: String.prototype.charAt, 100 charCodeAt: String.prototype.charCodeAt, 101 toString: function() { return "012"; }, 102 valueOf: function() { return "should not be called"; } 103 }; 104 105 function stealTest() { 106 assertEquals("0", o.charAt(0)); 107 assertEquals("1", o.charAt(1)); 108 assertEquals("1", o.charAt(1.4)); 109 assertEquals("1", o.charAt(slowIndex1)); 110 assertEquals("2", o.charAt(2)); 111 assertEquals("2", o.charAt(slowIndex2)); 112 assertEquals(48, o.charCodeAt(0)); 113 assertEquals(49, o.charCodeAt(1)); 114 assertEquals(49, o.charCodeAt(1.4)); 115 assertEquals(49, o.charCodeAt(slowIndex1)); 116 assertEquals(50, o.charCodeAt(2)); 117 assertEquals(50, o.charCodeAt(slowIndex2)); 118 assertEquals("", o.charAt(-1)); 119 assertEquals("", o.charAt(-1.4)); 120 assertEquals("", o.charAt(10)); 121 assertEquals("", o.charAt(slowIndexOutOfRange)); 122 assertTrue(isNaN(o.charCodeAt(-1))); 123 assertTrue(isNaN(o.charCodeAt(-1.4))); 124 assertTrue(isNaN(o.charCodeAt(10))); 125 assertTrue(isNaN(o.charCodeAt(slowIndexOutOfRange))); 126 } 127 stealTest(); 128 129 // Test custom string IC-s. 130 for (var i = 0; i < 20; i++) { 131 basicTest(function() { return s; }, s.length); 132 basicTest(getCons, getCons().length); 133 stealTest(); 134 } 135 136 var badToString = function() { return []; }; 137 138 function testBadToString_charAt() { 139 var goodToString = o.toString; 140 var hasCaught = false; 141 var numCalls = 0; 142 var result; 143 try { 144 for (var i = 0; i < 20; i++) { 145 if (i == 10) o.toString = o.valueOf = badToString; 146 result = o.charAt(1); 147 numCalls++; 148 } 149 } catch (e) { 150 hasCaught = true; 151 } finally { 152 o.toString = goodToString; 153 } 154 assertTrue(hasCaught); 155 assertEquals("1", result); 156 assertEquals(10, numCalls); 157 } 158 testBadToString_charAt(); 159 160 function testBadToString_charCodeAt() { 161 var goodToString = o.toString; 162 var hasCaught = false; 163 var numCalls = 0; 164 var result; 165 try { 166 for (var i = 0; i < 20; i++) { 167 if (i == 10) o.toString = o.valueOf = badToString; 168 result = o.charCodeAt(1); 169 numCalls++; 170 } 171 } catch (e) { 172 hasCaught = true; 173 } finally { 174 o.toString = goodToString; 175 } 176 assertTrue(hasCaught); 177 assertEquals(49, result); 178 assertEquals(10, numCalls); 179 } 180 testBadToString_charCodeAt(); 181 182 var badIndex = { 183 toString: badToString, 184 valueOf: badToString 185 }; 186 187 function testBadIndex_charAt() { 188 var index = 1; 189 var hasCaught = false; 190 var numCalls = 0; 191 var result; 192 try { 193 for (var i = 0; i < 20; i++) { 194 if (i == 10) index = badIndex; 195 result = o.charAt(index); 196 numCalls++; 197 } 198 } catch (e) { 199 hasCaught = true; 200 } 201 assertTrue(hasCaught); 202 assertEquals("1", result); 203 assertEquals(10, numCalls); 204 } 205 testBadIndex_charAt(); 206 207 function testBadIndex_charCodeAt() { 208 var index = 1; 209 var hasCaught = false; 210 var numCalls = 0; 211 var result; 212 try { 213 for (var i = 0; i < 20; i++) { 214 if (i == 10) index = badIndex; 215 result = o.charCodeAt(index); 216 numCalls++; 217 } 218 } catch (e) { 219 hasCaught = true; 220 } 221 assertTrue(hasCaught); 222 assertEquals(49, result); 223 assertEquals(10, numCalls); 224 } 225 testBadIndex_charCodeAt(); 226 227 function testPrototypeChange_charAt() { 228 var result, oldResult; 229 for (var i = 0; i < 20; i++) { 230 if (i == 10) { 231 oldResult = result; 232 String.prototype.charAt = function() { return "%"; }; 233 } 234 result = s.charAt(1); 235 } 236 assertEquals("%", result); 237 assertEquals("e", oldResult); 238 delete String.prototype.charAt; // Restore the default. 239 } 240 testPrototypeChange_charAt(); 241 242 function testPrototypeChange_charCodeAt() { 243 var result, oldResult; 244 for (var i = 0; i < 20; i++) { 245 if (i == 10) { 246 oldResult = result; 247 String.prototype.charCodeAt = function() { return 42; }; 248 } 249 result = s.charCodeAt(1); 250 } 251 assertEquals(42, result); 252 assertEquals(101, oldResult); 253 delete String.prototype.charCodeAt; // Restore the default. 254 } 255 testPrototypeChange_charCodeAt(); 256