Title: [198674] trunk
Revision
198674
Author
[email protected]
Date
2016-03-25 10:37:48 -0700 (Fri, 25 Mar 2016)

Log Message

[JSC] implement String.prototype.padStart() and String.prototype.padEnd() proposal
https://bugs.webkit.org/show_bug.cgi?id=155795

Patch by Caitlin Potter <[email protected]> on 2016-03-25
Reviewed by Darin Adler.

Source/_javascript_Core:

Implements ECMAScript proposal http://tc39.github.io/proposal-string-pad-start-end/
Currently at Stage 3.

* runtime/JSString.h:
* runtime/StringPrototype.cpp:
(JSC::StringPrototype::finishCreation):
(JSC::repeatCharacter):
(JSC::repeatStringPattern):
(JSC::padString):
(JSC::stringProtoFuncPadEnd):
(JSC::stringProtoFuncPadStart):
* tests/es6.yaml:
* tests/es6/String.prototype_methods_String.prototype.padEnd.js: Added.
* tests/es6/String.prototype_methods_String.prototype.padStart.js: Added.

LayoutTests:

* js/Object-getOwnPropertyNames-expected.txt:
* js/script-tests/Object-getOwnPropertyNames.js:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (198673 => 198674)


--- trunk/LayoutTests/ChangeLog	2016-03-25 17:24:33 UTC (rev 198673)
+++ trunk/LayoutTests/ChangeLog	2016-03-25 17:37:48 UTC (rev 198674)
@@ -1,3 +1,13 @@
+2016-03-25  Caitlin Potter  <[email protected]>
+
+        [JSC] implement String.prototype.padStart() and String.prototype.padEnd() proposal
+        https://bugs.webkit.org/show_bug.cgi?id=155795
+
+        Reviewed by Darin Adler.
+
+        * js/Object-getOwnPropertyNames-expected.txt:
+        * js/script-tests/Object-getOwnPropertyNames.js:
+
 2016-03-25  Youenn Fablet  <[email protected]>
 
         [Fetch API] Add basic loading of resources

Modified: trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt (198673 => 198674)


--- trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt	2016-03-25 17:24:33 UTC (rev 198673)
+++ trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt	2016-03-25 17:37:48 UTC (rev 198674)
@@ -48,7 +48,7 @@
 PASS getSortedOwnPropertyNames(Array) is ['from', 'isArray', 'length', 'name', 'of', 'prototype']
 PASS getSortedOwnPropertyNames(Array.prototype) is ['concat', 'constructor', 'copyWithin', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'forEach', 'includes', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift', 'values']
 PASS getSortedOwnPropertyNames(String) is ['fromCharCode', 'fromCodePoint', 'length', 'name', 'prototype', 'raw']
-PASS getSortedOwnPropertyNames(String.prototype) is ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'codePointAt', 'concat', 'constructor', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'includes', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'normalize', 'repeat', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']
+PASS getSortedOwnPropertyNames(String.prototype) is ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'codePointAt', 'concat', 'constructor', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'includes', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'normalize', 'padEnd', 'padStart', 'repeat', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']
 PASS getSortedOwnPropertyNames(Boolean) is ['length', 'name', 'prototype']
 PASS getSortedOwnPropertyNames(Boolean.prototype) is ['constructor', 'toString', 'valueOf']
 PASS getSortedOwnPropertyNames(Number) is ['EPSILON', 'MAX_SAFE_INTEGER', 'MAX_VALUE', 'MIN_SAFE_INTEGER', 'MIN_VALUE', 'NEGATIVE_INFINITY', 'NaN', 'POSITIVE_INFINITY', 'isFinite', 'isInteger', 'isNaN', 'isSafeInteger', 'length', 'name', 'parseFloat', 'parseInt', 'prototype']

Modified: trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js (198673 => 198674)


--- trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js	2016-03-25 17:24:33 UTC (rev 198673)
+++ trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js	2016-03-25 17:37:48 UTC (rev 198674)
@@ -57,7 +57,7 @@
     "Array": "['from', 'isArray', 'length', 'name', 'of', 'prototype']",
     "Array.prototype": "['concat', 'constructor', 'copyWithin', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'forEach', 'includes', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift', 'values']",
     "String": "['fromCharCode', 'fromCodePoint', 'length', 'name', 'prototype', 'raw']",
-    "String.prototype": "['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'codePointAt', 'concat', 'constructor', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'includes', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'normalize', 'repeat', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']",
+    "String.prototype": "['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'codePointAt', 'concat', 'constructor', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'includes', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'normalize', 'padEnd', 'padStart', 'repeat', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']",
     "Boolean": "['length', 'name', 'prototype']",
     "Boolean.prototype": "['constructor', 'toString', 'valueOf']",
     "Number": "['EPSILON', 'MAX_SAFE_INTEGER', 'MAX_VALUE', 'MIN_SAFE_INTEGER', 'MIN_VALUE', 'NEGATIVE_INFINITY', 'NaN', 'POSITIVE_INFINITY', 'isFinite', 'isInteger', 'isNaN', 'isSafeInteger', 'length', 'name', 'parseFloat', 'parseInt', 'prototype']",

Modified: trunk/Source/_javascript_Core/ChangeLog (198673 => 198674)


--- trunk/Source/_javascript_Core/ChangeLog	2016-03-25 17:24:33 UTC (rev 198673)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-03-25 17:37:48 UTC (rev 198674)
@@ -1,3 +1,25 @@
+2016-03-25  Caitlin Potter  <[email protected]>
+
+        [JSC] implement String.prototype.padStart() and String.prototype.padEnd() proposal
+        https://bugs.webkit.org/show_bug.cgi?id=155795
+
+        Reviewed by Darin Adler.
+
+        Implements ECMAScript proposal http://tc39.github.io/proposal-string-pad-start-end/
+        Currently at Stage 3.
+
+        * runtime/JSString.h:
+        * runtime/StringPrototype.cpp:
+        (JSC::StringPrototype::finishCreation):
+        (JSC::repeatCharacter):
+        (JSC::repeatStringPattern):
+        (JSC::padString):
+        (JSC::stringProtoFuncPadEnd):
+        (JSC::stringProtoFuncPadStart):
+        * tests/es6.yaml:
+        * tests/es6/String.prototype_methods_String.prototype.padEnd.js: Added.
+        * tests/es6/String.prototype_methods_String.prototype.padStart.js: Added.
+
 2016-03-24  Alex Christensen  <[email protected]>
 
         Fix Mac CMake build.

Modified: trunk/Source/_javascript_Core/runtime/JSString.h (198673 => 198674)


--- trunk/Source/_javascript_Core/runtime/JSString.h	2016-03-25 17:24:33 UTC (rev 198673)
+++ trunk/Source/_javascript_Core/runtime/JSString.h	2016-03-25 17:37:48 UTC (rev 198674)
@@ -87,6 +87,8 @@
     static const bool needsDestruction = true;
     static void destroy(JSCell*);
 
+    static const unsigned MaxLength = std::numeric_limits<int32_t>::max();
+
 private:
     JSString(VM& vm, PassRefPtr<StringImpl> value)
         : JSCell(vm, vm.stringStructure.get())

Modified: trunk/Source/_javascript_Core/runtime/StringPrototype.cpp (198673 => 198674)


--- trunk/Source/_javascript_Core/runtime/StringPrototype.cpp	2016-03-25 17:24:33 UTC (rev 198673)
+++ trunk/Source/_javascript_Core/runtime/StringPrototype.cpp	2016-03-25 17:37:48 UTC (rev 198674)
@@ -66,6 +66,8 @@
 EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState*);
 EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*);
 EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncPadEnd(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncPadStart(ExecState*);
 EncodedJSValue JSC_HOST_CALL stringProtoFuncRepeat(ExecState*);
 EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState*);
 EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*);
@@ -133,6 +135,8 @@
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("concat", stringProtoFuncConcat, DontEnum, 1);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("indexOf", stringProtoFuncIndexOf, DontEnum, 1);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("lastIndexOf", stringProtoFuncLastIndexOf, DontEnum, 1);
+    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("padEnd", stringProtoFuncPadEnd, DontEnum, 1);
+    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("padStart", stringProtoFuncPadStart, DontEnum, 1);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("repeat", stringProtoFuncRepeat, DontEnum, 1);
     JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("replace", stringProtoFuncReplace, DontEnum, 2, StringPrototypeReplaceIntrinsic);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("slice", stringProtoFuncSlice, DontEnum, 2);
@@ -775,6 +779,39 @@
     return jsString(exec, impl.release());
 }
 
+template <typename CharacterType>
+static inline JSString* repeatCharacter(ExecState& exec, CharacterType character, unsigned repeatCount)
+{
+    CharacterType* buffer = nullptr;
+    RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(repeatCount, buffer);
+    if (!impl)
+        return throwOutOfMemoryError(&exec), nullptr;
+
+    std::fill_n(buffer, repeatCount, character);
+
+    return jsString(&exec, impl.release());
+}
+
+static inline bool repeatStringPattern(ExecState& exec, unsigned maxLength, JSString* string, JSRopeString::RopeBuilder& ropeBuilder)
+{
+    unsigned repeatCount = maxLength / string->length();
+    unsigned remainingCharacters = maxLength - repeatCount * string->length();
+    for (unsigned i = 0; i < repeatCount; ++i) {
+        if (!ropeBuilder.append(string)) {
+            throwOutOfMemoryError(&exec);
+            return false;
+        }
+    }
+    if (remainingCharacters) {
+        JSString* substr = jsSubstring(&exec, string, 0, remainingCharacters);
+        if (!substr || !ropeBuilder.append(substr)) {
+            throwOutOfMemoryError(&exec);
+            return false;
+        }
+    }
+    return true;
+}
+
 EncodedJSValue JSC_HOST_CALL stringProtoFuncRepeat(ExecState* exec)
 {
     JSValue thisValue = exec->thisValue();
@@ -822,6 +859,79 @@
     return JSValue::encode(ropeBuilder.release());
 }
 
+enum class StringPaddingLocation { Start, End };
+
+static EncodedJSValue padString(ExecState& exec, StringPaddingLocation paddingLocation)
+{
+    JSValue thisValue = exec.thisValue();
+    if (!thisValue.requireObjectCoercible(&exec))
+        return JSValue::encode(jsUndefined());
+    JSString* thisString = thisValue.toString(&exec);
+    if (exec.hadException())
+        return JSValue::encode(jsUndefined());
+
+    double maxLengthAsDouble = exec.argument(0).toLength(&exec);
+    if (exec.hadException())
+        return JSValue::encode(jsUndefined());
+    ASSERT(maxLengthAsDouble >= 0.0);
+    ASSERT(maxLengthAsDouble == std::trunc(maxLengthAsDouble));
+
+    if (maxLengthAsDouble <= thisString->length())
+        return JSValue::encode(thisString);
+
+    if (maxLengthAsDouble > JSString::MaxLength)
+        return JSValue::encode(throwOutOfMemoryError(&exec));
+
+    unsigned maxLength = static_cast<unsigned>(maxLengthAsDouble);
+
+    JSValue fillString = exec.argument(1);
+    JSString* filler = nullptr;
+    if (!fillString.isUndefined()) {
+        filler = fillString.toString(&exec);
+        if (!filler)
+            return JSValue::encode(jsUndefined());
+    }
+
+    unsigned fillLength = static_cast<unsigned>(maxLength) - thisString->length();
+
+    JSRopeString::RopeBuilder ropeBuilder(exec.vm());
+    if (paddingLocation == StringPaddingLocation::End) {
+        if (!ropeBuilder.append(thisString))
+            return JSValue::encode(throwOutOfMemoryError(&exec));
+    }
+
+    if (!filler || filler->length() == 1) {
+        UChar character = filler ? filler->view(&exec)[0] : ' ';
+        if (!(character & ~0xff))
+            filler = repeatCharacter(exec, static_cast<LChar>(character), fillLength);
+        else
+            filler = repeatCharacter(exec, character, fillLength);
+        if (!filler || !ropeBuilder.append(filler))
+            return JSValue::encode(throwOutOfMemoryError(&exec));
+        ASSERT(filler->length() == fillLength);
+    } else {
+        if (!repeatStringPattern(exec, fillLength, filler, ropeBuilder))
+            return JSValue::encode(throwOutOfMemoryError(&exec));
+    }
+
+    if (paddingLocation == StringPaddingLocation::Start) {
+        if (!ropeBuilder.append(thisString))
+            return JSValue::encode(throwOutOfMemoryError(&exec));
+    }
+    ASSERT(!exec.hadException());
+    return JSValue::encode(ropeBuilder.release());
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncPadEnd(ExecState* exec)
+{
+    return padString(*exec, StringPaddingLocation::End);
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncPadStart(ExecState* exec)
+{
+    return padString(*exec, StringPaddingLocation::Start);
+}
+
 ALWAYS_INLINE EncodedJSValue replace(
     ExecState* exec, JSString* string, JSValue searchValue, JSValue replaceValue)
 {

Added: trunk/Source/_javascript_Core/tests/es6/String.prototype_methods_String.prototype.padEnd.js (0 => 198674)


--- trunk/Source/_javascript_Core/tests/es6/String.prototype_methods_String.prototype.padEnd.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/es6/String.prototype_methods_String.prototype.padEnd.js	2016-03-25 17:37:48 UTC (rev 198674)
@@ -0,0 +1,107 @@
+function shouldBe(expected, actual, msg) {
+    if (msg === void 0)
+        msg = '';
+    else
+        msg = ' for ' + msg;
+    if (actual !== expected)
+        throw new Error('bad value' + msg + ': ' + actual + '. Expected ' + expected);
+}
+
+function shouldThrow(func, errorType) {
+    try {
+        func();
+        throw new Error('Expected ' + func + '() to throw ' + errorType.name + ', but did not throw.');
+    } catch (e) {
+        if (e instanceof errorType) return;
+        throw new Error('Expected ' + func + '() to throw ' + errorType.name + ', but threw ' + e);
+    }
+}
+
+(function TestMeta() {
+    shouldBe(1, String.prototype.padEnd.length);
+    shouldBe("function", typeof String.prototype.padEnd);
+    shouldBe(Object.getPrototypeOf(Function), Object.getPrototypeOf(String.prototype.padEnd));
+    shouldBe("padEnd", String.prototype.padEnd.name);
+
+    var descriptor = Object.getOwnPropertyDescriptor(String.prototype, "padEnd");
+    shouldBe(undefined, descriptor.get);
+    shouldBe(undefined, descriptor.set);
+    shouldBe(true, descriptor.configurable);
+    shouldBe(false, descriptor.enumerable);
+    shouldBe(true, descriptor.writable);
+    shouldBe(String.prototype.padEnd, descriptor.value);
+
+    shouldThrow(() => new Function(`${String.prototype.padEnd}`), SyntaxError);
+})();
+
+(function TestRequireObjectCoercible() {
+    var padEnd = String.prototype.padEnd;
+    shouldThrow(() => padEnd.call(null, 4, "test"), TypeError);
+    shouldThrow(() => padEnd.call(undefined, 4, "test"), TypeError);
+    shouldBe("123   ", padEnd.call({
+        __proto__: null,
+        valueOf() { return 123; }
+    }, 6, " "));
+
+    var proxy = new Proxy({}, {
+        get(t, name) {
+            if (name === Symbol.toPrimitive || name === "toString") return;
+            if (name === "valueOf") return () => 6.7;
+            throw new Error("unreachable code");
+        }
+    });
+    shouldBe("6.7   ", padEnd.call(proxy, 6, " "));
+
+    proxy = new Proxy({}, {
+        get(t, name) {
+            if (name === Symbol.toPrimitive || name === "valueOf") return;
+            if (name === "toString") return () => 6.7;
+            throw new Error("unreachable code");
+        }
+    });
+    shouldBe("6.7   ", padEnd.call(proxy, 6, " "));
+})();
+
+(function TestToLength() {
+    shouldThrow(() => "123".padEnd(Symbol("16")), TypeError);
+    shouldBe("123", "123".padEnd(-1));
+    shouldBe("123", "123".padEnd({ toString() { return -1; } }));
+    shouldBe("123", "123".padEnd(-0));
+    shouldBe("123", "123".padEnd({ toString() { return -0; } }));
+    shouldBe("123", "123".padEnd(+0));
+    shouldBe("123", "123".padEnd({ toString() { return +0; } }));
+    shouldBe("123", "123".padEnd(NaN));
+    shouldBe("123", "123".padEnd({ toString() { return NaN; } }));
+})();
+
+(function TestFillerToString() {
+    shouldBe(".         ", ".".padEnd(10));
+    shouldBe(".         ", ".".padEnd(10, undefined));
+    shouldBe(".         ", ".".padEnd(10, { toString() { return ""; } }));
+    shouldBe(".nullnulln", ".".padEnd(10, null));
+})();
+
+(function TestSingleCharacterFiller() {
+    shouldBe(".!!!!!!!!!", ".".padEnd(10, "!"));
+    shouldBe(".!!!!!!!!!", ".".padEnd(10, { toString() { return "!"; } }));
+    shouldBe(".!!!!!!!!!", ".".padEnd(10, "" + "!" + ""));
+    shouldBe(".!!!!!!!!!", ".".padEnd(10, { toString() { return "" + "!" + ""; } }));
+})();
+
+(function TestMemoryLimits() {
+    shouldThrow(() => ".".padEnd(0x80000000, "o"), Error);
+    shouldThrow(() => ".".padEnd({ valueOf() { return 0x80000000; } }, "o"), Error);
+    shouldThrow(() => ".".padEnd("0x80000000", "o"), Error);
+})();
+
+(function TestFillerRepetition() {
+    for (var i = 2000; i > 0; --i) {
+        var expected = "123" + "xoxo".repeat(i / 4).slice(0, i - 3);
+        var actual = "123".padEnd(i, "xoxo");
+        shouldBe(expected, actual);
+        shouldBe(i > "123".length ? i : 3, actual.length);
+        actual = "123".padEnd(i, "xo" + "" + "xo");
+        shouldBe(expected, actual);
+        shouldBe(i > "123".length ? i : 3, actual.length);
+    }
+})();

Added: trunk/Source/_javascript_Core/tests/es6/String.prototype_methods_String.prototype.padStart.js (0 => 198674)


--- trunk/Source/_javascript_Core/tests/es6/String.prototype_methods_String.prototype.padStart.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/es6/String.prototype_methods_String.prototype.padStart.js	2016-03-25 17:37:48 UTC (rev 198674)
@@ -0,0 +1,107 @@
+function shouldBe(expected, actual, msg) {
+    if (msg === void 0)
+        msg = '';
+    else
+        msg = ' for ' + msg;
+    if (actual !== expected)
+        throw new Error('bad value' + msg + ': ' + actual + '. Expected ' + expected);
+}
+
+function shouldThrow(func, errorType) {
+    try {
+        func();
+        throw new Error('Expected ' + func + '() to throw ' + errorType.name + ', but did not throw.');
+    } catch (e) {
+        if (e instanceof errorType) return;
+        throw new Error('Expected ' + func + '() to throw ' + errorType.name + ', but threw ' + e);
+    }
+}
+
+(function TestMeta() {
+    shouldBe(1, String.prototype.padEnd.length);
+    shouldBe("function", typeof String.prototype.padStart);
+    shouldBe(Object.getPrototypeOf(Function), Object.getPrototypeOf(String.prototype.padStart));
+    shouldBe("padStart", String.prototype.padStart.name);
+
+    var descriptor = Object.getOwnPropertyDescriptor(String.prototype, "padStart");
+    shouldBe(undefined, descriptor.get);
+    shouldBe(undefined, descriptor.set);
+    shouldBe(true, descriptor.configurable);
+    shouldBe(false, descriptor.enumerable);
+    shouldBe(true, descriptor.writable);
+    shouldBe(String.prototype.padStart, descriptor.value);
+
+    shouldThrow(() => new Function(`${String.prototype.padStart}`), SyntaxError);
+})();
+
+(function TestRequireObjectCoercible() {
+    var padStart = String.prototype.padStart;
+    shouldThrow(() => padStart.call(null, 4, "test"), TypeError);
+    shouldThrow(() => padStart.call(undefined, 4, "test"), TypeError);
+    shouldBe("   123", padStart.call({
+        __proto__: null,
+        valueOf() { return 123; }
+    }, 6, " "));
+
+    var proxy = new Proxy({}, {
+        get(t, name) {
+            if (name === Symbol.toPrimitive || name === "toString") return;
+            if (name === "valueOf") return () => 6.7;
+            throw new Error("unreachable code");
+        }
+    });
+    shouldBe("   6.7", padStart.call(proxy, 6, " "));
+
+    proxy = new Proxy({}, {
+        get(t, name) {
+            if (name === Symbol.toPrimitive || name === "valueOf") return;
+            if (name === "toString") return () => 6.7;
+            throw new Error("unreachable code");
+        }
+    });
+    shouldBe("   6.7", padStart.call(proxy, 6, " "));
+})();
+
+(function TestToLength() {
+    shouldThrow(() => "123".padStart(Symbol("16")), TypeError);
+    shouldBe("123", "123".padStart(-1));
+    shouldBe("123", "123".padStart({ toString() { return -1; } }));
+    shouldBe("123", "123".padStart(-0));
+    shouldBe("123", "123".padStart({ toString() { return -0; } }));
+    shouldBe("123", "123".padStart(+0));
+    shouldBe("123", "123".padStart({ toString() { return +0; } }));
+    shouldBe("123", "123".padStart(NaN));
+    shouldBe("123", "123".padStart({ toString() { return NaN; } }));
+})();
+
+(function TestFillerToString() {
+    shouldBe("         .", ".".padStart(10));
+    shouldBe("         .", ".".padStart(10, undefined));
+    shouldBe("         .", ".".padStart(10, { toString() { return ""; } }));
+    shouldBe("nullnulln.", ".".padStart(10, null));
+})();
+
+(function TestSingleCharacterFiller() {
+    shouldBe("!!!!!!!!!.", ".".padStart(10, "!"));
+    shouldBe("!!!!!!!!!.", ".".padStart(10, { toString() { return "!"; } }));
+    shouldBe("!!!!!!!!!.", ".".padStart(10, "" + "!" + ""));
+    shouldBe("!!!!!!!!!.", ".".padStart(10, { toString() { return "" + "!" + ""; } }));
+})();
+
+(function TestMemoryLimits() {
+    shouldThrow(() => ".".padStart(0x80000000, "o"), Error);
+    shouldThrow(() => ".".padStart({ valueOf() { return 0x80000000; } }, "o"), Error);
+    shouldThrow(() => ".".padStart("0x80000000", "o"), Error);
+})();
+
+(function TestFillerRepetition() {
+    for (var i = 2000; i > 0; --i) {
+        var expected = "xoxo".repeat(i / 4).slice(0, i - 3) + "123";
+        var actual = "123".padStart(i, "xoxo");
+        shouldBe(expected, actual);
+        shouldBe(i > "123".length ? i : 3, actual.length);
+        actual = "123".padStart(i, "xo" + "" + "xo");
+        shouldBe(expected, actual);
+        shouldBe(i > "123".length ? i : 3, actual.length);
+    }
+})();

Modified: trunk/Source/_javascript_Core/tests/es6.yaml (198673 => 198674)


--- trunk/Source/_javascript_Core/tests/es6.yaml	2016-03-25 17:24:33 UTC (rev 198673)
+++ trunk/Source/_javascript_Core/tests/es6.yaml	2016-03-25 17:37:48 UTC (rev 198674)
@@ -574,6 +574,10 @@
   cmd: runES6 :normal
 - path: es6/String.prototype_methods_String.prototype.normalize.js
   cmd: runES6 :normal
+- path: es6/String.prototype_methods_String.prototype.padEnd.js
+  cmd: runES6 :normal
+- path: es6/String.prototype_methods_String.prototype.padStart.js
+  cmd: runES6 :normal
 - path: es6/String.prototype_methods_String.prototype.repeat.js
   cmd: runES6 :normal
 - path: es6/String.prototype_methods_String.prototype.startsWith.js
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to