| // Copyright 2015 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. |
| |
| var target = {}; |
| var configurable_desc = { |
| value: 123, |
| configurable: true, |
| writable: true, |
| enumerable: false, |
| }; |
| Object.defineProperty(target, "configurable", configurable_desc); |
| var nonconfigurable_desc = { |
| value: 234, |
| configurable: false, |
| writable: false, |
| enumerable: true |
| } |
| Object.defineProperty(target, "nonconfigurable", nonconfigurable_desc); |
| |
| var proxied_desc = { |
| value: 345, |
| configurable: true |
| }; |
| |
| var handler = { |
| "getOwnPropertyDescriptor": function(target, name) { |
| if (name === "proxied") { |
| return proxied_desc; |
| } |
| if (name === "return_null") { |
| return null; |
| } |
| return Object.getOwnPropertyDescriptor(target, name); |
| } |
| }; |
| |
| var proxy = new Proxy(target, handler); |
| var proxy_without_handler = new Proxy(target, {}); |
| |
| // Checking basic functionality: |
| |
| assertEquals(configurable_desc, |
| Object.getOwnPropertyDescriptor(proxy, "configurable")); |
| assertEquals(nonconfigurable_desc, |
| Object.getOwnPropertyDescriptor(proxy, "nonconfigurable")); |
| assertEquals({ value: proxied_desc.value, |
| configurable: proxied_desc.configurable, |
| enumerable: false, |
| writable: false }, |
| Object.getOwnPropertyDescriptor(proxy, "proxied")); |
| assertEquals(configurable_desc, |
| Object.getOwnPropertyDescriptor(proxy_without_handler, |
| "configurable")); |
| assertEquals(nonconfigurable_desc, |
| Object.getOwnPropertyDescriptor(proxy_without_handler, |
| "nonconfigurable")); |
| |
| assertThrows('Object.getOwnPropertyDescriptor(proxy, "return_null")'); |
| |
| handler.getOwnPropertyDescriptor = undefined; |
| assertEquals(configurable_desc, |
| Object.getOwnPropertyDescriptor(proxy, "configurable")); |
| |
| // Checking invariants mentioned explicitly by the ES spec: |
| |
| // (Inv-1) "A property cannot be reported as non-existent, if it exists as a |
| // non-configurable own property of the target object." |
| handler.getOwnPropertyDescriptor = function(target, name) { return undefined; }; |
| assertThrows('Object.getOwnPropertyDescriptor(proxy, "nonconfigurable")'); |
| assertEquals(undefined, Object.getOwnPropertyDescriptor(proxy, "configurable")); |
| |
| // (Inv-2) "A property cannot be reported as non-configurable, if it does not |
| // exist as an own property of the target object or if it exists as a |
| // configurable own property of the target object." |
| handler.getOwnPropertyDescriptor = function(target, name) { |
| return {value: 234, configurable: false, enumerable: true}; |
| }; |
| assertThrows('Object.getOwnPropertyDescriptor(proxy, "nonexistent")'); |
| assertThrows('Object.getOwnPropertyDescriptor(proxy, "configurable")'); |
| assertEquals( |
| false, |
| Object.getOwnPropertyDescriptor(proxy, "nonconfigurable").configurable); |
| |
| // (Inv-3) "A property cannot be reported as non-existent, if it exists as an |
| // own property of the target object and the target object is not extensible." |
| Object.seal(target); |
| handler.getOwnPropertyDescriptor = function(target, name) { return undefined; }; |
| assertThrows('Object.getOwnPropertyDescriptor(proxy, "configurable")'); |
| assertThrows('Object.getOwnPropertyDescriptor(proxy, "nonconfigurable")'); |
| assertEquals(undefined, Object.getOwnPropertyDescriptor(proxy, "nonexistent")); |
| |
| // (Inv-4) "A property cannot be reported as existent, if it does not exist as |
| // an own property of the target object and the target object is not |
| // extensible." |
| var existent_desc = {value: "yes"}; |
| handler.getOwnPropertyDescriptor = function() { return existent_desc; }; |
| assertThrows('Object.getOwnPropertyDescriptor(proxy, "nonexistent")'); |
| assertEquals( |
| {value: "yes", writable: false, enumerable: false, configurable: false}, |
| Object.getOwnPropertyDescriptor(proxy, "configurable")); |
| |
| // Checking individual bailout points in the implementation: |
| |
| // Step 6: Trap is not callable. |
| handler.getOwnPropertyDescriptor = {}; |
| assertThrows('Object.getOwnPropertyDescriptor(proxy, "configurable")'); |
| |
| // Step 8: Trap throws. |
| handler.getOwnPropertyDescriptor = function() { throw "ball"; }; |
| assertThrows('Object.getOwnPropertyDescriptor(proxy, "configurable")'); |
| |
| // Step 9: Trap result is neither undefined nor an object. |
| handler.getOwnPropertyDescriptor = function() { return 1; } |
| assertThrows('Object.getOwnPropertyDescriptor(proxy, "configurable")'); |
| |
| // Step 11b: See (Inv-1) above. |
| // Step 11e: See (Inv-3) above. |
| |
| // Step 16: Incompatible PropertyDescriptor; a non-configurable property |
| // cannot be reported as configurable. (Inv-4) above checks more cases. |
| handler.getOwnPropertyDescriptor = function(target, name) { |
| return {value: 456, configurable: true, writable: true} |
| }; |
| assertThrows('Object.getOwnPropertyDescriptor(proxy, "nonconfigurable")'); |
| |
| // Step 17: See (Inv-2) above. |