1// Copyright 2016 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5// Flags: --harmony-object-values-entries 6// Flags: --allow-natives-syntax 7 8function TestMeta() { 9 assertEquals(1, Object.entries.length); 10 assertEquals(Function.prototype, Object.getPrototypeOf(Object.entries)); 11 assertEquals("entries", Object.entries.name); 12 13 var descriptor = Object.getOwnPropertyDescriptor(Object, "entries"); 14 assertTrue(descriptor.writable); 15 assertFalse(descriptor.enumerable); 16 assertTrue(descriptor.configurable); 17 18 assertThrows(() => new Object.entries({}), TypeError); 19} 20TestMeta(); 21 22 23function TestBasic() { 24 var x = 16; 25 var O = { 26 d: 1, 27 c: 3, 28 [Symbol.iterator]: void 0, 29 0: 123, 30 1000: 456, 31 [x * x]: "ducks", 32 [`0x${(x * x).toString(16)}`]: "quack" 33 }; 34 O.a = 2; 35 O.b = 4; 36 Object.defineProperty(O, "HIDDEN", { enumerable: false, value: NaN }); 37 assertEquals([ 38 ["0", 123], 39 ["256", "ducks"], 40 ["1000", 456], 41 ["d", 1], 42 ["c", 3], 43 ["0x100", "quack"], 44 ["a", 2], 45 ["b", 4] 46 ], Object.entries(O)); 47 assertEquals(Object.entries(O), Object.keys(O).map(key => [key, O[key]])); 48 49 assertTrue(Array.isArray(Object.entries({}))); 50 assertEquals(0, Object.entries({}).length); 51} 52TestBasic(); 53 54 55function TestToObject() { 56 assertThrows(function() { Object.entries(); }, TypeError); 57 assertThrows(function() { Object.entries(null); }, TypeError); 58 assertThrows(function() { Object.entries(void 0); }, TypeError); 59} 60TestToObject(); 61 62 63function TestOrder() { 64 var O = { 65 a: 1, 66 [Symbol.iterator]: null 67 }; 68 O[456] = 123; 69 Object.defineProperty(O, "HIDDEN", { enumerable: false, value: NaN }); 70 var priv = %CreatePrivateSymbol("Secret"); 71 O[priv] = 56; 72 73 var log = []; 74 var P = new Proxy(O, { 75 ownKeys(target) { 76 log.push("[[OwnPropertyKeys]]"); 77 return Reflect.ownKeys(target); 78 }, 79 get(target, name) { 80 log.push(`[[Get]](${JSON.stringify(name)})`); 81 return Reflect.get(target, name); 82 }, 83 getOwnPropertyDescriptor(target, name) { 84 log.push(`[[GetOwnProperty]](${JSON.stringify(name)})`); 85 return Reflect.getOwnPropertyDescriptor(target, name); 86 }, 87 set(target, name, value) { 88 assertUnreachable(); 89 } 90 }); 91 92 assertEquals([["456", 123], ["a", 1]], Object.entries(P)); 93 assertEquals([ 94 "[[OwnPropertyKeys]]", 95 "[[GetOwnProperty]](\"456\")", 96 "[[Get]](\"456\")", 97 "[[GetOwnProperty]](\"a\")", 98 "[[Get]](\"a\")", 99 "[[GetOwnProperty]](\"HIDDEN\")" 100 ], log); 101} 102TestOrder(); 103 104 105function TestOrderWithDuplicates() { 106 var O = { 107 a: 1, 108 [Symbol.iterator]: null 109 }; 110 O[456] = 123; 111 Object.defineProperty(O, "HIDDEN", { enumerable: false, value: NaN }); 112 var priv = %CreatePrivateSymbol("Secret"); 113 O[priv] = 56; 114 115 var log = []; 116 var P = new Proxy(O, { 117 ownKeys(target) { 118 log.push("[[OwnPropertyKeys]]"); 119 return ["a", Symbol.iterator, "a", "456", "HIDDEN", "HIDDEN", "456"]; 120 }, 121 get(target, name) { 122 log.push(`[[Get]](${JSON.stringify(name)})`); 123 return Reflect.get(target, name); 124 }, 125 getOwnPropertyDescriptor(target, name) { 126 log.push(`[[GetOwnProperty]](${JSON.stringify(name)})`); 127 return Reflect.getOwnPropertyDescriptor(target, name); 128 }, 129 set(target, name, value) { 130 assertUnreachable(); 131 } 132 }); 133 134 assertEquals([ 135 ["a", 1], 136 ["a", 1], 137 ["456", 123], 138 ["456", 123] 139 ], Object.entries(P)); 140 assertEquals([ 141 "[[OwnPropertyKeys]]", 142 "[[GetOwnProperty]](\"a\")", 143 "[[Get]](\"a\")", 144 "[[GetOwnProperty]](\"a\")", 145 "[[Get]](\"a\")", 146 "[[GetOwnProperty]](\"456\")", 147 "[[Get]](\"456\")", 148 "[[GetOwnProperty]](\"HIDDEN\")", 149 "[[GetOwnProperty]](\"HIDDEN\")", 150 "[[GetOwnProperty]](\"456\")", 151 "[[Get]](\"456\")" 152 ], log); 153} 154TestOrderWithDuplicates(); 155 156 157function TestPropertyFilter() { 158 var object = { prop3: 30 }; 159 object[2] = 40; 160 object["prop4"] = 50; 161 Object.defineProperty(object, "prop5", { value: 60, enumerable: true }); 162 Object.defineProperty(object, "prop6", { value: 70, enumerable: false }); 163 Object.defineProperty(object, "prop7", { 164 enumerable: true, get() { return 80; }}); 165 var sym = Symbol("prop8"); 166 object[sym] = 90; 167 168 values = Object.entries(object); 169 assertEquals(5, values.length); 170 assertEquals([ 171 [ "2", 40 ], 172 [ "prop3", 30 ], 173 [ "prop4", 50 ], 174 [ "prop5", 60 ], 175 [ "prop7", 80 ] 176 ], values); 177} 178TestPropertyFilter(); 179 180 181function TestWithProxy() { 182 var obj1 = {prop1:10}; 183 var proxy1 = new Proxy(obj1, { }); 184 assertEquals([ [ "prop1", 10 ] ], Object.entries(proxy1)); 185 186 var obj2 = {}; 187 Object.defineProperty(obj2, "prop2", { value: 20, enumerable: true }); 188 Object.defineProperty(obj2, "prop3", { 189 get() { return 30; }, enumerable: true }); 190 var proxy2 = new Proxy(obj2, { 191 getOwnPropertyDescriptor(target, name) { 192 return Reflect.getOwnPropertyDescriptor(target, name); 193 } 194 }); 195 assertEquals([ [ "prop2", 20 ], [ "prop3", 30 ] ], Object.entries(proxy2)); 196 197 var obj3 = {}; 198 var count = 0; 199 var proxy3 = new Proxy(obj3, { 200 get(target, property, receiver) { 201 return count++ * 5; 202 }, 203 getOwnPropertyDescriptor(target, property) { 204 return { configurable: true, enumerable: true }; 205 }, 206 ownKeys(target) { 207 return [ "prop0", "prop1", Symbol("prop2"), Symbol("prop5") ]; 208 } 209 }); 210 assertEquals([ [ "prop0", 0 ], [ "prop1", 5 ] ], Object.entries(proxy3)); 211} 212TestWithProxy(); 213 214 215function TestMutateDuringEnumeration() { 216 var aDeletesB = { 217 get a() { 218 delete this.b; 219 return 1; 220 }, 221 b: 2 222 }; 223 assertEquals([ [ "a", 1 ] ], Object.entries(aDeletesB)); 224 225 var aRemovesB = { 226 get a() { 227 Object.defineProperty(this, "b", { enumerable: false }); 228 return 1; 229 }, 230 b: 2 231 }; 232 assertEquals([ [ "a", 1 ] ], Object.entries(aRemovesB)); 233 234 var aAddsB = { get a() { this.b = 2; return 1; } }; 235 assertEquals([ [ "a", 1 ] ], Object.entries(aAddsB)); 236 237 var aMakesBEnumerable = {}; 238 Object.defineProperty(aMakesBEnumerable, "a", { 239 get() { 240 Object.defineProperty(this, "b", { enumerable: true }); 241 return 1; 242 }, 243 enumerable: true 244 }); 245 Object.defineProperty(aMakesBEnumerable, "b", { 246 value: 2, configurable:true, enumerable: false }); 247 assertEquals([ [ "a", 1 ], [ "b", 2 ] ], Object.entries(aMakesBEnumerable)); 248} 249TestMutateDuringEnumeration(); 250 251 252(function TestElementKinds() { 253 var O1 = { name: "1" }, O2 = { name: "2" }, O3 = { name: "3" }; 254 var PI = 3.141592653589793; 255 var E = 2.718281828459045; 256 function fastSloppyArguments(a, b, c) { 257 delete arguments[0]; 258 arguments[0] = a; 259 return arguments; 260 } 261 262 function slowSloppyArguments(a, b, c) { 263 delete arguments[0]; 264 arguments[0] = a; 265 Object.defineProperties(arguments, { 266 0: { 267 enumerable: true, 268 value: a 269 }, 270 9999: { 271 enumerable: false, 272 value: "Y" 273 } 274 }); 275 arguments[10000] = "X"; 276 return arguments; 277 } 278 279 var element_kinds = { 280 FAST_SMI_ELEMENTS: [ [1, 2, 3], [ ["0", 1], ["1", 2], ["2", 3] ] ], 281 FAST_HOLEY_SMI_ELEMENTS: [ [, , 3], [ ["2", 3] ] ], 282 FAST_ELEMENTS: [ [O1, O2, O3], [ ["0", O1], ["1", O2], ["2", O3] ] ], 283 FAST_HOLEY_ELEMENTS: [ [, , O3], [ ["2", O3] ] ], 284 FAST_DOUBLE_ELEMENTS: [ [E, NaN, PI], [ ["0", E], ["1", NaN], ["2", PI] ] ], 285 FAST_HOLEY_DOUBLE_ELEMENTS: [ [, , NaN], [ ["2", NaN] ] ], 286 287 DICTIONARY_ELEMENTS: [ Object.defineProperties({ 10000: "world" }, { 288 100: { enumerable: true, value: "hello" }, 289 99: { enumerable: false, value: "nope" } 290 }), [ ["100", "hello"], ["10000", "world" ] ] ], 291 FAST_SLOPPY_ARGUMENTS_ELEMENTS: [ 292 fastSloppyArguments("a", "b", "c"), 293 [ ["0", "a"], ["1", "b"], ["2", "c"] ] ], 294 SLOW_SLOPPY_ARGUMENTS_ELEMENTS: [ 295 slowSloppyArguments("a", "b", "c"), 296 [ ["0", "a"], ["1", "b"], ["2", "c"], ["10000", "X"] ] ], 297 298 FAST_STRING_WRAPPER_ELEMENTS: [ new String("str"), 299 [ ["0", "s"], ["1", "t"], ["2", "r"]] ], 300 SLOW_STRING_WRAPPER_ELEMENTS: [ 301 Object.defineProperties(new String("str"), { 302 10000: { enumerable: false, value: "X" }, 303 9999: { enumerable: true, value: "Y" } 304 }), [["0", "s"], ["1", "t"], ["2", "r"], ["9999", "Y"]] ], 305 }; 306 307 for (let [kind, [object, expected]] of Object.entries(element_kinds)) { 308 let result1 = Object.entries(object); 309 assertEquals(expected, result1, `fast Object.entries() with ${kind}`); 310 311 let proxy = new Proxy(object, {}); 312 let result2 = Object.entries(proxy); 313 assertEquals(result1, result2, `slow Object.entries() with ${kind}`); 314 } 315})(); 316