description("Test the basic behaviors of String.codePointAt"); shouldBe('String.codePointAt', 'undefined'); shouldBeEqualToString('typeof String.prototype.codePointAt', 'function'); // Function properties. shouldBe('String.prototype.codePointAt.length', '1'); shouldBeEqualToString('String.prototype.codePointAt.name', 'codePointAt') shouldBe('Object.getOwnPropertyDescriptor(String.prototype, "codePointAt").configurable', 'true'); shouldBe('Object.getOwnPropertyDescriptor(String.prototype, "codePointAt").enumerable', 'false'); shouldBe('Object.getOwnPropertyDescriptor(String.prototype, "codePointAt").writable', 'true'); // The function should only be on the prototype chain, not on the object themselves. shouldBeFalse('"foo".hasOwnProperty("codePointAt")'); shouldBeFalse('(new String("bar")).hasOwnProperty("codePointAt")'); // Some simple cases. shouldBe('"".codePointAt(0)', 'undefined'); shouldBe('"".codePointAt(1)', 'undefined'); shouldBe('"Été".codePointAt(0)', '201'); shouldBe('"Été".codePointAt(1)', '116'); shouldBe('"Été".codePointAt(2)', '233'); shouldBe('"Été".codePointAt(3)', 'undefined'); shouldBe('"ウェブキット".codePointAt(0)', '12454'); shouldBe('"ウェブキット".codePointAt(1)', '12455'); shouldBe('"ウェブキット".codePointAt(2)', '12502'); shouldBe('"ウェブキット".codePointAt(3)', '12461'); shouldBe('"ウェブキット".codePointAt(4)', '12483'); shouldBe('"ウェブキット".codePointAt(5)', '12488'); shouldBe('"ウェブキット".codePointAt(6)', 'undefined'); // Object coercion. shouldThrow('"".codePointAt.call(null, 0)'); shouldThrow('"".codePointAt.call(undefined, 0)'); shouldBe('"".codePointAt.call(0, 0)', '48'); shouldBe('"".codePointAt.call(Math.PI, 0)', '51'); shouldBe('"".codePointAt.call(Math.PI, 1)', '46'); shouldBe('"".codePointAt.call(Math.PI, 3)', '52'); shouldBe('"".codePointAt.call(true, 3)', '101'); shouldBe('"".codePointAt.call(false, 3)', '115'); shouldBe('"".codePointAt.call(new Object, 3)', '106'); shouldThrow('"".codePointAt.call(Symbol("WebKit"), 3)'); // toString. var objectWithCustomToString = { toString: function() { return "ø"; } }; shouldBe('"".codePointAt.call(objectWithCustomToString, 0)', '248'); var objectThrowingOnToString = { toString: function() { throw "Hehe"; } }; shouldThrow('"".codePointAt.call(objectThrowingOnToString, 0)'); var objectCountingToString = { counter: 0, toString: function() { ++this.counter; return this.counter; } }; shouldBe('"".codePointAt.call(objectCountingToString, 0)', '49'); shouldBe('objectCountingToString.counter', '1'); // ToNumber. var objectWithCustomValueOf = { toString: function() { return "5"; }, valueOf: function() { return 1; } }; shouldBe('"abcde".codePointAt(objectWithCustomValueOf)', '98'); // The second object is never converted to number if the first object did not convert to string. var objectRecordsValueOf = { valueOfEvaluated: false, valueOf: function() { this.valueOfEvaluated = true; return 1; } } shouldThrow('"".codePointAt.call(null, objectRecordsValueOf)'); shouldThrow('"".codePointAt.call(undefined, objectRecordsValueOf)'); shouldThrow('"".codePointAt.call(Symbol("WebKit"), objectRecordsValueOf)'); shouldThrow('"".codePointAt.call(objectThrowingOnToString, objectRecordsValueOf)'); shouldBeFalse('objectRecordsValueOf.valueOfEvaluated'); // Evaluation order. var evaluationOrderRecorder = { methodsCalled: [], toString: function() { this.methodsCalled.push("toString"); return "foobar"; }, valueOf: function() { this.methodsCalled.push("valueOf"); return 5; } } shouldBe('"".codePointAt.call(evaluationOrderRecorder, evaluationOrderRecorder)', '114'); shouldBeEqualToString('evaluationOrderRecorder.methodsCalled.toString()', 'toString,valueOf'); // Weird positions. shouldBe('"abc".codePointAt(NaN)', '97'); shouldBe('"abc".codePointAt(-0)', '97'); shouldBe('"abc".codePointAt(-0.0)', '97'); shouldBe('"abc".codePointAt(-0.05)', '97'); shouldBe('"abc".codePointAt(-0.999)', '97'); shouldBe('"abc".codePointAt(0.4)', '97'); shouldBe('"abc".codePointAt(0.9)', '97'); shouldBe('"abc".codePointAt(2.9999)', '99'); // Out of bound positions. shouldBe('"abc".codePointAt(-1)', 'undefined'); shouldBe('"abc".codePointAt(4)', 'undefined'); shouldBe('var str = "abc"; str.codePointAt(str.length)', 'undefined'); shouldBe('"abc".codePointAt(4.1)', 'undefined'); shouldBe('"abc".codePointAt(Number.POSITIVE_INFINITY)', 'undefined'); shouldBe('"abc".codePointAt(Number.NEGATIVE_INFINITY)', 'undefined'); // Non-number as positions. shouldBe('"abc".codePointAt(null)', '97'); shouldBe('"abc".codePointAt(undefined)', '97'); shouldBe('"abc".codePointAt("")', '97'); shouldBe('"abc".codePointAt("WebKit!")', '97'); shouldBe('"abc".codePointAt(new Object)', '97'); shouldThrow('"abc".codePointAt(Symbol("WebKit"))'); // The following are using special test functions because of limitations of WebKitTestRunner when handling strings with invalid codepoints. // When transfering the text of a test, WebKitTestRunner converts it to a UTF-8 C String. Not all invalid code point can be represented. // If first < 0xD800 or first > 0xDBFF or position+1 = size, return first. function testLeadSurrogateOutOfBounds() { return ("\uD7FF\uDC00".codePointAt(0) === 0xd7ff && "\uD7FF\uDC00".codePointAt(1) === 0xdc00 && "\uD7FF\uDC00".codePointAt(2) === undefined && "\uDC00\uDC00".codePointAt(0) === 0xdc00 && "\uDC00\uDC00".codePointAt(1) === 0xdc00 && "\uDC00\uDC00".codePointAt(2) === undefined) } shouldBeTrue("testLeadSurrogateOutOfBounds()"); function testLeadSurrogateAsLastCharacter() { return "abc\uD800".codePointAt(3) === 0xd800; } shouldBeTrue("testLeadSurrogateAsLastCharacter()"); // If second < 0xDC00 or second > 0xDFFF, return first. function testTrailSurrogateOutOfbounds() { return ("\uD800\uDBFF".codePointAt(0) === 0xd800 && "\uD800\uDBFF".codePointAt(1) === 0xdbff && "\uD800\uDBFF".codePointAt(2) === undefined && "\uD800\uE000".codePointAt(0) === 0xd800 && "\uD800\uE000".codePointAt(1) === 0xe000 && "\uD800\uE000".codePointAt(2) === undefined) } shouldBeTrue("testTrailSurrogateOutOfbounds()"); // Null in a string. function testAccessNullInString() { return "a\u0000b".codePointAt(0) === 97 && "a\u0000b".codePointAt(1) === 0 && "a\u0000b".codePointAt(2) === 98 && "a\u0000b".codePointAt(3) === undefined; } shouldBeTrue("testAccessNullInString()"); // Normal combinations of surrogates. function testNormalCombinationOfSurrogates() { return "\uD800\uDC00".codePointAt(0) === 65536 && "\uD800\uDC00".codePointAt(1) === 56320 && "\uD800\uDC00".codePointAt(2) === undefined; } shouldBeTrue("testNormalCombinationOfSurrogates()");