/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ //----------------------------------------------------------------------------- var BUGNUMBER = 1704385; var summary = 'Array.prototype.findLast and Array.prototype.findLastIndex'; print(BUGNUMBER + ": " + summary); /************** * BEGIN TEST * **************/ function isString(v, index, array) { assertEq(array[index], v); return typeof v == 'string'; } function dumpError(e) { var s = e.name + ': ' + e.message + ' File: ' + e.fileName + ', Line: ' + e.lineNumber + ', Stack: ' + e.stack; return s; } var expect; var actual; var obj; var strings = ['hello', 'Array', 'WORLD']; var mixed = [0, '1', 2]; var sparsestrings = new Array(); sparsestrings[2] = 'sparse'; var arraylike = {0:0, 1:'string', 2:2, length:3}; // array for which JSObject::isIndexed() holds. var indexedArray = []; Object.defineProperty(indexedArray, 42, { get: function() { return 42; } }); Object.defineProperty(indexedArray, 142, { get: function() { return 'string'; } }); // findLast and findLastIndex have 1 required argument expect = 1; actual = Array.prototype.findLast.length; reportCompare(expect, actual, 'Array.prototype.findLast.length == 1'); actual = Array.prototype.findLastIndex.length; reportCompare(expect, actual, 'Array.prototype.findLastIndex.length == 1'); // throw TypeError if no predicate specified expect = 'TypeError'; try { strings.findLast(); actual = 'no error'; } catch(e) { actual = e.name; } reportCompare(expect, actual, 'Array.findLast(undefined) throws TypeError'); try { strings.findLastIndex(); actual = 'no error'; } catch(e) { actual = e.name; } reportCompare(expect, actual, 'Array.findLastIndex(undefined) throws TypeError'); // Length gets treated as integer, not uint32 obj = { length: -4294967295, 0: 42 }; expected = undefined; actual = Array.prototype.findLast.call(obj, () => true); reportCompare(expected, actual, 'findLast correctly treats "length" as an integer'); expected = -1 actual = Array.prototype.findLastIndex.call(obj, () => true); reportCompare(expected, actual, 'findLastIndex correctly treats "length" as an integer'); // test findLast and findLastIndex results try { expect = 'WORLD'; actual = strings.findLast(isString); } catch(e) { actual = dumpError(e); } reportCompare(expect, actual, 'strings: findLast finds last string element'); try { expect = 2; actual = strings.findLastIndex(isString); } catch(e) { actual = dumpError(e); } reportCompare(expect, actual, 'strings: findLastIndex finds last string element'); try { expect = '1'; actual = mixed.findLast(isString); } catch(e) { actual = dumpError(e); } reportCompare(expect, actual, 'mixed: findLast finds last string element'); try { expect = 1; actual = mixed.findLastIndex(isString); } catch(e) { actual = dumpError(e); } reportCompare(expect, actual, 'mixed: findLastIndex finds last string element'); try { expect = 'sparse'; actual = sparsestrings.findLast(isString); } catch(e) { actual = dumpError(e); } reportCompare(expect, actual, 'sparsestrings: findLast finds last string element'); try { expect = 2; actual = sparsestrings.findLastIndex(isString); } catch(e) { actual = dumpError(e); } reportCompare(expect, actual, 'sparsestrings: findLastIndex finds first string element'); try { expect = 'string'; actual = [].findLast.call(arraylike, isString); } catch(e) { actual = dumpError(e); } reportCompare(expect, actual, 'arraylike: findLast finds last string element'); try { expect = 1; actual = [].findLastIndex.call(arraylike, isString); } catch(e) { actual = dumpError(e); } reportCompare(expect, actual, 'arraylike: findLastIndex finds last string element'); try { expect = 1; actual = 0; Array.prototype.findLast.call({get 0(){ actual++ }, length: 1}, ()=>true); } catch(e) { actual = dumpError(e); } reportCompare(expect, actual, 'arraylike with getter: getter only called once'); try { expect = 'string'; actual = [].findLast.call(indexedArray, isString); } catch(e) { actual = dumpError(e); } reportCompare(expect, actual, 'indexedArray: findLast finds last string element'); try { expect = 142; actual = [].findLastIndex.call(indexedArray, isString); } catch(e) { actual = dumpError(e); } reportCompare(expect, actual, 'indexedArray: findLastIndex finds last string element'); // Bug 1058394 - Array#findLast and Array#findLastIndex no longer skip holes too. var sparseArray = [1,,]; var sparseArrayWithInheritedDataProperty = Object.setPrototypeOf([1,,,], { __proto__: [].__proto__, 2 : 0 }); var sparseArrayWithInheritedAccessorProperty = Object.setPrototypeOf([1,,,], { __proto__: [].__proto__, get 2(){ throw "get 2"; } }); try { expect = undefined; actual = sparseArray.findLast(() => true); } catch(e) { actual = dumpError(e); } reportCompare(expect, actual, "Don't skip holes in Array#findLast."); try { expect = 1; actual = sparseArray.findLastIndex(() => true); } catch(e) { actual = dumpError(e); } reportCompare(expect, actual, "Don't skip holes in Array#findLastIndex."); try { expect = 0; actual = sparseArrayWithInheritedDataProperty.findLast(v => v === 0); } catch(e) { actual = dumpError(e); } reportCompare(expect, actual, "Array#findLast can find inherited data property."); try { expect = 2; actual = sparseArrayWithInheritedDataProperty.findLastIndex(v => v === 0); } catch(e) { actual = dumpError(e); } reportCompare(expect, actual, "Array#findLastIndex can find inherited data property."); try { expect = "get 2"; actual = sparseArrayWithInheritedAccessorProperty.findLast(() => true); } catch(e) { actual = e; } reportCompare(expect, actual, "Array#findLast can find inherited accessor property."); try { expect = "get 2"; actual = sparseArrayWithInheritedAccessorProperty.findLastIndex(() => true); } catch(e) { actual = e; } reportCompare(expect, actual, "Array#findLastIndex can find inherited accessor property.");