[mjsunit] Make Array deepEquals respect holes

Don't let holes compare equal to undefined, to avoid tests accidentally
succeeding when operating on the wrong holeyness.

Change-Id: I5fe1eea8b3e718389b46d542be45cca578a1080c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4091024
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/main@{#84769}
This commit is contained in:
Leszek Swirski 2022-12-09 09:56:42 +01:00 committed by V8 LUCI CQ
parent 292c0a637a
commit c5dc2fc9c1
21 changed files with 41 additions and 34 deletions

View File

@ -12,6 +12,6 @@ var obj = {
obj[Symbol.isConcatSpreadable] = true;
var obj2 = { length: 3, "0": "0", "1": "1", "2": "2" };
var arr = ["X", "Y", "Z"];
assertEquals([void 0, "A", void 0, "B", void 0, "C",
assertEquals([, "A", , "B", , "C",
{ "length": 3, "0": "0", "1": "1", "2": "2" },
"X", "Y", "Z"], Array.prototype.concat.call(obj, obj2, arr));

View File

@ -12,6 +12,6 @@ var obj = {
obj[Symbol.isConcatSpreadable] = true;
var obj2 = { length: 3, "0": "0", "1": "1", "2": "2" };
var arr = ["X", "Y", "Z"];
assertEquals([void 0, "A", void 0, "B", void 0, "C",
assertEquals([, "A", , "B", , "C",
{ "length": 3, "0": "0", "1": "1", "2": "2" },
"X", "Y", "Z"], Array.prototype.concat.call(obj, obj2, arr));

View File

@ -7,5 +7,5 @@ var arr = [];
arr[4] = "Item 4";
arr[8] = "Item 8";
var arr2 = [".", "!", "?"];
assertEquals([void 0, void 0, void 0, void 0, "Item 4", void 0, void 0,
void 0, "Item 8", ".", "!", "?"], arr.concat(arr2));
assertEquals(
[, , , , 'Item 4', , , , 'Item 8', '.', '!', '?'], arr.concat(arr2));

View File

@ -5,4 +5,4 @@
var args = (function(a) { return arguments; })(1,2,3);
delete args[1];
args[Symbol.isConcatSpreadable] = true;
assertEquals([1, void 0, 3, 1, void 0, 3], [].concat(args, args));
assertEquals([1, , 3, 1, , 3], [].concat(args, args));

View File

@ -7,4 +7,4 @@ args[Symbol.isConcatSpreadable] = true;
assertEquals([1, 2, 3, 1, 2, 3], [].concat(args, args));
Object.defineProperty(args, "length", { value: 6 });
assertEquals([1, 2, 3, void 0, void 0, void 0], [].concat(args));
assertEquals([1, 2, 3, , , ,], [].concat(args));

View File

@ -7,4 +7,4 @@ args[Symbol.isConcatSpreadable] = true;
assertEquals([1, 2, 3, 1, 2, 3], [].concat(args, args));
Object.defineProperty(args, "length", { value: 6 });
assertEquals([1, 2, 3, void 0, void 0, void 0], [].concat(args));
assertEquals([1, 2, 3, , ,, ], [].concat(args));

View File

@ -14,7 +14,7 @@ assertEquals([1, 2, 3], [].concat(fn));
Function.prototype[Symbol.isConcatSpreadable] = true;
// Functions may be concat-spreadable
assertEquals([void 0, void 0, void 0], [].concat(function(a,b,c) {}));
assertEquals(new Array(3), [].concat(function(a,b,c) {}));
Function.prototype[0] = 1;
Function.prototype[1] = 2;
Function.prototype[2] = 3;

View File

@ -36,7 +36,7 @@ assertEquals(["get", target, "length", obj], log[1]);
target.length = 3;
log.length = 0;
assertEquals(["a", "b", undefined], [].concat(obj));
assertEquals(["a", "b", ,], [].concat(obj));
assertEquals(7, log.length);
for (var i in log) assertSame(target, log[i][1]);
assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[0]);
@ -48,7 +48,7 @@ assertEquals(["get", target, "1", obj], log[5]);
assertEquals(["has", target, "2"], log[6]);
log.length = 0;
assertEquals(["a", "b", undefined], Array.prototype.concat.apply(obj));
assertEquals(["a", "b", ,], Array.prototype.concat.apply(obj));
assertEquals(7, log.length);
for (var i in log) assertSame(target, log[i][1]);
assertEquals(["get", target, Symbol.isConcatSpreadable, obj], log[0]);

View File

@ -16,7 +16,7 @@ assertEquals([1, 2, 3], [].concat(re));
RegExp.prototype[Symbol.isConcatSpreadable] = true;
RegExp.prototype.length = 3;
assertEquals([void 0, void 0, void 0], [].concat(/abc/));
assertEquals(new Array(3), [].concat(/abc/));
RegExp.prototype[0] = 1;
RegExp.prototype[1] = 2;
RegExp.prototype[2] = 3;

View File

@ -5,7 +5,7 @@
"use strict";
var obj = { length: 5 };
obj[Symbol.isConcatSpreadable] = true;
assertEquals([void 0, void 0, void 0, void 0, void 0], [].concat(obj));
assertEquals(new Array(5), [].concat(obj));
obj.length = 4000;
assertEquals(new Array(4000), [].concat(obj));

View File

@ -7,4 +7,4 @@ args[Symbol.isConcatSpreadable] = true;
assertEquals([1, 2, 3, 1, 2, 3], [].concat(args, args));
Object.defineProperty(args, "length", { value: 6 });
assertEquals([1, 2, 3, void 0, void 0, void 0], [].concat(args));
assertEquals([1, 2, 3, , , ,], [].concat(args));

View File

@ -6,7 +6,7 @@
var a = [, 2];
assertEquals([, 2], [...a]);
assertEquals([undefined, 2], [...a]);
assertTrue([...a].hasOwnProperty(0));
assertTrue([2, ...a].hasOwnProperty(1));

View File

@ -142,7 +142,7 @@ var group = () => {
}
assertEquals(group(), [
['undefined', [,]],
['undefined', [undefined]],
]);
array.__proto__.push(6);

View File

@ -147,7 +147,7 @@ var groupToMap = () => {
}
assertEquals(groupToMap(), [
[undefined, [,]],
[undefined, [undefined]],
]);
array.__proto__.push(6);
assertEquals(groupToMap(), [

View File

@ -7,32 +7,39 @@
assertEquals(1, Array.prototype.toSorted.length);
assertEquals("toSorted", Array.prototype.toSorted.name);
function TerribleCopy(input) {
function TerribleCopy(input, fillHoles) {
let copy;
if (Array.isArray(input)) {
copy = [...input];
copy = new Array(input.length);
} else {
copy = { length: input.length };
for (let i = 0; i < input.length; i++) {
}
for (let i = 0; i < input.length; ++i) {
if (i in input) {
copy[i] = input[i];
} else if (fillHoles) {
copy[i] = undefined;
}
}
return copy;
}
function AssertToSortedAndSortSameResult(input, ...args) {
const orig = TerribleCopy(input);
const orig = TerribleCopy(input, false);
const s = Array.prototype.toSorted.apply(input, args);
const copy = TerribleCopy(input);
const copy = TerribleCopy(input, true);
Array.prototype.sort.apply(copy, args);
// The in-place sorted version should be pairwise equal to the toSorted,
// modulo being an actual Array if the input is generic.
// modulo being an actual Array if the input is generic, and holes should
// be filled with undefined.
if (Array.isArray(input)) {
assertEquals(copy, s);
} else {
assertEquals(copy.length, s.length);
for (let i = 0; i < copy.length; i++) {
assertTrue(i in copy);
assertTrue(i in s);
assertEquals(copy[i], s[i]);
}
}

View File

@ -8,7 +8,7 @@
function f1() {
const x = [,];
x[1] = 42;
assertEquals([undefined, 42], x);
assertEquals([, 42], x);
}
%PrepareFunctionForOptimization(f1);

View File

@ -70,6 +70,8 @@ function testAssertEquals(a, b) {
testAssertEquals(new Array(1), new Array(1));
testAssertNotEquals(new Array(1), new Array(2));
testAssertEquals([,,], new Array(2));
// The difference between empty and undefined is not ignored.
testAssertNotEquals([undefined], new Array(1));
})();
(function TestAssertEqualsArraysNested() {
@ -80,9 +82,7 @@ function testAssertEquals(a, b) {
})();
(function TestAssertEqualsArrayProperties() {
// Difference between empty and undefined is ignored by the assert
// implementation as well as additional properties.
testAssertEquals([undefined], new Array(1));
// Array properties are ignored.
let arrWithProp = new Array();
arrWithProp.myProperty = 'Additional property';
testAssertEquals([], arrWithProp);

View File

@ -432,6 +432,7 @@ var prettyPrinted;
return false;
}
for (var i = 0; i < a.length; i++) {
if ((i in a) !== (i in b)) return false;
if (!deepEquals(a[i], b[i])) return false;
}
return true;

View File

@ -4,7 +4,7 @@
// Make sure that packed and unpacked array slices are still properly handled
var holey_array = [1, 2, 3, 4, 5,,,,,,];
assertEquals([undefined], holey_array.slice(6, 7));
assertEquals(new Array(1), holey_array.slice(6, 7));
assertEquals(undefined, holey_array.slice(6, 7)[0]);
assertEquals([], holey_array.slice(2, 1));
assertEquals(3, holey_array.slice(2, 3)[0]);

View File

@ -25,7 +25,7 @@
}
b = Array.of.call(f,1,2);
b[4] = 1;
assertEquals(b, [1, 2, undefined, undefined, 1]);
assertEquals(b, [1, 2, , , 1]);
})();
// Tests that using Array.of with a constructor returning an object with an

View File

@ -373,8 +373,7 @@ d8.file.execute('test/mjsunit/typedarray-helpers.js');
const fixedLength = new ctor(rab, 0, 4);
const evil = { valueOf: () => { rab.resize(2 * ctor.BYTES_PER_ELEMENT);
return 0; }};
assertEquals([undefined, undefined, undefined, undefined],
sliceHelper(fixedLength, evil));
assertEquals(new Array(4), sliceHelper(fixedLength, evil));
assertEquals(2 * ctor.BYTES_PER_ELEMENT, rab.byteLength);
}
for (let ctor of ctors) {
@ -401,8 +400,7 @@ d8.file.execute('test/mjsunit/typedarray-helpers.js');
const fixedLength = new ctor(rab, 0, 4);
const evil = { valueOf: () => { %ArrayBufferDetach(rab);
return 0; }};
assertEquals([undefined, undefined, undefined, undefined],
sliceHelper(fixedLength, evil));
assertEquals(new Array(4), sliceHelper(fixedLength, evil));
assertEquals(0, rab.byteLength);
}
for (let ctor of ctors) {
@ -414,8 +412,9 @@ d8.file.execute('test/mjsunit/typedarray-helpers.js');
}
const evil = { valueOf: () => { %ArrayBufferDetach(rab);
return 0; }};
assertEquals([undefined, undefined, undefined, undefined],
ToNumbers(sliceHelper(lengthTracking, evil)));
assertEquals(
[undefined, undefined, undefined, undefined],
ToNumbers(sliceHelper(lengthTracking, evil)));
assertEquals(0, rab.byteLength);
}
})();