Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 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 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 5 | // Flags: --harmony-object-values-entries |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 6 | // Flags: --allow-natives-syntax |
| 7 | |
| 8 | function 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 | } |
| 20 | TestMeta(); |
| 21 | |
| 22 | |
| 23 | function 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 | } |
| 52 | TestBasic(); |
| 53 | |
| 54 | |
| 55 | function TestToObject() { |
| 56 | assertThrows(function() { Object.entries(); }, TypeError); |
| 57 | assertThrows(function() { Object.entries(null); }, TypeError); |
| 58 | assertThrows(function() { Object.entries(void 0); }, TypeError); |
| 59 | } |
| 60 | TestToObject(); |
| 61 | |
| 62 | |
| 63 | function 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 | } |
| 102 | TestOrder(); |
| 103 | |
| 104 | |
| 105 | function 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 | } |
| 154 | TestOrderWithDuplicates(); |
| 155 | |
| 156 | |
| 157 | function 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 | } |
| 178 | TestPropertyFilter(); |
| 179 | |
| 180 | |
| 181 | function 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 | } |
| 212 | TestWithProxy(); |
| 213 | |
| 214 | |
| 215 | function 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 | } |
| 249 | TestMutateDuringEnumeration(); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 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 | })(); |