blob: 45d74b96b4d5351c6434456b0e198e11d28b16b4 [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
// ES6 String API extensions tests -- verifies the API shape and basic functionality
WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
function verifyThrowsIfRegExpSearchString(functionName) {
var f = String.prototype[functionName].bind("abc");
var re = /./;
assert.throws(f.bind(undefined, re), TypeError, "Regular RegExp");
helpers.withPropertyDeleted(RegExp.prototype, Symbol.match, function () {
assert.throws(f.bind(undefined, re), TypeError, "Regular RegExp without Symbol.match property");
})
re = 1;
assert.doesNotThrow(f.bind(undefined, re), "Not an Object (Number)");
re = {};
assert.doesNotThrow(f.bind(undefined, re), "Object without Symbol.match property");
re = {
[Symbol.match]: true
};
assert.throws(f.bind(undefined, re), TypeError, "Object with Boolean Symbol.match property");
re = {
[Symbol.match]: 'coerced to true'
};
assert.throws(f.bind(undefined, re), TypeError, "Object with Symbol.match property coerced to 'true'");
re = {
[Symbol.match]: null
};
assert.doesNotThrow(f.bind(undefined, re), "Object with Symbol.match property coerced to 'false'");
}
var tests = [
{
name: "Array prototype and String prototype should have spec defined built-ins with correct lengths",
body: function () {
assert.isTrue(Array.prototype.hasOwnProperty('find'), "Array.prototype should have a find method");
assert.isTrue(Array.prototype.hasOwnProperty('findIndex'), "Array.prototype should have a findIndex method");
assert.isTrue(String.prototype.hasOwnProperty('repeat'), "String.prototype should have a repeat method");
assert.isTrue(String.prototype.hasOwnProperty('startsWith'), "String.prototype should have a startsWith method");
assert.isTrue(String.prototype.hasOwnProperty('endsWith'), "String.prototype should have a endsWith method");
assert.isTrue(String.prototype.hasOwnProperty('includes'), "String.prototype should have a includes method");
assert.isTrue(Array.prototype.find.length === 1, "find method takes two arguments but the second is optional and the spec says the length must be 1");
assert.isTrue(Array.prototype.findIndex.length === 1, "findIndex method takes two arguments but the second is optional and the spec says the length must be 1");
assert.isTrue(String.prototype.repeat.length === 1, "repeat method takes zero arguments");
assert.isTrue(String.prototype.startsWith.length === 1, "startsWith method takes two arguments but the second is optional and the spec says the length must be 1");
assert.isTrue(String.prototype.endsWith.length === 1, "endsWith method takes two arguments but the second is optional and the spec says the length must be 1");
assert.isTrue(String.prototype.includes.length === 1, "includes method takes two arguments but the second is optional and the spec says the length must be 1");
}
},
{
name: "find takes a predicate and applies it to each element in the array in ascending order until the predicate returns true, then find returns that element",
body: function () {
assert.throws(function () { Array.prototype.find.call(); }, TypeError, "find throws TypeError if it is given no arguments", "Array.prototype.find: 'this' is null or undefined");
assert.throws(function () { Array.prototype.find.call(undefined); }, TypeError, "find throws TypeError if its this argument is undefined", "Array.prototype.find: 'this' is null or undefined");
assert.throws(function () { Array.prototype.find.call(undefined, function () { return true; }, {}); }, TypeError, "find throws TypeError if its this argument is undefined even if given further arguments", "Array.prototype.find: 'this' is null or undefined");
assert.throws(function () { Array.prototype.find.call(null); }, TypeError, "find throws TypeError if its this argument is null", "Array.prototype.find: 'this' is null or undefined");
assert.throws(function () { Array.prototype.find.call(null, function () { return true; }, {}); }, TypeError, "find throws TypeError if its this argument is null even if given further arguments", "Array.prototype.find: 'this' is null or undefined");
var arr = [ 1, 2, 3 ];
// Test missing/invalid predicate argument
assert.throws(function () { arr.find(); }, TypeError, "find throws TypeError if it is given no predicate argument", "Array.prototype.find: argument is not a Function object");
assert.throws(function () { arr.find({}); }, TypeError, "find throws TypeError if it is given a non-Function object predicate argument", "Array.prototype.find: argument is not a Function object");
var fakeArrWithLengthGetter = {
__proto__: Array.prototype,
get length () { throw new Error('getter called'); }
};
assert.throws(function () { fakeArrWithLengthGetter.find(); }, Error, "find gets length property, calling getter method, before checking for a valid predicate function argument", "getter called");
// Test simple predicates matching each element
assert.areEqual( 1, arr.find(function (v, i, a) { return true; }), "Simple predicate always returns true, should find first item");
assert.areEqual( 1, arr.find(function (v, i, a) { if (i >= 1) { assert.fail("shouldn't visit index > 0"); } return v === 1; }), "Simple predicate matching first element, should find first element");
assert.areEqual( 2, arr.find(function (v, i, a) { if (i >= 2) { assert.fail("shouldn't visit index > 1"); } return v === 2; }), "Simple predicate matching second element, should find second element");
assert.areEqual( 3, arr.find(function (v, i, a) { if (i >= 3) { assert.fail("shouldn't visit index > 2"); } return v === 3; }), "Simple predicate matching third element, should find third element");
assert.areEqual(undefined, arr.find(function (v, i, a) { if (i >= 3) { assert.fail("shouldn't visit index > 2"); } return v === 4; }), "Simple predicate matching non-existent element, should not find any element");
assert.areEqual( 2, arr.find(function (v, i, a) { if (i >= 2) { assert.fail("shouldn't visit index > 1"); } return v === 2 || v === 3; }), "Simple predicate matching two elements, second and third, should find first of them, i.e. the second element");
// Test adding elements in predicate function
assert.areEqual(undefined, arr.find(function (v, i, a) { if (i >= 3) { assert.fail("shouldn't visit index > 2 (initial array length"); } a.push(v + 3); return false; }), "Elements added after find has started shouldn't be included in the search");
assert.areEqual([ 1, 2, 3, 4, 5, 6 ], arr, "Three more elements should be added to end of arr");
// Test deleting elements in predicate function that have not been visited
function f(v, i, a) {
if (i % 2 === 1) {
assert.areEqual(undefined, v, "odd indices should be undefined since they were deleted");
} else {
delete a[i+1];
}
return false;
};
assert.areEqual(undefined, arr.find(f), "Elements deleted before being visited after find has started shouldn't be included in the search");
assert.areEqual( 1, arr[0], "Odd elements should be deleted [0]");
assert.areEqual(undefined, arr[1], "Odd elements should be deleted [1]");
assert.areEqual( 3, arr[2], "Odd elements should be deleted [2]");
assert.areEqual(undefined, arr[3], "Odd elements should be deleted [3]");
assert.areEqual( 5, arr[4], "Odd elements should be deleted [4]");
assert.areEqual(undefined, arr[5], "Odd elements should be deleted [5]");
// Test deleting elements in predicate function that have already been visited
assert.areEqual(undefined, arr.find(function (v, i, a) { delete a[i]; return false; }), "Elements deleted after being visited has no effect on the search");
assert.areEqual(undefined, arr[0], "All elements should be deleted [0]");
assert.areEqual(undefined, arr[1], "All elements should be deleted [1]");
assert.areEqual(undefined, arr[2], "All elements should be deleted [2]");
assert.areEqual(undefined, arr[3], "All elements should be deleted [3]");
assert.areEqual(undefined, arr[4], "All elements should be deleted [4]");
assert.areEqual(undefined, arr[5], "All elements should be deleted [5]");
assert.areEqual(6, arr.length, "arr length is still 6");
// Test thisArg argument
var thisArg = { };
assert.areEqual(undefined, arr.find(function (v, i, a) { if (this !== thisArg) { assert.fail("this is not what was passed to second parameter of find()"); } return false; }, thisArg), "Argument passed as the optional second parameter of find should become the this value in the predicate");
// Test and ensure Array.prototype.find calls ToLength
// checks lower bound (negative -> zero)
// upper bound ( pow(2,53)-1 ) cannot be tested in reasonable time
var arr = { '0': 1, '1': 2, '2': 3, length: -1 };
assert.areEqual(undefined, Array.prototype.find.call(arr, function (v, i, a) {assert.fail("shouldn't visit any element when length is less than zero"); return true;}), "find should use ToLength function that clamps length between 0 and pow(2,53)-1");
}
},
{
name: "findIndex takes a predicate and applies it to each element in the array in ascending order until the predicate returns true, then findIndex returns the index of that element",
body: function () {
assert.throws(function () { Array.prototype.findIndex.call(); }, TypeError, "findIndex throws TypeError if it is given no arguments", "Array.prototype.findIndex: 'this' is null or undefined");
assert.throws(function () { Array.prototype.findIndex.call(undefined); }, TypeError, "findIndex throws TypeError if its this argument is undefined", "Array.prototype.findIndex: 'this' is null or undefined");
assert.throws(function () { Array.prototype.findIndex.call(undefined, function () { return true; }, {}); }, TypeError, "findIndex throws TypeError if its this argument is undefined even if given further arguments", "Array.prototype.findIndex: 'this' is null or undefined");
assert.throws(function () { Array.prototype.findIndex.call(null); }, TypeError, "findIndex throws TypeError if its this argument is null", "Array.prototype.findIndex: 'this' is null or undefined");
assert.throws(function () { Array.prototype.findIndex.call(null, function () { return true; }, {}); }, TypeError, "findIndex throws TypeError if its this argument is null even if given further arguments", "Array.prototype.findIndex: 'this' is null or undefined");
var arr = [ 1, 2, 3 ];
// Test missing/invalid predicate argument
assert.throws(function () { arr.findIndex(); }, TypeError, "findIndex throws TypeError if it is given no predicate argument", "Array.prototype.findIndex: argument is not a Function object");
assert.throws(function () { arr.findIndex({}); }, TypeError, "findIndex throws TypeError if it is given a non-Function object predicate argument", "Array.prototype.findIndex: argument is not a Function object");
var fakeArrWithLengthGetter = {
__proto__: Array.prototype,
get length () { throw new Error('getter called'); }
};
assert.throws(function () { fakeArrWithLengthGetter.findIndex(); }, Error, "findIndex gets length property, calling getter method, before checking for a valid predicate function argument", "getter called");
// Test simple predicates matching each element
assert.areEqual( 0, arr.findIndex(function (v, i, a) { return true; }), "Simple predicate always returns true, should find first item");
assert.areEqual( 0, arr.findIndex(function (v, i, a) { if (i >= 1) { assert.fail("shouldn't visit index > 0"); } return v === 1; }), "Simple predicate matching first element, should find first element");
assert.areEqual( 1, arr.findIndex(function (v, i, a) { if (i >= 2) { assert.fail("shouldn't visit index > 1"); } return v === 2; }), "Simple predicate matching second element, should find second element");
assert.areEqual( 2, arr.findIndex(function (v, i, a) { if (i >= 3) { assert.fail("shouldn't visit index > 2"); } return v === 3; }), "Simple predicate matching third element, should find third element");
assert.areEqual(-1, arr.findIndex(function (v, i, a) { if (i >= 3) { assert.fail("shouldn't visit index > 2"); } return v === 4; }), "Simple predicate matching non-existent element, should not find any element");
assert.areEqual( 1, arr.findIndex(function (v, i, a) { if (i >= 2) { assert.fail("shouldn't visit index > 1"); } return v === 2 || v === 3; }), "Simple predicate matching two elements, second and third, should find first of them, i.e. the second element");
// Test adding elements in predicate function
assert.areEqual(-1, arr.findIndex(function (v, i, a) { if (i >= 3) { assert.fail("shouldn't visit index > 2 (initial array length"); } a.push(v + 3); return false; }), "Elements added after findIndex has started shouldn't be included in the search");
assert.areEqual([ 1, 2, 3, 4, 5, 6 ], arr, "Three more elements should be added to end of arr");
// Test deleting elements in predicate function that have not been visited
function f(v, i, a) {
if (i % 2 === 1) {
assert.areEqual(undefined, v, "odd indices should be undefined since they were deleted");
} else {
delete a[i+1];
}
return false;
}
assert.areEqual( -1, arr.findIndex(f), "Elements deleted before being visited after findIndex has started shouldn't be included in the search");
assert.areEqual( 1, arr[0], "Odd elements should be deleted [0]");
assert.areEqual(undefined, arr[1], "Odd elements should be deleted [1]");
assert.areEqual( 3, arr[2], "Odd elements should be deleted [2]");
assert.areEqual(undefined, arr[3], "Odd elements should be deleted [3]");
assert.areEqual( 5, arr[4], "Odd elements should be deleted [4]");
assert.areEqual(undefined, arr[5], "Odd elements should be deleted [5]");
// Test deleting elements in predicate function that have already been visited
assert.areEqual( -1, arr.findIndex(function (v, i, a) { delete a[i]; return false; }), "Elements deleted after being visited has no effect on the search");
assert.areEqual(undefined, arr[0], "All elements should be deleted [0]");
assert.areEqual(undefined, arr[1], "All elements should be deleted [1]");
assert.areEqual(undefined, arr[2], "All elements should be deleted [2]");
assert.areEqual(undefined, arr[3], "All elements should be deleted [3]");
assert.areEqual(undefined, arr[4], "All elements should be deleted [4]");
assert.areEqual(undefined, arr[5], "All elements should be deleted [5]");
assert.areEqual(6, arr.length, "arr length is still 6");
// Test thisArg argument
var thisArg = { };
assert.areEqual(-1, arr.findIndex(function (v, i, a) { if (this !== thisArg) { assert.fail("this is not what was passed to second parameter of findIndex()"); } return false; }, thisArg), "Argument passed as the optional second parameter of findIndex should become the this value in the predicate");
// Test and ensure Array.prototype.findIndex calls ToLength
// checks lower bound (negative -> zero)
// upper bound ( pow(2,53)-1 ) cannot be tested in reasonable time
var arr = { '0': 1, '1': 2, '2': 3, length: -3 };
assert.areEqual(-1, Array.prototype.findIndex.call(arr, function (v, i, a) {assert.fail("shouldn't visit any element when length is less than zero"); return true;}), "findIndex should use ToLength function that clamps length between 0 and pow(2,53)-1");
}
},
{
name: "find and findIndex do not skip 'holes' in arrays and array-likes",
body: function () {
var arr = [,,,,,];
var count = 0;
arr.find(function () { count++; return false; });
assert.areEqual(arr.length, count, "find calls its callback for every element up to the array's length even if those elements are undefined");
count = 0;
arr.findIndex(function () { count++; return false; });
assert.areEqual(arr.length, count, "findIndex calls its callback for every element up to the array's length even if those elements are undefined");
arr = { length: 5, 0: undefined, 1: undefined, 3: undefined };
count = 0;
Array.prototype.find.call(arr, function () { count++; return false; });
assert.areEqual(arr.length, count, "find calls its callback for every element up to the array-like's length even if those elements do not exist on the array-like");
count = 0;
Array.prototype.findIndex.call(arr, function () { count++; return false; });
assert.areEqual(arr.length, count, "findIndex calls its callback for every element up to the array-like's length even if those elements do not exist on the array-like");
}
},
{
name: "repeat takes a string and number and returns a string that is the given string repeated the given number of times",
body: function () {
assert.throws(function () { String.prototype.repeat.call(); }, TypeError, "repeat throws TypeError if it is given no arguments", "String.prototype.repeat: 'this' is null or undefined");
assert.throws(function () { String.prototype.repeat.call(undefined); }, TypeError, "repeat throws TypeError if its this argument is undefined", "String.prototype.repeat: 'this' is null or undefined");
assert.throws(function () { String.prototype.repeat.call(undefined, "", 0); }, TypeError, "repeat throws TypeError if its this argument is undefined even if given further arguments", "String.prototype.repeat: 'this' is null or undefined");
assert.throws(function () { String.prototype.repeat.call(null); }, TypeError, "repeat throws TypeError if its this argument is null", "String.prototype.repeat: 'this' is null or undefined");
assert.throws(function () { String.prototype.repeat.call(null, "", 0); }, TypeError, "repeat throws TypeError if its this argument is null even if given further arguments", "String.prototype.repeat: 'this' is null or undefined");
var s;
s = "";
assert.areEqual("", s.repeat(0), "empty string repeated zero times is the empty string");
assert.areEqual("", s.repeat(NaN), "empty string: NaN converts to zero so produces the empty string");
assert.areEqual("", s.repeat(1), "empty string repeated once is the empty string");
assert.areEqual("", s.repeat(2), "empty string repeated twice is the empty string");
assert.areEqual("", s.repeat(50), "empty string repeated fifty times is the empty string");
s = "a";
assert.areEqual("", s.repeat(0), "single character string repeated zero times is the empty string");
assert.areEqual("", s.repeat(NaN), "single character string: NaN converts to zero so produces the empty string");
assert.areEqual("a", s.repeat(1), "single character string repeated once is itself");
assert.areEqual("aa", s.repeat(2), "single character string repeated twice is a two character string");
assert.areEqual("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", s.repeat(50), "single character string repeated fifty times is a 50 character string");
s = "abc";
assert.areEqual("", s.repeat(0), "multi-character string repeated zero times is the empty string");
assert.areEqual("", s.repeat(NaN), "multi-character string: NaN converts to zero so produces the empty string");
assert.areEqual("abc", s.repeat(1), "multi-character string repeated once is itself");
assert.areEqual("abcabc", s.repeat(2), "3 character string repeated twice is a six character string");
assert.areEqual("abcabcabcabcabcabcabcabcabcabc", s.repeat(10), "3 character string repeated ten times is a 30 character string");
assert.throws(function () { s.repeat(-1); }, RangeError, "negative repeat counts are out of range", "String.prototype.repeat: argument out of range");
assert.throws(function () { s.repeat(-Infinity); }, RangeError, "negative infinite repeat count is out of range", "String.prototype.repeat: argument out of range");
assert.throws(function () { s.repeat(Infinity); }, RangeError, "infinite repeat count is out of range", "String.prototype.repeat: argument out of range");
assert.areEqual("\0\0\0\0", "\0".repeat(4), "null character embedded in string is repeated");
assert.areEqual("a\0ba\0ba\0b", "a\0b".repeat(3), "null character embedded in string mixed with normal characters is repeated");
assert.areEqual("\0abc\0\0abc\0\0abc\0", "\0abc\0".repeat(3), "null character embedded in string surrounding normal characters is repeated");
}
},
{
name: "startsWith returns true if the given search string matches the substring of the given string starting at the given position",
body: function () {
assert.throws(function () { String.prototype.startsWith.call(); }, TypeError, "startsWith throws TypeError if it is given no arguments", "String.prototype.startsWith: 'this' is null or undefined");
assert.throws(function () { String.prototype.startsWith.call(undefined); }, TypeError, "startsWith throws TypeError if its this argument is undefined", "String.prototype.startsWith: 'this' is null or undefined");
assert.throws(function () { String.prototype.startsWith.call(undefined, "", 0); }, TypeError, "startsWith throws TypeError if its this argument is undefined even if given further arguments", "String.prototype.startsWith: 'this' is null or undefined");
assert.throws(function () { String.prototype.startsWith.call(null); }, TypeError, "startsWith throws TypeError if its this argument is null", "String.prototype.startsWith: 'this' is null or undefined");
assert.throws(function () { String.prototype.startsWith.call(null, "", 0); }, TypeError, "startsWith throws TypeError if its this argument is null even if given further arguments", "String.prototype.startsWith: 'this' is null or undefined");
var s;
s = "";
assert.isTrue(s.startsWith(""), "the empty string starts with the empty string");
assert.isFalse(s.startsWith("anything"), "the empty string does not start with any non-empty string");
assert.isTrue(s.startsWith("", 1), "the search position is clipped to exist within the string and thus the the empty string starts with the empty string for any given position argument");
assert.isTrue(s.startsWith("", Infinity), "the empty string starts with the empty string even if given starting position is Infinity, since the starting position is clipped");
s = "abcdefghijklmnopqrstuvwxyz";
assert.isTrue(s.startsWith(""), "a non-empty string starts with the empty string");
assert.isTrue(s.startsWith("a"), "single character prefix substring matches the beginning of the string");
assert.isTrue(s.startsWith("abc"), "prefix substring matches the beginning of the string");
assert.isTrue(s.startsWith("abcdefghijklm"), "long prefix substring string matches the beginning of the string");
assert.isTrue(s.startsWith("abcdefghijklmnopqrstuvwxyz"), "identical string matches the beginning of the string");
assert.isFalse(s.startsWith("bcd"), "non-prefix substring does not match beginning of the string");
assert.isFalse(s.startsWith("mnopqrstuv"), "long non-prefix substring does not match beginning of the string");
assert.isFalse(s.startsWith("xyz"), "suffix substring does not match beginning of the string");
assert.isFalse(s.startsWith("abczzz"), "non-substring with partial prefix match does not match beginning of the string");
assert.isTrue(s.startsWith("", 3), "a non-empty string starts with the empty string at any position");
assert.isTrue(s.startsWith("", 26), "a non-empty string starts with the empty string at its end");
assert.isTrue(s.startsWith("", Infinity), "a non-empty string starts with the empty string at its end (Infinity clipped to end position)");
assert.isTrue(s.startsWith("abcd", -Infinity), "a non-empty string starts with a prefix substring at its beginning (-Infinity clipped to start position)");
assert.isTrue(s.startsWith("bcd", 1), "a non-empty string starts with a given substring at the position where that substring begins");
assert.isTrue(s.startsWith("mnopqrstuv", 12), "a non-empty string starts with a given (long) substring at the position where that substring begins");
assert.isTrue(s.startsWith("xyz", 23), "a non-empty string starts with a suffix substring at the position where the suffix begins");
assert.isTrue(s.startsWith("z", 25), "a non-empty string starts with a single character suffix substring at the last position in the string");
assert.isFalse(s.startsWith("z", 26), "a non-empty string does not start with a single suffix substring at the position past the string");
s = "abc\0def";
assert.isTrue(s.startsWith("abc\0def"), "string with embedded null character starts with itself");
assert.isTrue(s.startsWith("abc\0d"), "string with embedded null character starts with prefix including null character");
assert.isTrue(s.startsWith("abc\0"), "string with embedded null character starts with prefix including and ending with null character in search string");
assert.isFalse(s.startsWith("abc\0abc"), "string with embedded null character does not start with string that is only different after null character");
assert.isFalse(s.startsWith("def\0abc"), "string with embedded null character does not start with string that is only different before null character");
assert.isTrue(s.startsWith("\0def", 3), "string with embedded null character starts with substring beginning with null character at corresponding starting position");
var n = 12345;
assert.isTrue(String.prototype.startsWith.call(n, "123"), "startsWith works even when its this argument is not a string object");
assert.isFalse(String.prototype.startsWith.call(n, "45"), "startsWith works even when its this argument is not a string object");
}
},
{
name: "startsWith throws if searchString is a RegExp",
body: verifyThrowsIfRegExpSearchString.bind(undefined, "startsWith")
},
{
name: "endsWith returns true if the given search string matches the substring of the given string ending at the given position",
body: function () {
assert.throws(function () { String.prototype.endsWith.call(); }, TypeError, "endsWith throws TypeError if it is given no arguments", "String.prototype.endsWith: 'this' is null or undefined");
assert.throws(function () { String.prototype.endsWith.call(undefined); }, TypeError, "endsWith throws TypeError if its this argument is undefined", "String.prototype.endsWith: 'this' is null or undefined");
assert.throws(function () { String.prototype.endsWith.call(undefined, "", 0); }, TypeError, "endsWith throws TypeError if its this argument is undefined even if given further arguments", "String.prototype.endsWith: 'this' is null or undefined");
assert.throws(function () { String.prototype.endsWith.call(null); }, TypeError, "endsWith throws TypeError if its this argument is null", "String.prototype.endsWith: 'this' is null or undefined");
assert.throws(function () { String.prototype.endsWith.call(null, "", 0); }, TypeError, "endsWith throws TypeError if its this argument is null even if given further arguments", "String.prototype.endsWith: 'this' is null or undefined");
var s;
s = "";
assert.isTrue(s.endsWith(""), "the empty string ends with the empty string");
assert.isFalse(s.endsWith("anything"), "the empty string does not end with any non-empty string");
assert.isTrue(s.endsWith("", -1), "the search position is clipped to exist within the string and thus the the empty string ends with the empty string for any given position argument");
assert.isTrue(s.endsWith("", Infinity), "the empty string ends with the empty string even if given ending position is Infinity, since the ending position is clipped");
s = "abcdefghijklmnopqrstuvwxyz";
assert.isTrue(s.endsWith(""), "a non-empty string ends with the empty string");
assert.isTrue(s.endsWith("z"), "single character suffix substring matches the beginning of the string");
assert.isTrue(s.endsWith("xyz"), "suffix substring matches the beginning of the string");
assert.isTrue(s.endsWith("nopqrstuvwxyz"), "long suffix substring string matches the beginning of the string");
assert.isTrue(s.endsWith("abcdefghijklmnopqrstuvwxyz"), "identical string matches the beginning of the string");
assert.isFalse(s.endsWith("wxy"), "non-suffix substring does not match beginning of the string");
assert.isFalse(s.endsWith("mnopqrstuv"), "long non-suffix substring does not match beginning of the string");
assert.isFalse(s.endsWith("abc"), "prefix substring does not match beginning of the string");
assert.isFalse(s.endsWith("aaaxyz"), "non-substring with partial suffix match does not match beginning of the string");
assert.isTrue(s.endsWith("", 23), "a non-empty string ends with the empty string at any position");
assert.isTrue(s.endsWith("", 0), "a non-empty string ends with the empty string at its beginning");
assert.isTrue(s.endsWith("wxyz", Infinity), "a non-empty string ends with a suffix substring at its end (Infinity clipped to end position)");
assert.isTrue(s.endsWith("", -Infinity), "a non-empty string ends with the empty string at its beginning (-Infinity clipped to start position)");
assert.isTrue(s.endsWith("wxy", 25), "a non-empty string ends with a given substring at the position where that substring ends");
assert.isTrue(s.endsWith("mnopqrstuv", 22), "a non-empty string ends with a given (long) substring at the position where that substring ends");
assert.isTrue(s.endsWith("abc", 3), "a non-empty string ends with a prefix substring at the position where the prefix ends");
assert.isTrue(s.endsWith("a", 1), "a non-empty string ends with a single character prefix substring at the first position in the string");
assert.isFalse(s.endsWith("a", 0), "a non-empty string does not end with a single prefix substring at the position past the beginning of the string");
s = "abc\0def";
assert.isTrue(s.endsWith("abc\0def"), "string with embedded null character ends with itself");
assert.isTrue(s.endsWith("c\0def"), "string with embedded null character ends with prefix including null character");
assert.isTrue(s.endsWith("\0def"), "string with embedded null character ends with prefix including and starting with null character in search string");
assert.isFalse(s.endsWith("abc\0abc"), "string with embedded null character does not end with string that is only different after null character");
assert.isFalse(s.endsWith("def\0abc"), "string with embedded null character does not end with string that is only different before null character");
assert.isTrue(s.endsWith("abc\0", 4), "string with embedded null character ends with substring ending with null character at corresponding ending position");
var n = 12345;
assert.isTrue(String.prototype.endsWith.call(n, "345"), "endsWith works even when its this argument is not a string object");
assert.isFalse(String.prototype.endsWith.call(n, "12"), "endsWith works even when its this argument is not a string object");
}
},
{
name: "endsWith throws if searchString is a RegExp",
body: verifyThrowsIfRegExpSearchString.bind(undefined, "endsWith")
},
{
name: "includes returns true if the given search string matches any substring of the given string",
body: function () {
assert.throws(function () { String.prototype.includes.call(); }, TypeError, "includes throws TypeError if it is given no arguments", "String.prototype.includes: 'this' is null or undefined");
assert.throws(function () { String.prototype.includes.call(undefined); }, TypeError, "includes throws TypeError if its this argument is undefined", "String.prototype.includes: 'this' is null or undefined");
assert.throws(function () { String.prototype.includes.call(undefined, "", 0); }, TypeError, "includes throws TypeError if its this argument is undefined even if given further arguments", "String.prototype.includes: 'this' is null or undefined");
assert.throws(function () { String.prototype.includes.call(null); }, TypeError, "includes throws TypeError if its this argument is null", "String.prototype.includes: 'this' is null or undefined");
assert.throws(function () { String.prototype.includes.call(null, "", 0); }, TypeError, "includes throws TypeError if its this argument is null even if given further arguments", "String.prototype.includes: 'this' is null or undefined");
var s;
s = "";
assert.isTrue(s.includes(""), "the empty string includes the empty string");
assert.isFalse(s.includes("anything"), "the empty string includes no non-empty strings");
assert.isTrue(s.includes("", 1), "the search position is clipped to exist within the string and thus the empty string includes itself for any given position argument");
assert.isTrue(s.includes("", Infinity), "the empty string includes the empty string even if given ending position is Infinity, since the ending position is clipped");
s = "abcdefghijklmnopqrstuvwxyz";
assert.isTrue(s.includes(""), "a non-empty string includes the empty string");
assert.isTrue(s.includes("abc"), "substring found at the beginning of the string");
assert.isTrue(s.includes("xyz"), "substring found at the end of the string");
assert.isTrue(s.includes("z"), "substring found at the very end of the string");
assert.isTrue(s.includes("ijklmno"), "substring found in the middle of the string");
assert.isFalse(s.includes("abczzz"), "substring partially matches at the beginning of the string but is not a match");
assert.isFalse(s.includes("xyzaaa"), "substring partially matches at the ending of the string but is not a match");
assert.isFalse(s.includes("zaaa"), "substring partially matches at the very ending of the string but is not a match");
assert.isFalse(s.includes("ijklxyz"), "substring partially matches in the middle of the string but is not a match");
assert.isTrue(s.includes("", 26), "a non-empty string includes the empty string even at the end");
assert.isTrue(s.includes("", Infinity), "a non-empty string includes the empty string even at the end (Infinity clipped to end position)");
assert.isTrue(s.includes("abc", -Infinity), "a non-empty string includes a substring starting at the beginning (-Infinity clipped to start position)");
assert.isFalse(s.includes("z", 26), "a non-empty string includes no non-empty string at the end");
assert.isTrue(s.includes("z", 25), "starting at the last character, a string includes its last character");
assert.isFalse(s.includes("y", 25), "starting at the last character, a string does not contain previous characters");
assert.isFalse(s.includes("abc", 1), "a string does not contain a substring if the only occurrence begins before the given start position");
assert.isTrue(s.includes("mnop", 5), "substring found in the middle of a string after the given start position");
assert.isTrue(s.includes("efg", 4), "substring found in the middle of a string at the given start position");
s = "abc\0def";
assert.isTrue(s.includes("abc\0def"), "string with embedded null character includes itself");
assert.isTrue(s.includes("abc\0d"), "string with embedded null character includes prefix including null character");
assert.isTrue(s.includes("abc\0"), "string with embedded null character includes prefix including and ending with null character in search string");
assert.isTrue(s.includes("\0def"), "string with embedded null character includes prefix including and starting with null character in search string");
assert.isFalse(s.includes("abc\0abc"), "string with embedded null character does not contain string that is only different after null character");
assert.isFalse(s.includes("def\0abc"), "string with embedded null character does not contain string that is only different before null character");
assert.isTrue(s.includes("\0def", 3), "string with embedded null character includes with substring beginning with null character at corresponding starting position");
var n = 12345;
assert.isTrue(String.prototype.includes.call(n, "34"), "includes works even when its this argument is not a string object");
assert.isFalse(String.prototype.includes.call(n, "7"), "includes works even when its this argument is not a string object");
}
},
{
name: "includes throws if searchString is a RegExp",
body: verifyThrowsIfRegExpSearchString.bind(undefined, "includes")
},
{
name: "String.fromCodePoint has correct shape",
body: function() {
assert.areEqual(1, String.fromCodePoint.length, "String.fromCodePoint.length === 1");
}
},
];
testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });