// Copyright 2017 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. // Flags: --allow-natives-syntax // Ensure empty keys are handled properly (function() { const a = {}; let k = Object.keys(a); %HeapObjectVerify(k); assertEquals(0, k.length); })(); // Ensure non-enumerable keys are handled properly (function() { const a = {}; Object.defineProperty(a, 'x', { value: 1, enumerable: false }); let k = Object.keys(a); %HeapObjectVerify(k); assertEquals(0, k.length); a.y = 2; k = Object.keys(a); %HeapObjectVerify(k); assertEquals(1, k.length); })(); // Ensure that mutation of the Object.keys result doesn't affect the // enumeration cache for fast-mode objects. (function() { const a = {x:1, y:2}; let k = Object.keys(a); %HeapObjectVerify(k); assertEquals(2, k.length); assertEquals("x", k[0]); assertEquals("y", k[1]); k[0] = "y"; k[1] = "x"; k = Object.keys(a); assertEquals(2, k.length); assertEquals("x", k[0]); assertEquals("y", k[1]); })(); // Ensure that the copy-on-write keys are handled properly, even in // the presence of Symbols. (function() { const s = Symbol(); const a = {[s]: 1}; let k = Object.keys(a); %HeapObjectVerify(k); assertEquals(0, k.length); k.shift(); assertEquals(0, k.length); })(); // Ensure we invoke all steps on proxies. (function ObjectKeysProxy() { let log = []; let result = Object.keys(new Proxy({}, { ownKeys(target) { log.push('ownKeys'); return ['a', 'b', 'c']; }, getOwnPropertyDescriptor(target, key) { log.push('getOwnPropertyDescriptor-' + key); if (key === 'b') return {enumerable: false, configurable: true}; return {enumerable: true, configurable: true}; } })); assertEquals(['a', 'c'], result); assertEquals( [ 'ownKeys', 'getOwnPropertyDescriptor-a', 'getOwnPropertyDescriptor-b', 'getOwnPropertyDescriptor-c' ], log); // Test normal target. log = []; let target = {a: 1, b: 1, c: 1}; let handler = { getOwnPropertyDescriptor(target, key) { log.push('getOwnPropertyDescriptor-' + key); if (key === 'b') return {enumerable: false, configurable: true}; return {enumerable: true, configurable: true}; } }; result = Object.keys(new Proxy(target, handler)); assertEquals(['a', 'c'], result); assertEquals( [ 'getOwnPropertyDescriptor-a', 'getOwnPropertyDescriptor-b', 'getOwnPropertyDescriptor-c' ], log); // Test trap invocation with non-enumerable target properties. log = []; target = Object.create(Object.prototype, { a: {enumerable: true, configurable: true}, b: {enumerable: false, configurable: true}, c: {enumerable: true, configurable: true} }); result = Object.keys(new Proxy(target, handler)); assertEquals(['a', 'c'], result); assertEquals( [ 'getOwnPropertyDescriptor-a', 'getOwnPropertyDescriptor-b', 'getOwnPropertyDescriptor-c' ], log); })();