ArraySetLength deletes array index properties in descending order. When a non-configurable index cannot be deleted, the length is restored to that index plus one, and lower indexes are not touched. The dictionary indexed storage path already restored the final length, but removed configurable entries below the failing index too. Keep those entries when truncation stops early and add sparse array coverage.
136 lines
4.2 KiB
JavaScript
136 lines
4.2 KiB
JavaScript
describe("errors", () => {
|
|
test("invalid array length value", () => {
|
|
var a = [1, 2, 3];
|
|
[undefined, "foo", -1, Infinity, -Infinity, NaN].forEach(value => {
|
|
expect(() => {
|
|
a.length = value;
|
|
}).toThrowWithMessage(RangeError, "Invalid array length");
|
|
expect(a).toHaveLength(3);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("normal behavior", () => {
|
|
test("extend array by setting length", () => {
|
|
var a = [1, 2, 3];
|
|
a.length = 5;
|
|
expect(a).toEqual([1, 2, 3, undefined, undefined]);
|
|
});
|
|
|
|
test("truncate array by setting length", () => {
|
|
var a = [1, 2, 3];
|
|
a.length = 2;
|
|
expect(a).toEqual([1, 2]);
|
|
a.length = 0;
|
|
expect(a).toEqual([]);
|
|
});
|
|
|
|
test("length value is coerced to number if possible", () => {
|
|
var a = [1, 2, 3];
|
|
a.length = "42";
|
|
expect(a).toHaveLength(42);
|
|
a.length = [];
|
|
expect(a).toHaveLength(0);
|
|
a.length = true;
|
|
expect(a).toHaveLength(1);
|
|
});
|
|
|
|
test("setting a huge array length", () => {
|
|
var a = [];
|
|
a.length = 0x80000000;
|
|
expect(a.length).toEqual(0x80000000);
|
|
|
|
var b = [];
|
|
b.length = 0x80000001;
|
|
expect(b.length).toEqual(0x80000001);
|
|
});
|
|
|
|
test("should not remove non-configurable values", () => {
|
|
var a = [1, undefined, 3];
|
|
Object.defineProperty(a, 1, { configurable: false, value: 2 });
|
|
expect(a.length).toEqual(3);
|
|
|
|
expect((a.length = 1)).toEqual(1);
|
|
expect(a.length).toEqual(2);
|
|
expect(a[1]).toEqual(2);
|
|
});
|
|
|
|
test("should stop truncating sparse arrays at non-configurable values", () => {
|
|
var a = [0, , 2, , , 5];
|
|
Object.defineProperty(a, 100, { configurable: true, value: "deleted" });
|
|
Object.defineProperty(a, 50, { configurable: false, value: "kept" });
|
|
Object.defineProperty(a, 40, { configurable: true, value: "also kept" });
|
|
|
|
expect((a.length = 1)).toEqual(1);
|
|
expect(a.length).toEqual(51);
|
|
expect(Object.getOwnPropertyNames(a).sort()).toEqual(["0", "2", "40", "5", "50", "length"]);
|
|
|
|
function strictTruncate() {
|
|
"use strict";
|
|
a.length = 1;
|
|
}
|
|
expect(strictTruncate).toThrow(TypeError);
|
|
expect(a.length).toEqual(51);
|
|
expect(Object.getOwnPropertyNames(a).sort()).toEqual(["0", "2", "40", "5", "50", "length"]);
|
|
});
|
|
});
|
|
|
|
describe("behavior when obj has Array prototype", () => {
|
|
function ArrExtend() {}
|
|
ArrExtend.prototype = [10, 11, 12];
|
|
|
|
test("Has the properties from prototype", () => {
|
|
var arr = new ArrExtend();
|
|
expect(arr.length).toEqual(3);
|
|
expect(arr[0]).toEqual(10);
|
|
expect(arr[1]).toEqual(11);
|
|
expect(arr[2]).toEqual(12);
|
|
});
|
|
|
|
test("Can override length to any value", () => {
|
|
[null, "Hello friends :^)", -6, 0].forEach(value => {
|
|
var arr = new ArrExtend();
|
|
arr.length = value;
|
|
expect(arr.length).toEqual(value);
|
|
|
|
// should not wipe high values
|
|
expect(arr[0]).toEqual(10);
|
|
expect(arr[1]).toEqual(11);
|
|
expect(arr[2]).toEqual(12);
|
|
});
|
|
});
|
|
|
|
test("Can call array methods", () => {
|
|
var arr = new ArrExtend();
|
|
arr.push(1);
|
|
expect(arr.length).toEqual(4);
|
|
expect(arr[3]).toEqual(1);
|
|
});
|
|
|
|
test("If length overwritten uses that value", () => {
|
|
[null, "Hello friends :^)", -6, 0].forEach(value => {
|
|
var arr = new ArrExtend();
|
|
arr.length = value;
|
|
expect(arr.length).toEqual(value);
|
|
|
|
arr.push(99);
|
|
expect(arr.length).toEqual(1);
|
|
expect(arr[0]).toEqual(99);
|
|
|
|
// should not wipe higher value
|
|
expect(arr[1]).toEqual(11);
|
|
expect(arr[2]).toEqual(12);
|
|
|
|
arr.push(100);
|
|
|
|
expect(arr.length).toEqual(2);
|
|
expect(arr[1]).toEqual(100);
|
|
|
|
arr.length = 0;
|
|
// should not wipe values since we are not an array
|
|
expect(arr[0]).toEqual(99);
|
|
expect(arr[1]).toEqual(100);
|
|
expect(arr[2]).toEqual(12);
|
|
});
|
|
});
|
|
});
|