Diff
Modified: trunk/LayoutTests/ChangeLog (173760 => 173761)
--- trunk/LayoutTests/ChangeLog 2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/LayoutTests/ChangeLog 2014-09-19 17:47:50 UTC (rev 173761)
@@ -1,3 +1,23 @@
+2014-09-19 Diego Pino Garcia <[email protected]>
+
+ Simple ES6 feature:String prototype additions
+ https://bugs.webkit.org/show_bug.cgi?id=131704
+
+ Reviewed by Darin Adler.
+
+ Test ES6 functions: string.startsWith(), string.endsWith() and
+ string.contains().
+
+ * js/Object-getOwnPropertyNames-expected.txt:
+ * js/script-tests/Object-getOwnPropertyNames.js:
+ * js/script-tests/string-contains.js: Added.
+ (stringToSearchIn.toString):
+ (startOffset.valueOf):
+ (matchString.toString):
+ (endOffset.valueOf):
+ * js/string-contains-expected.txt: Added.
+ * js/string-contains.html: Added.
+
2014-09-19 Youenn Fablet <[email protected]>
WTR and DRT didReceiveAuthenticationChallengeInFrame should print messages consistently
Modified: trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt (173760 => 173761)
--- trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt 2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt 2014-09-19 17:47:50 UTC (rev 173761)
@@ -47,7 +47,7 @@
PASS getSortedOwnPropertyNames(Array) is ['isArray', 'length', 'name', 'prototype']
PASS getSortedOwnPropertyNames(Array.prototype) is ['concat', 'constructor', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'forEach', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']
PASS getSortedOwnPropertyNames(String) is ['fromCharCode', 'length', 'name', 'prototype']
-PASS getSortedOwnPropertyNames(String.prototype) is ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'fixed', 'fontcolor', 'fontsize', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'replace', 'search', 'slice', 'small', 'split', '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', 'concat', 'constructor', 'contains', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', '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 ['MAX_VALUE', 'MIN_VALUE', 'NEGATIVE_INFINITY', 'NaN', 'POSITIVE_INFINITY', 'length', 'name', 'prototype']
Modified: trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js (173760 => 173761)
--- trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js 2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js 2014-09-19 17:47:50 UTC (rev 173761)
@@ -55,7 +55,7 @@
"Array": "['isArray', 'length', 'name', 'prototype']",
"Array.prototype": "['concat', 'constructor', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'forEach', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']",
"String": "['fromCharCode', 'length', 'name', 'prototype']",
- "String.prototype": "['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'fixed', 'fontcolor', 'fontsize', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'replace', 'search', 'slice', 'small', 'split', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']",
+ "String.prototype": "['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'contains', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', '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": "['MAX_VALUE', 'MIN_VALUE', 'NEGATIVE_INFINITY', 'NaN', 'POSITIVE_INFINITY', 'length', 'name', 'prototype']",
Added: trunk/LayoutTests/js/script-tests/string-contains.js (0 => 173761)
--- trunk/LayoutTests/js/script-tests/string-contains.js (rev 0)
+++ trunk/LayoutTests/js/script-tests/string-contains.js 2014-09-19 17:47:50 UTC (rev 173761)
@@ -0,0 +1,278 @@
+description("This test checks the ES6 string functions startsWith(), endsWith() and contains().");
+
+// Test contains
+shouldBe("'foo bar'.contains('bar')", "true");
+shouldBe("'foo bar'.contains('bar', 4)", "true");
+shouldBe("'foo bar'.contains('ar', 5)", "true");
+shouldBe("'foo bar'.contains('qux')", "false");
+shouldBe("'foo bar'.contains('foo')", "true");
+shouldBe("'foo bar'.contains('foo', 0)", "true");
+shouldBe("'foo bar'.contains('foo', -1)", "true");
+shouldBe("'foo bar'.contains('')", "true");
+shouldBe("'foo bar'.contains()", "false");
+shouldBe("'foo bar qux'.contains('qux', 7)", "true");
+shouldBe("'foo bar qux'.contains('bar', 7)", "false");
+shouldBe("'foo null bar'.contains()", "false");
+shouldBe("'foo null bar'.contains(null)", "true");
+shouldBe("'foo null bar'.contains(null)", "true");
+shouldBe("'foo undefined bar'.contains()", "true");
+shouldBe("'foo undefined bar'.contains(undefined)", "true");
+shouldBe("'foo undefined bar'.contains()", "true");
+shouldBe("'foo undefined bar'.contains()", "true");
+shouldBe("'foo true bar'.contains(true)", "true");
+shouldBe("'foo false bar'.contains(false)", "true");
+shouldBe("'foo 1 bar'.contains(1)", "true");
+shouldBe("'foo 1.1 bar'.contains(1.1)", "true");
+shouldBe("'foo NaN bar'.contains(NaN)", "true");
+shouldBe("'foo 1.0 bar'.contains(1.0)", "true");
+shouldBe("'foo 1e+100 bar'.contains(1e+100)", "true");
+shouldBe("'foo 1e100 bar'.contains(1e100)", "false");
+shouldBe("'フーバー'.contains('ーバ')", "true");
+shouldBe("'フーバー'.contains('クー')", "false");
+
+// Test startsWith
+shouldBe("'foo bar'.startsWith('foo')", "true");
+shouldBe("'foo bar'.startsWith('foo', 0)", "true");
+shouldBe("'foo bar'.startsWith('foo', -1)", "true");
+shouldBe("'foo bar'.startsWith('oo', 1)", "true");
+shouldBe("'foo bar'.startsWith('qux')", "false");
+shouldBe("'foo bar'.startsWith('')", "true");
+shouldBe("'foo bar'.startsWith()", "false");
+shouldBe("'null'.startsWith()", "false");
+shouldBe("'null'.startsWith(null)", "true");
+shouldBe("'null bar'.startsWith(null)", "true");
+shouldBe("'undefined'.startsWith()", "true");
+shouldBe("'undefined'.startsWith(undefined)", "true");
+shouldBe("'undefined bar'.startsWith()", "true");
+shouldBe("'undefined bar'.startsWith()", "true");
+shouldBe("'true bar'.startsWith(true)", "true");
+shouldBe("'false bar'.startsWith(false)", "true");
+shouldBe("'1 bar'.startsWith(1)", "true");
+shouldBe("'1.1 bar'.startsWith(1.1)", "true");
+shouldBe("'NaN bar'.startsWith(NaN)", "true");
+shouldBe("'1e+100 bar'.startsWith(1e+100)", "true");
+shouldBe("'1e100 bar'.startsWith(1e100)", "false");
+shouldBe("'フーバー'.startsWith('フー')", "true");
+shouldBe("'フーバー'.startsWith('バー')", "false");
+
+// Test endsWith
+shouldBe("'foo bar'.endsWith('bar')", "true");
+shouldBe("'foo bar'.endsWith('ba', 6)", "true");
+shouldBe("'foo bar'.endsWith(' ba', 6)", "true");
+shouldBe("'foo bar'.endsWith('foo bar')", "true");
+shouldBe("'foo bar'.endsWith('foo bar', 7)", "true");
+shouldBe("'foo bar'.endsWith('foo bar', 8)", "true");
+shouldBe("'foo bar'.endsWith('foo bar', -1)", "false");
+shouldBe("'foo bar'.endsWith('qux')", "false");
+shouldBe("'foo bar'.endsWith('')", "true");
+shouldBe("'foo bar'.endsWith()", "false");
+shouldBe("'foo null'.endsWith()", "false");
+shouldBe("'foo null'.endsWith(null)", "true");
+shouldBe("'foo null'.endsWith(null)", "true");
+shouldBe("'foo undefined'.endsWith()", "true");
+shouldBe("'foo undefined'.endsWith(undefined)", "true");
+shouldBe("'foo undefined'.endsWith()", "true");
+shouldBe("'foo undefined'.endsWith()", "true");
+shouldBe("'foo true'.endsWith(true)", "true");
+shouldBe("'foo false'.endsWith(false)", "true");
+shouldBe("'foo 1'.endsWith(1)", "true");
+shouldBe("'foo 1.1'.endsWith(1.1)", "true");
+shouldBe("'foo NaN'.endsWith(NaN)", "true");
+shouldBe("'foo 1e+100'.endsWith(1e+100)", "true");
+shouldBe("'foo 1e100'.endsWith(1e100)", "false");
+shouldBe("'フーバー'.endsWith('バー')", "true");
+shouldBe("'フーバー'.endsWith('フー')", "false");
+
+// Call functions with an environment record as 'this'.
+shouldThrow("(function() { var f = String.prototype.startsWith; (function() { f('a'); })(); })()");
+shouldThrow("(function() { var f = String.prototype.endsWith; (function() { f('a'); })(); })()");
+shouldThrow("(function() { var f = String.prototype.contains; (function() { f('a'); })(); })()");
+
+// ES6 spec says a regex as argument should throw an Exception.
+shouldThrow("'foo bar'.startsWith(/\w+/)");
+shouldThrow("'foo bar'.endsWith(/\w+/)");
+shouldThrow("'foo bar'.contains(/\w+/)");
+
+// Check side effects in startsWith.
+var sideEffect = "";
+var stringToSearchIn = new String("foo bar");
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+var startOffset = new Number(0);
+startOffset.valueOf = function() {
+ sideEffect += "B";
+ return this;
+}
+var matchString = new String("foo");
+matchString.toString = function() {
+ sideEffect += "C";
+ return this;
+}
+// Calling stringToSearchIn.startsWith implicitly calls stringToSearchIn.toString(),
+// startOffset.valueOf() and matchString.toString(), in that respective order.
+shouldBe("stringToSearchIn.startsWith(matchString, startOffset)", "true");
+shouldBe("sideEffect == 'ABC'", "true");
+
+// If stringToSearchIn throws an exception startOffset.valueOf() and
+// matchString.toString() are not called.
+stringToSearchIn.toString = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.startsWith(matchString, startOffset)", "'error'");
+shouldBe("sideEffect == ''", "true");
+
+// If startOffset throws an exception stringToSearchIn.toString() is called but
+// matchString.toString() is not.
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+startOffset.valueOf = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.startsWith(matchString, startOffset)", "'error'");
+shouldBe("sideEffect == 'A'", "true");
+
+// If matchString.toString() throws an exception stringToSearchIn.toString() and
+// startOffset.valueOf() were called.
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+startOffset.valueOf = function() {
+ sideEffect += "B";
+ return this;
+}
+matchString.toString = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.startsWith(matchString, startOffset)", "'error'");
+shouldBe("sideEffect == 'AB'", "true");
+
+// Check side effects in endsWith.
+sideEffect = "";
+stringToSearchIn = new String('foo bar');
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+var endOffset = new Number(stringToSearchIn.length);
+endOffset.valueOf = function() {
+ sideEffect += "B";
+ return this;
+}
+matchString = new String('bar');
+matchString.toString = function() {
+ sideEffect += "C";
+ return this;
+}
+
+// Calling stringToSearchIn.endsWith implicitly calls stringToSearchIn.toString(),
+// endOffset.valueOf() and matchString.toString(), in that respective order.
+shouldBe("stringToSearchIn.endsWith(matchString, endOffset)", "true");
+shouldBe("sideEffect == 'ABC'", "true");
+
+// If stringToSearchIn throws an exception endOffset.valueOf() and
+// matchString.toString() are not called.
+stringToSearchIn.toString = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.endsWith(matchString, endOffset)", "'error'");
+shouldBe("sideEffect == ''", "true");
+
+// If endOffset throws an exception stringToSearchIn.toString() is called but
+// matchString.toString() is not.
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+endOffset.valueOf = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.endsWith(matchString, endOffset)", "'error'");
+shouldBe("sideEffect == 'A'", "true");
+
+// If matchString.toString() throws an exception stringToSearchIn.toString() and
+// endOffset.valueOf() were called.
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+endOffset.valueOf = function() {
+ sideEffect += "B";
+ return this;
+}
+matchString.toString = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.endsWith(matchString, endOffset)", "'error'");
+shouldBe("sideEffect == 'AB'", "true");
+
+// Check side effects in contains.
+var sideEffect = "";
+stringToSearchIn = new String("foo bar");
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+var startOffset = new Number(0);
+startOffset.valueOf = function() {
+ sideEffect += "B";
+ return this;
+}
+matchString = new String("foo");
+matchString.toString = function() {
+ sideEffect += "C";
+ return this;
+}
+// Calling stringToSearchIn.contains implicitly calls stringToSearchIn.toString(),
+// startOffset.valueOf() and matchString.toString(), in that respective order.
+shouldBe("stringToSearchIn.contains(matchString, startOffset)", "true");
+shouldBe("sideEffect == 'ABC'", "true");
+
+// If stringToSearchIn throws an exception startOffset.valueOf() and
+// matchString.toString() are not called.
+stringToSearchIn.toString = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.contains(matchString, startOffset)", "'error'");
+shouldBe("sideEffect == ''", "true");
+
+// If startOffset throws an exception stringToSearchIn.toString() is called but
+// matchString.toString() is not.
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+startOffset.valueOf = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.contains(matchString, startOffset)", "'error'");
+shouldBe("sideEffect == 'A'", "true");
+
+// If matchString.toString() throws an exception stringToSearchIn.toString() and
+// startOffset.valueOf() were called.
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+startOffset.valueOf = function() {
+ sideEffect += "B";
+ return this;
+}
+matchString.toString = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.contains(matchString, startOffset)", "'error'");
+shouldBe("sideEffect == 'AB'", "true");
Added: trunk/LayoutTests/js/string-contains-expected.txt (0 => 173761)
--- trunk/LayoutTests/js/string-contains-expected.txt (rev 0)
+++ trunk/LayoutTests/js/string-contains-expected.txt 2014-09-19 17:47:50 UTC (rev 173761)
@@ -0,0 +1,116 @@
+This test checks the ES6 string functions startsWith(), endsWith() and contains().
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS 'foo bar'.contains('bar') is true
+PASS 'foo bar'.contains('bar', 4) is true
+PASS 'foo bar'.contains('ar', 5) is true
+PASS 'foo bar'.contains('qux') is false
+PASS 'foo bar'.contains('foo') is true
+PASS 'foo bar'.contains('foo', 0) is true
+PASS 'foo bar'.contains('foo', -1) is true
+PASS 'foo bar'.contains('') is true
+PASS 'foo bar'.contains() is false
+PASS 'foo bar qux'.contains('qux', 7) is true
+PASS 'foo bar qux'.contains('bar', 7) is false
+PASS 'foo null bar'.contains() is false
+PASS 'foo null bar'.contains(null) is true
+PASS 'foo null bar'.contains(null) is true
+PASS 'foo undefined bar'.contains() is true
+PASS 'foo undefined bar'.contains(undefined) is true
+PASS 'foo undefined bar'.contains() is true
+PASS 'foo undefined bar'.contains() is true
+PASS 'foo true bar'.contains(true) is true
+PASS 'foo false bar'.contains(false) is true
+PASS 'foo 1 bar'.contains(1) is true
+PASS 'foo 1.1 bar'.contains(1.1) is true
+PASS 'foo NaN bar'.contains(NaN) is true
+PASS 'foo 1.0 bar'.contains(1.0) is true
+PASS 'foo 1e+100 bar'.contains(1e+100) is true
+PASS 'foo 1e100 bar'.contains(1e100) is false
+PASS 'フーバー'.contains('ーバ') is true
+PASS 'フーバー'.contains('クー') is false
+PASS 'foo bar'.startsWith('foo') is true
+PASS 'foo bar'.startsWith('foo', 0) is true
+PASS 'foo bar'.startsWith('foo', -1) is true
+PASS 'foo bar'.startsWith('oo', 1) is true
+PASS 'foo bar'.startsWith('qux') is false
+PASS 'foo bar'.startsWith('') is true
+PASS 'foo bar'.startsWith() is false
+PASS 'null'.startsWith() is false
+PASS 'null'.startsWith(null) is true
+PASS 'null bar'.startsWith(null) is true
+PASS 'undefined'.startsWith() is true
+PASS 'undefined'.startsWith(undefined) is true
+PASS 'undefined bar'.startsWith() is true
+PASS 'undefined bar'.startsWith() is true
+PASS 'true bar'.startsWith(true) is true
+PASS 'false bar'.startsWith(false) is true
+PASS '1 bar'.startsWith(1) is true
+PASS '1.1 bar'.startsWith(1.1) is true
+PASS 'NaN bar'.startsWith(NaN) is true
+PASS '1e+100 bar'.startsWith(1e+100) is true
+PASS '1e100 bar'.startsWith(1e100) is false
+PASS 'フーバー'.startsWith('フー') is true
+PASS 'フーバー'.startsWith('バー') is false
+PASS 'foo bar'.endsWith('bar') is true
+PASS 'foo bar'.endsWith('ba', 6) is true
+PASS 'foo bar'.endsWith(' ba', 6) is true
+PASS 'foo bar'.endsWith('foo bar') is true
+PASS 'foo bar'.endsWith('foo bar', 7) is true
+PASS 'foo bar'.endsWith('foo bar', 8) is true
+PASS 'foo bar'.endsWith('foo bar', -1) is false
+PASS 'foo bar'.endsWith('qux') is false
+PASS 'foo bar'.endsWith('') is true
+PASS 'foo bar'.endsWith() is false
+PASS 'foo null'.endsWith() is false
+PASS 'foo null'.endsWith(null) is true
+PASS 'foo null'.endsWith(null) is true
+PASS 'foo undefined'.endsWith() is true
+PASS 'foo undefined'.endsWith(undefined) is true
+PASS 'foo undefined'.endsWith() is true
+PASS 'foo undefined'.endsWith() is true
+PASS 'foo true'.endsWith(true) is true
+PASS 'foo false'.endsWith(false) is true
+PASS 'foo 1'.endsWith(1) is true
+PASS 'foo 1.1'.endsWith(1.1) is true
+PASS 'foo NaN'.endsWith(NaN) is true
+PASS 'foo 1e+100'.endsWith(1e+100) is true
+PASS 'foo 1e100'.endsWith(1e100) is false
+PASS 'フーバー'.endsWith('バー') is true
+PASS 'フーバー'.endsWith('フー') is false
+PASS (function() { var f = String.prototype.startsWith; (function() { f('a'); })(); })() threw exception TypeError: Type error.
+PASS (function() { var f = String.prototype.endsWith; (function() { f('a'); })(); })() threw exception TypeError: Type error.
+PASS (function() { var f = String.prototype.contains; (function() { f('a'); })(); })() threw exception TypeError: Type error.
+PASS 'foo bar'.startsWith(/w+/) threw exception TypeError: Type error.
+PASS 'foo bar'.endsWith(/w+/) threw exception TypeError: Type error.
+PASS 'foo bar'.contains(/w+/) threw exception TypeError: Type error.
+PASS stringToSearchIn.startsWith(matchString, startOffset) is true
+PASS sideEffect == 'ABC' is true
+PASS stringToSearchIn.startsWith(matchString, startOffset) threw exception error.
+PASS sideEffect == '' is true
+PASS stringToSearchIn.startsWith(matchString, startOffset) threw exception error.
+PASS sideEffect == 'A' is true
+PASS stringToSearchIn.startsWith(matchString, startOffset) threw exception error.
+PASS sideEffect == 'AB' is true
+PASS stringToSearchIn.endsWith(matchString, endOffset) is true
+PASS sideEffect == 'ABC' is true
+PASS stringToSearchIn.endsWith(matchString, endOffset) threw exception error.
+PASS sideEffect == '' is true
+PASS stringToSearchIn.endsWith(matchString, endOffset) threw exception error.
+PASS sideEffect == 'A' is true
+PASS stringToSearchIn.endsWith(matchString, endOffset) threw exception error.
+PASS sideEffect == 'AB' is true
+PASS stringToSearchIn.contains(matchString, startOffset) is true
+PASS sideEffect == 'ABC' is true
+PASS stringToSearchIn.contains(matchString, startOffset) threw exception error.
+PASS sideEffect == '' is true
+PASS stringToSearchIn.contains(matchString, startOffset) threw exception error.
+PASS sideEffect == 'A' is true
+PASS stringToSearchIn.contains(matchString, startOffset) threw exception error.
+PASS sideEffect == 'AB' is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/js/string-contains.html (0 => 173761)
--- trunk/LayoutTests/js/string-contains.html (rev 0)
+++ trunk/LayoutTests/js/string-contains.html 2014-09-19 17:47:50 UTC (rev 173761)
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <script src=""
+</head>
+<body>
+ <script src=""
+ <script src=""
+</body>
+</html>
Modified: trunk/Source/_javascript_Core/ChangeLog (173760 => 173761)
--- trunk/Source/_javascript_Core/ChangeLog 2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/Source/_javascript_Core/ChangeLog 2014-09-19 17:47:50 UTC (rev 173761)
@@ -1,3 +1,16 @@
+2014-09-19 Diego Pino Garcia <[email protected]>
+
+ Simple ES6 feature:String prototype additions
+ https://bugs.webkit.org/show_bug.cgi?id=131704
+
+ Reviewed by Darin Adler.
+
+ * runtime/StringPrototype.cpp:
+ (JSC::StringPrototype::finishCreation):
+ (JSC::stringProtoFuncStartsWith): Added.
+ (JSC::stringProtoFuncEndsWith): Added.
+ (JSC::stringProtoFuncContains): Added.
+
2014-09-18 Joseph Pecoraro <[email protected]>
Unreviewed rollout r173731. Broke multiple builds.
Modified: trunk/Source/_javascript_Core/runtime/StringPrototype.cpp (173760 => 173761)
--- trunk/Source/_javascript_Core/runtime/StringPrototype.cpp 2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/Source/_javascript_Core/runtime/StringPrototype.cpp 2014-09-19 17:47:50 UTC (rev 173761)
@@ -82,6 +82,9 @@
EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState*);
EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*);
EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncStartsWith(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncEndsWith(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncContains(ExecState*);
const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, CREATE_METHOD_TABLE(StringPrototype) };
@@ -131,6 +134,9 @@
JSC_NATIVE_FUNCTION("trim", stringProtoFuncTrim, DontEnum, 0);
JSC_NATIVE_FUNCTION("trimLeft", stringProtoFuncTrimLeft, DontEnum, 0);
JSC_NATIVE_FUNCTION("trimRight", stringProtoFuncTrimRight, DontEnum, 0);
+ JSC_NATIVE_FUNCTION("startsWith", stringProtoFuncStartsWith, DontEnum, 0);
+ JSC_NATIVE_FUNCTION("endsWith", stringProtoFuncEndsWith, DontEnum, 0);
+ JSC_NATIVE_FUNCTION("contains", stringProtoFuncContains, DontEnum, 0);
// The constructor will be added later, after StringConstructor has been built
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
@@ -1546,6 +1552,77 @@
JSValue thisValue = exec->thisValue();
return JSValue::encode(trimString(exec, thisValue, TrimRight));
}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncStartsWith(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!checkObjectCoercible(thisValue))
+ return throwVMTypeError(exec);
+
+ String stringToSearchIn = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue a0 = exec->argument(0);
+ if (jsDynamicCast<RegExpObject*>(a0))
+ return throwVMTypeError(exec);
+
+ unsigned start = std::max(0, exec->argument(1).toInt32(exec));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ String matchString = a0.toString(exec)->value(exec);
+
+ return JSValue::encode(jsBoolean(stringToSearchIn.startsWith(matchString, start, true)));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncEndsWith(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!checkObjectCoercible(thisValue))
+ return throwVMTypeError(exec);
+
+ String stringToSearchIn = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue a0 = exec->argument(0);
+ if (jsDynamicCast<RegExpObject*>(a0))
+ return throwVMTypeError(exec);
+
+ unsigned length = stringToSearchIn.length();
+ JSValue a1 = exec->argument(1);
+ int pos = a1.isUndefined() ? length : a1.toInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ unsigned end = std::min<unsigned>(std::max(pos, 0), length);
+
+ String matchString = a0.toString(exec)->value(exec);
+
+ return JSValue::encode(jsBoolean(stringToSearchIn.endsWith(matchString, end, true)));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncContains(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!checkObjectCoercible(thisValue))
+ return throwVMTypeError(exec);
+
+ String stringToSearchIn = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue a0 = exec->argument(0);
+ if (jsDynamicCast<RegExpObject*>(a0))
+ return throwVMTypeError(exec);
+
+ unsigned start = std::max(0, exec->argument(1).toInt32(exec));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ String matchString = a0.toString(exec)->value(exec);
+
+ return JSValue::encode(jsBoolean(stringToSearchIn.contains(matchString, true, start)));
+}
-
} // namespace JSC
Modified: trunk/Source/WTF/ChangeLog (173760 => 173761)
--- trunk/Source/WTF/ChangeLog 2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/Source/WTF/ChangeLog 2014-09-19 17:47:50 UTC (rev 173761)
@@ -1,3 +1,24 @@
+2014-09-19 Diego Pino Garcia <[email protected]>
+
+ Simple ES6 feature:String prototype additions
+ https://bugs.webkit.org/show_bug.cgi?id=131704
+
+ Reviewed by Darin Adler.
+
+ * wtf/text/StringImpl.cpp:
+ (WTF::StringImpl::find):
+ (WTF::equalInner): Added.
+ (WTF::StringImpl::startsWith): Add implementation that supports
+ 'startOffset' parameter.
+ (WTF::StringImpl::endsWith): Add implementation that supports
+ 'endOffset' parameter.
+ * wtf/text/StringImpl.h:
+ * wtf/text/WTFString.h:
+ (WTF::String::contains): Modify current implementation to allow
+ setting a startOffset, 0 by default.
+ (WTF::String::startsWith):
+ (WTF::String::endsWith):
+
2014-09-18 Carlos Garcia Campos <[email protected]>
[GTK] Dot not allow to create delete-on-destroy GMainLoopSources
Modified: trunk/Source/WTF/wtf/text/StringImpl.cpp (173760 => 173761)
--- trunk/Source/WTF/wtf/text/StringImpl.cpp 2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/Source/WTF/wtf/text/StringImpl.cpp 2014-09-19 17:47:50 UTC (rev 173761)
@@ -1368,6 +1368,25 @@
return equalIgnoringCase(stringImpl->characters16() + startOffset, reinterpret_cast<const LChar*>(matchString), matchLength);
}
+ALWAYS_INLINE static bool equalInner(StringImpl& stringImpl, unsigned startOffset, StringImpl& matchString, bool caseSensitive)
+{
+ if (startOffset > stringImpl.length())
+ return false;
+ if (matchString.length() > stringImpl.length())
+ return false;
+ if (matchString.length() + startOffset > stringImpl.length())
+ return false;
+
+ if (caseSensitive) {
+ if (stringImpl.is8Bit())
+ return equal(stringImpl.characters8() + startOffset, matchString.characters8(), matchString.length());
+ return equal(stringImpl.characters16() + startOffset, matchString.characters16(), matchString.length());
+ }
+ if (stringImpl.is8Bit())
+ return equalIgnoringCase(stringImpl.characters8() + startOffset, matchString.characters8(), matchString.length());
+ return equalIgnoringCase(stringImpl.characters16() + startOffset, matchString.characters16(), matchString.length());
+}
+
bool StringImpl::startsWith(const StringImpl* str) const
{
if (!str)
@@ -1399,6 +1418,11 @@
return equalInner(this, 0, matchString, matchLength, caseSensitive);
}
+bool StringImpl::startsWith(StringImpl& matchString, unsigned startOffset, bool caseSensitive) const
+{
+ return equalInner(const_cast<StringImpl&>(*this), startOffset, matchString, caseSensitive);
+}
+
bool StringImpl::endsWith(StringImpl* matchString, bool caseSensitive)
{
ASSERT(matchString);
@@ -1423,6 +1447,13 @@
return equalInner(this, startOffset, matchString, matchLength, caseSensitive);
}
+bool StringImpl::endsWith(StringImpl& matchString, unsigned endOffset, bool caseSensitive) const
+{
+ if (endOffset < matchString.length())
+ return false;
+ return equalInner(const_cast<StringImpl&>(*this), endOffset - matchString.length(), matchString, caseSensitive);
+}
+
PassRef<StringImpl> StringImpl::replace(UChar oldC, UChar newC)
{
if (oldC == newC)
Modified: trunk/Source/WTF/wtf/text/StringImpl.h (173760 => 173761)
--- trunk/Source/WTF/wtf/text/StringImpl.h 2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/Source/WTF/wtf/text/StringImpl.h 2014-09-19 17:47:50 UTC (rev 173761)
@@ -673,12 +673,14 @@
WTF_EXPORT_STRING_API bool startsWith(const char*, unsigned matchLength, bool caseSensitive) const;
template<unsigned matchLength>
bool startsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const { return startsWith(prefix, matchLength - 1, caseSensitive); }
+ WTF_EXPORT_STRING_API bool startsWith(StringImpl&, unsigned startOffset, bool caseSensitive) const;
WTF_EXPORT_STRING_API bool endsWith(StringImpl*, bool caseSensitive = true);
WTF_EXPORT_STRING_API bool endsWith(UChar) const;
WTF_EXPORT_STRING_API bool endsWith(const char*, unsigned matchLength, bool caseSensitive) const;
template<unsigned matchLength>
bool endsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const { return endsWith(prefix, matchLength - 1, caseSensitive); }
+ WTF_EXPORT_STRING_API bool endsWith(StringImpl&, unsigned endOffset, bool caseSensitive) const;
WTF_EXPORT_STRING_API PassRef<StringImpl> replace(UChar, UChar);
WTF_EXPORT_STRING_API PassRef<StringImpl> replace(UChar, StringImpl*);
Modified: trunk/Source/WTF/wtf/text/WTFString.h (173760 => 173761)
--- trunk/Source/WTF/wtf/text/WTFString.h 2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/Source/WTF/wtf/text/WTFString.h 2014-09-19 17:47:50 UTC (rev 173761)
@@ -256,8 +256,10 @@
WTF_EXPORT_STRING_API UChar32 characterStartingAt(unsigned) const; // Ditto.
bool contains(UChar c) const { return find(c) != notFound; }
- bool contains(const LChar* str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != notFound; }
- bool contains(const String& str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != notFound; }
+ bool contains(const LChar* str, bool caseSensitive = true, unsigned startOffset = 0) const
+ { return find(str, startOffset, caseSensitive) != notFound; }
+ bool contains(const String& str, bool caseSensitive = true, unsigned startOffset = 0) const
+ { return find(str, startOffset, caseSensitive) != notFound; }
bool startsWith(const String& s) const
{ return m_impl ? m_impl->startsWith(s.impl()) : s.isEmpty(); }
@@ -268,6 +270,8 @@
template<unsigned matchLength>
bool startsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const
{ return m_impl ? m_impl->startsWith<matchLength>(prefix, caseSensitive) : !matchLength; }
+ bool startsWith(String& prefix, unsigned startOffset, bool caseSensitive) const
+ { return m_impl && prefix.impl() ? m_impl->startsWith(*prefix.impl(), startOffset, caseSensitive) : false; }
bool endsWith(const String& s, bool caseSensitive = true) const
{ return m_impl ? m_impl->endsWith(s.impl(), caseSensitive) : s.isEmpty(); }
@@ -277,6 +281,8 @@
template<unsigned matchLength>
bool endsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const
{ return m_impl ? m_impl->endsWith<matchLength>(prefix, caseSensitive) : !matchLength; }
+ bool endsWith(String& suffix, unsigned endOffset, bool caseSensitive) const
+ { return m_impl && suffix.impl() ? m_impl->endsWith(*suffix.impl(), endOffset, caseSensitive) : false; }
WTF_EXPORT_STRING_API void append(const String&);
WTF_EXPORT_STRING_API void append(LChar);