247 lines
6.6 KiB
Plaintext
247 lines
6.6 KiB
Plaintext
var hasStrictMode = require('has-strict-mode')();
|
|
var v = require('es-value-fixtures');
|
|
var forEach = require('for-each');
|
|
var inspect = require('object-inspect');
|
|
var maxSafeInteger = require('es-abstract/helpers/maxSafeInteger');
|
|
var global = require('globalthis')();
|
|
|
|
var trueThunk = function () { return true; };
|
|
var falseThunk = function () { return false; };
|
|
|
|
var canDistinguishSparseFromUndefined = 0 in [undefined]; // IE 6 - 8 have a bug where this returns false.
|
|
var undefinedIfNoSparseBug = canDistinguishSparseFromUndefined ? undefined : { valueOf: function () { return 0; } };
|
|
|
|
var createArrayLikeFromArray = function createArrayLikeFromArray(arr) {
|
|
var o = {};
|
|
for (var i = 0; i < arr.length; i += 1) {
|
|
if (i in arr) {
|
|
o[i] = arr[i];
|
|
}
|
|
}
|
|
o.length = arr.length;
|
|
return o;
|
|
};
|
|
|
|
var getTestArr = function () {
|
|
var arr = [0, false, null, 'hej', true, undefinedIfNoSparseBug, 3, 2];
|
|
delete arr[6];
|
|
return arr;
|
|
};
|
|
|
|
module.exports = function (findLastIndex, t) {
|
|
forEach(v.nonArrays, function (nonArray) {
|
|
if (nonArray != null) { // eslint-disable-line eqeqeq
|
|
t.equal(
|
|
findLastIndex(nonArray, function () { return true; }),
|
|
typeof nonArray.length === 'number' ? nonArray.length - 1 : -1,
|
|
inspect(nonArray) + ' is not an array'
|
|
);
|
|
}
|
|
});
|
|
|
|
t.test('throws on a non-callable predicate', function (st) {
|
|
forEach(v.nonFunctions, function (nonFunction) {
|
|
st['throws'](
|
|
function () { findLastIndex([], nonFunction); },
|
|
TypeError,
|
|
inspect(nonFunction) + ' is not a Function'
|
|
);
|
|
});
|
|
|
|
st.end();
|
|
});
|
|
|
|
t.test('passes the correct values to the callback', function (st) {
|
|
st.plan(5);
|
|
|
|
var expectedValue = {};
|
|
var arr = [expectedValue];
|
|
var context = {};
|
|
findLastIndex(arr, function (value, key, list) {
|
|
st.equal(arguments.length, 3);
|
|
st.equal(value, expectedValue, 'first argument is the value');
|
|
st.equal(key, 0, 'second argument is the index');
|
|
st.equal(list, arr, 'third argument is the array being iterated');
|
|
st.equal(this, context, 'receiver is the expected value');
|
|
return true;
|
|
}, context);
|
|
|
|
st.end();
|
|
});
|
|
|
|
t.test('does not visit elements added to the array after it has begun', function (st) {
|
|
st.plan(2);
|
|
|
|
var arr = [1, 2, 3];
|
|
var i = 0;
|
|
findLastIndex(arr, function (a) {
|
|
i += 1;
|
|
arr.push(a + 3);
|
|
return i > 3;
|
|
});
|
|
st.deepEqual(arr, [1, 2, 3, 6, 5, 4], 'array has received 3 new elements');
|
|
st.equal(i, 3, 'findLastIndex callback only called thrice');
|
|
|
|
st.end();
|
|
});
|
|
|
|
t.test('does not visit elements deleted from the array after it has begun', function (st) {
|
|
var arr = [1, 2, 3];
|
|
var actual = [];
|
|
findLastIndex(arr, function (x, i) {
|
|
actual.push([i, x]);
|
|
delete arr[1];
|
|
return false;
|
|
});
|
|
st.deepEqual(actual, [[2, 3], [1, undefined], [0, 1]]);
|
|
|
|
st.end();
|
|
});
|
|
|
|
t.test('sets the right context when given none', function (st) {
|
|
var context;
|
|
findLastIndex([1], function () { context = this; });
|
|
st.equal(context, global, 'receiver is global object in sloppy mode');
|
|
|
|
st.test('strict mode', { skip: !hasStrictMode }, function (sst) {
|
|
findLastIndex([1], function () {
|
|
'use strict';
|
|
|
|
context = this;
|
|
});
|
|
sst.equal(context, undefined, 'receiver is undefined in strict mode');
|
|
sst.end();
|
|
});
|
|
|
|
st.end();
|
|
});
|
|
|
|
t.test('empty array', function (st) {
|
|
st.equal(findLastIndex([], trueThunk), -1, 'true thunk callback yields -1');
|
|
st.equal(findLastIndex([], falseThunk), -1, 'false thunk callback yields -1');
|
|
|
|
var counter = 0;
|
|
var callback = function () { counter += 1; };
|
|
findLastIndex([], callback);
|
|
st.equal(counter, 0, 'counter is not incremented');
|
|
|
|
st.end();
|
|
});
|
|
|
|
t.equal(findLastIndex([1, 2, 3], trueThunk), 2, 'returns last index if findLastIndex callback returns true');
|
|
t.equal(findLastIndex([1, 2, 3], falseThunk), -1, 'returns -1 if no callback returns true');
|
|
|
|
t.test('stopping after N elements', function (st) {
|
|
st.test('no context', function (sst) {
|
|
var actual = {};
|
|
var count = 0;
|
|
findLastIndex(getTestArr(), function (obj, index) {
|
|
actual[index] = obj;
|
|
count += 1;
|
|
return count === 4;
|
|
});
|
|
sst.deepEqual(actual, { 4: true, 5: undefinedIfNoSparseBug, 6: undefined, 7: 2 });
|
|
sst.end();
|
|
});
|
|
|
|
st.test('with context', function (sst) {
|
|
var actual = {};
|
|
var context = { actual: actual };
|
|
var count = 0;
|
|
findLastIndex(getTestArr(), function (obj, index) {
|
|
this.actual[index] = obj;
|
|
count += 1;
|
|
return count === 4;
|
|
}, context);
|
|
sst.deepEqual(actual, { 4: true, 5: undefinedIfNoSparseBug, 6: undefined, 7: 2 });
|
|
sst.end();
|
|
});
|
|
|
|
st.test('arraylike, no context', function (sst) {
|
|
var actual = {};
|
|
var count = 0;
|
|
findLastIndex(createArrayLikeFromArray(getTestArr()), function (obj, index) {
|
|
actual[index] = obj;
|
|
count += 1;
|
|
return count === 4;
|
|
});
|
|
sst.deepEqual(actual, { 4: true, 5: undefinedIfNoSparseBug, 6: undefined, 7: 2 });
|
|
sst.end();
|
|
});
|
|
|
|
st.test('arraylike, context', function (sst) {
|
|
var actual = {};
|
|
var count = 0;
|
|
var context = { actual: actual };
|
|
findLastIndex(createArrayLikeFromArray(getTestArr()), function (obj, index) {
|
|
this.actual[index] = obj;
|
|
count += 1;
|
|
return count === 4;
|
|
}, context);
|
|
sst.deepEqual(actual, { 4: true, 5: undefinedIfNoSparseBug, 6: undefined, 7: 2 });
|
|
sst.end();
|
|
});
|
|
|
|
st.end();
|
|
});
|
|
|
|
t.test('list arg boxing', function (st) {
|
|
st.plan(3);
|
|
|
|
findLastIndex('bar', function (item, index, list) {
|
|
st.equal(item, 'r', 'last letter matches');
|
|
st.equal(typeof list, 'object', 'primitive list arg is boxed');
|
|
st.equal(Object.prototype.toString.call(list), '[object String]', 'boxed list arg is a String');
|
|
return true;
|
|
});
|
|
|
|
st.end();
|
|
});
|
|
|
|
t.test('array altered during loop', function (st) {
|
|
var arr = ['Shoes', 'Car', 'Bike'];
|
|
var results = [];
|
|
|
|
findLastIndex(arr, function (kValue) {
|
|
if (results.length === 0) {
|
|
arr.splice(1, 1);
|
|
}
|
|
results.push(kValue);
|
|
});
|
|
|
|
st.equal(results.length, 3, 'predicate called three times');
|
|
st.deepEqual(results, ['Bike', 'Bike', 'Shoes']);
|
|
|
|
results = [];
|
|
arr = ['Skateboard', 'Barefoot'];
|
|
findLastIndex(arr, function (kValue) {
|
|
if (results.length === 0) {
|
|
arr.push('Motorcycle');
|
|
arr[0] = 'Magic Carpet';
|
|
}
|
|
|
|
results.push(kValue);
|
|
});
|
|
|
|
st.equal(results.length, 2, 'predicate called twice');
|
|
st.deepEqual(results, ['Barefoot', 'Magic Carpet']);
|
|
|
|
st.end();
|
|
});
|
|
|
|
t.test('maximum index', function (st) {
|
|
// https://github.com/tc39/test262/pull/3775
|
|
|
|
var arrayLike = { length: Number.MAX_VALUE };
|
|
var calledWithIndex = [];
|
|
|
|
findLastIndex(arrayLike, function (_, index) {
|
|
calledWithIndex.push(index);
|
|
return true;
|
|
});
|
|
|
|
st.deepEqual(calledWithIndex, [maxSafeInteger - 1], 'predicate invoked once');
|
|
st.end();
|
|
});
|
|
};
|