[mjsunit] assertEquals: Assert equality of non-enumerable properties too
assertEquals() compares objects by comparing each property for both objects. This was done by using Object.keys() which however only returns enumerable properties. With this change also non-enumerable properties are compared. Still, the comparison doesn't require the properties to be equal. So, if one property is marked enumerable in one object but not the other, the objects would still be considered equal. This could be adapted in a follow-up CL if desired. The prototype is still ignored for the comparison. Change-Id: I1bb9df055bfb764ac1c02d971ac6f4a50f4a98e8 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3876384 Commit-Queue: Matthias Liedtke <mliedtke@chromium.org> Reviewed-by: Marja Hölttä <marja@chromium.org> Cr-Commit-Position: refs/heads/main@{#83058}
This commit is contained in:
parent
178f2eeb13
commit
319af35d1d
@ -431,12 +431,17 @@ function TestSortOnTypedArray() {
|
||||
var array = new Int8Array([10,9,8,7,6,5,4,3,2,1]);
|
||||
Object.defineProperty(array, "length", {value: 5});
|
||||
Array.prototype.sort.call(array);
|
||||
assertEquals(array, new Int8Array([10,6,7,8,9,5,4,3,2,1]));
|
||||
// Elements within `length` sorted by string comparison.
|
||||
var expected = new Int8Array([10,6,7,8,9,5,4,3,2,1]);
|
||||
Object.defineProperty(expected, "length", {value: 5});
|
||||
assertEquals(expected, array);
|
||||
|
||||
var array = new Int8Array([10,9,8,7,6,5,4,3,2,1]);
|
||||
Object.defineProperty(array, "length", {value: 15});
|
||||
Array.prototype.sort.call(array);
|
||||
assertEquals(array, new Int8Array([1,10,2,3,4,5,6,7,8,9]));
|
||||
var expected = new Int8Array([1,10,2,3,4,5,6,7,8,9]);
|
||||
Object.defineProperty(expected, "length", {value: 15});
|
||||
assertEquals(expected, array);
|
||||
}
|
||||
TestSortOnTypedArray();
|
||||
|
||||
|
@ -6,10 +6,10 @@
|
||||
|
||||
// Check that Error.prepareStackTrace properly marks async frames.
|
||||
Error.prepareStackTrace = (e, frames) => {
|
||||
assertEquals(two, frames[0].getFunction());
|
||||
assertSame(two, frames[0].getFunction());
|
||||
assertEquals(two.name, frames[0].getFunctionName());
|
||||
assertFalse(frames[0].isAsync());
|
||||
assertEquals(two, frames[1].getFunction());
|
||||
assertSame(one, frames[1].getFunction());
|
||||
assertEquals(one.name, frames[1].getFunctionName());
|
||||
assertTrue(frames[1].isAsync());
|
||||
return frames;
|
||||
|
@ -4,6 +4,13 @@
|
||||
|
||||
// Flags: --allow-natives-syntax --noturbo-inlining
|
||||
|
||||
// Helper function to compare two arguments objects of strict mode functions.
|
||||
// Access to arguments.callee results in TypeError for them, so assertEquals
|
||||
// can't be used directly.
|
||||
function assertEqualsArgumentsStrict(a, b) {
|
||||
assertEquals(JSON.stringify(a), JSON.stringify(b));
|
||||
}
|
||||
|
||||
// Ensure that arguments in sloppy mode function works
|
||||
// properly when called directly from optimized code.
|
||||
(function() {
|
||||
@ -28,13 +35,13 @@
|
||||
function f() { return g(1, 2, 3); }
|
||||
|
||||
%PrepareFunctionForOptimization(f);
|
||||
assertEquals(g(1, 2, 3), f());
|
||||
assertEquals(g(1, 2, 3), f());
|
||||
assertEqualsArgumentsStrict(g(1, 2, 3), f());
|
||||
assertEqualsArgumentsStrict(g(1, 2, 3), f());
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
assertEquals(g(1, 2, 3), f());
|
||||
assertEqualsArgumentsStrict(g(1, 2, 3), f());
|
||||
%PrepareFunctionForOptimization(g);
|
||||
%OptimizeFunctionOnNextCall(g);
|
||||
assertEquals(g(1, 2, 3), f());
|
||||
assertEqualsArgumentsStrict(g(1, 2, 3), f());
|
||||
})();
|
||||
|
||||
// Ensure that arguments in sloppy mode function works
|
||||
@ -63,14 +70,14 @@
|
||||
function f() { return g(1, 2, 3); }
|
||||
|
||||
%PrepareFunctionForOptimization(f);
|
||||
assertEquals(g(1, 2, 3), f());
|
||||
assertEquals(g(1, 2, 3), f());
|
||||
assertEqualsArgumentsStrict(g(1, 2, 3), f());
|
||||
assertEqualsArgumentsStrict(g(1, 2, 3), f());
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
assertEquals(g(1, 2, 3), f());
|
||||
assertEqualsArgumentsStrict(g(1, 2, 3), f());
|
||||
%PrepareFunctionForOptimization(g);
|
||||
assertEquals(g(1, 2, 3), f());
|
||||
assertEqualsArgumentsStrict(g(1, 2, 3), f());
|
||||
%OptimizeFunctionOnNextCall(g);
|
||||
assertEquals(g(1, 2, 3), f());
|
||||
assertEqualsArgumentsStrict(g(1, 2, 3), f());
|
||||
})();
|
||||
|
||||
// Ensure that `Function.arguments` accessor does the
|
||||
|
@ -146,11 +146,11 @@ function TestArrayIteratorPrototype() {
|
||||
|
||||
var ArrayIteratorPrototype = iterator.__proto__;
|
||||
|
||||
assertEquals(ArrayIteratorPrototype, array[Symbol.iterator]().__proto__);
|
||||
assertEquals(ArrayIteratorPrototype, array.keys().__proto__);
|
||||
assertEquals(ArrayIteratorPrototype, array.entries().__proto__);
|
||||
assertSame(ArrayIteratorPrototype, array[Symbol.iterator]().__proto__);
|
||||
assertSame(ArrayIteratorPrototype, array.keys().__proto__);
|
||||
assertSame(ArrayIteratorPrototype, array.entries().__proto__);
|
||||
|
||||
assertEquals(Object.prototype, ArrayIteratorPrototype.__proto__);
|
||||
assertSame(Object.prototype, ArrayIteratorPrototype.__proto__.__proto__);
|
||||
|
||||
assertFalse(ArrayIteratorPrototype.hasOwnProperty('constructor'));
|
||||
assertArrayEquals(['next'],
|
||||
|
@ -18,13 +18,13 @@ test(function TestSetIterator() {
|
||||
|
||||
var SetIteratorPrototype = iter.__proto__;
|
||||
assertFalse(SetIteratorPrototype.hasOwnProperty('constructor'));
|
||||
assertEquals(SetIteratorPrototype.__proto__, Object.prototype);
|
||||
assertSame(SetIteratorPrototype.__proto__.__proto__, Object.prototype);
|
||||
|
||||
var propertyNames = Object.getOwnPropertyNames(SetIteratorPrototype);
|
||||
assertArrayEquals(['next'], propertyNames);
|
||||
|
||||
assertEquals(new Set().values().__proto__, SetIteratorPrototype);
|
||||
assertEquals(new Set().entries().__proto__, SetIteratorPrototype);
|
||||
assertSame(new Set().values().__proto__, SetIteratorPrototype);
|
||||
assertSame(new Set().entries().__proto__, SetIteratorPrototype);
|
||||
|
||||
assertEquals("[object Set Iterator]",
|
||||
Object.prototype.toString.call(iter));
|
||||
@ -163,14 +163,14 @@ test(function TestMapIterator() {
|
||||
|
||||
var MapIteratorPrototype = iter.__proto__;
|
||||
assertFalse(MapIteratorPrototype.hasOwnProperty('constructor'));
|
||||
assertEquals(MapIteratorPrototype.__proto__, Object.prototype);
|
||||
assertSame(MapIteratorPrototype.__proto__.__proto__, Object.prototype);
|
||||
|
||||
var propertyNames = Object.getOwnPropertyNames(MapIteratorPrototype);
|
||||
assertArrayEquals(['next'], propertyNames);
|
||||
|
||||
assertEquals(new Map().values().__proto__, MapIteratorPrototype);
|
||||
assertEquals(new Map().keys().__proto__, MapIteratorPrototype);
|
||||
assertEquals(new Map().entries().__proto__, MapIteratorPrototype);
|
||||
assertSame(new Map().values().__proto__, MapIteratorPrototype);
|
||||
assertSame(new Map().keys().__proto__, MapIteratorPrototype);
|
||||
assertSame(new Map().entries().__proto__, MapIteratorPrototype);
|
||||
|
||||
assertEquals("[object Map Iterator]",
|
||||
Object.prototype.toString.call(iter));
|
||||
|
@ -54,7 +54,7 @@ function TestStringIteratorPrototype() {
|
||||
var iterator = ""[Symbol.iterator]();
|
||||
var StringIteratorPrototype = iterator.__proto__;
|
||||
assertFalse(StringIteratorPrototype.hasOwnProperty('constructor'));
|
||||
assertEquals(StringIteratorPrototype.__proto__, Object.prototype);
|
||||
assertSame(StringIteratorPrototype.__proto__.__proto__, Object.prototype);
|
||||
assertArrayEquals(['next'],
|
||||
Object.getOwnPropertyNames(StringIteratorPrototype));
|
||||
assertEquals('[object String Iterator]', "" + iterator);
|
||||
|
@ -5,7 +5,7 @@
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
|
||||
assertEquals(this.__proto__, Object.prototype);
|
||||
assertSame(this.__proto__.__proto__, Object.prototype);
|
||||
|
||||
function TestAddingPropertyToGlobalPrototype() {
|
||||
let foo_func_called = 0;
|
||||
|
98
test/mjsunit/mjsunit-assert-equals.js
Normal file
98
test/mjsunit/mjsunit-assert-equals.js
Normal file
@ -0,0 +1,98 @@
|
||||
// Copyright 2022 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
function testAssertNotEquals(a, b) {
|
||||
let impl = (a, b) => {
|
||||
assertNotEquals(a, b);
|
||||
try {
|
||||
assertEquals(a, b);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
throw new Error('assertEquals did not throw');
|
||||
};
|
||||
// Test in both directions.
|
||||
impl(a, b);
|
||||
impl(b, a);
|
||||
}
|
||||
|
||||
function testAssertEquals(a, b) {
|
||||
let impl = (a, b) => {
|
||||
assertEquals(a, b);
|
||||
try {
|
||||
assertNotEquals(a, b);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
throw new Error('assertNotEquals did not throw');
|
||||
};
|
||||
// Test in both directions.
|
||||
impl(a, b);
|
||||
impl(b, a);
|
||||
}
|
||||
|
||||
(function TestAssertEqualsNonEnumerableProperty() {
|
||||
let a = {};
|
||||
assertTrue(Reflect.defineProperty(a, 'prop', {value: 1}));
|
||||
testAssertNotEquals({}, a);
|
||||
// Both objects are treated as equal if they have the same properties
|
||||
// with the same values independent of the property's enumerability.
|
||||
testAssertEquals({prop: 1}, a);
|
||||
testAssertNotEquals({prop: 2}, a);
|
||||
})();
|
||||
|
||||
(function TestAssertEqualsPropertyOrder() {
|
||||
// Test that property order does not matter.
|
||||
let a = {};
|
||||
a.x = 1;
|
||||
a.y = 2;
|
||||
let b = {};
|
||||
b.y = 2;
|
||||
b.x = 1;
|
||||
testAssertEquals(a, b);
|
||||
})();
|
||||
|
||||
(function TestAssertEqualsPropertyDifferentName() {
|
||||
testAssertNotEquals({a: 1, b: 2}, {a: 1, c: 2});
|
||||
testAssertNotEquals({a: 1, b: undefined}, {a: 1, c: undefined});
|
||||
})();
|
||||
|
||||
(function TestAssertEqualsArrays() {
|
||||
let arr = new Array();
|
||||
arr.push(...[1, 2, 3]);
|
||||
assertNotSame([1, 2, 3], arr);
|
||||
testAssertEquals([1, 2, 3], arr);
|
||||
testAssertNotEquals([1, 2, 3, 4], arr);
|
||||
testAssertNotEquals([1, 2, -3], arr);
|
||||
testAssertNotEquals([1, 3, 2], arr);
|
||||
// Array length matters, even with empty elements
|
||||
testAssertEquals(new Array(1), new Array(1));
|
||||
testAssertNotEquals(new Array(1), new Array(2));
|
||||
testAssertEquals([,,], new Array(2));
|
||||
})();
|
||||
|
||||
(function TestAssertEqualsArraysNested() {
|
||||
let arr = new Array();
|
||||
arr.push(...[1, 2, new Array(3, 4, 5)]);
|
||||
assertNotSame([1, 2, [3, 4, 5]], arr);
|
||||
testAssertEquals([1, 2, [3, 4, 5]], arr);
|
||||
})();
|
||||
|
||||
(function TestAssertEqualsArrayProperties() {
|
||||
// Difference between empty and undefined is ignored by the assert
|
||||
// implementation as well as additional properties.
|
||||
testAssertEquals([undefined], new Array(1));
|
||||
let arrWithProp = new Array();
|
||||
arrWithProp.myProperty = 'Additional property';
|
||||
testAssertEquals([], arrWithProp);
|
||||
})();
|
||||
|
||||
(function TestAssertEqualsArrayObject() {
|
||||
// An array isn't treated as equal to an equivalent object.
|
||||
let obj = {0: 1, 1: 2};
|
||||
Object.defineProperty(obj, 'length', {value: 2});
|
||||
Object.setPrototypeOf(obj, Array.prototype);
|
||||
testAssertNotEquals(obj , [1, 2]);
|
||||
testAssertNotEquals([1, 2], obj);
|
||||
})();
|
@ -374,9 +374,13 @@ var prettyPrinted;
|
||||
|
||||
|
||||
function deepObjectEquals(a, b) {
|
||||
var aProps = Object.keys(a);
|
||||
// Note: This function does not check prototype equality.
|
||||
|
||||
// For now, treat two objects the same even if some property is configured
|
||||
// differently (configurable, enumerable, writable).
|
||||
var aProps = Object.getOwnPropertyNames(a);
|
||||
aProps.sort();
|
||||
var bProps = Object.keys(b);
|
||||
var bProps = Object.getOwnPropertyNames(b);
|
||||
bProps.sort();
|
||||
if (!deepEquals(aProps, bProps)) {
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user