| //------------------------------------------------------------------------------------------------------- |
| // 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" }); |
| |