1// Copyright 2015 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-proxies --strong-mode
6
7// Forwarding proxies adapted from proposal definition
8function handlerMaker1(obj) {
9  return {
10    getPropertyDescriptor: function(name) {
11      var desc;
12      var searchObj = obj;
13      while (desc === undefined && searchObj != null) {
14        desc = Object.getOwnPropertyDescriptor(searchObj, name);
15        searchObj = searchObj.__proto__;
16      }
17      // a trapping proxy's properties must always be configurable
18      if (desc !== undefined) { desc.configurable = true; }
19      return desc;
20    },
21    fix: function() {
22      if (Object.isFrozen(obj)) {
23        var result = {};
24        Object.getOwnPropertyNames(obj).forEach(function(name) {
25          result[name] = Object.getOwnPropertyDescriptor(obj, name);
26        });
27        return result;
28      }
29      // As long as obj is not frozen, the proxy won't allow itself to be fixed
30      return undefined; // will cause a TypeError to be thrown
31    }
32  };
33}
34function handlerMaker2(obj) {
35  return {
36    get: function(receiver, name) {
37      return obj[name];
38    },
39    fix: function() {
40      if (Object.isFrozen(obj)) {
41        var result = {};
42        Object.getOwnPropertyNames(obj).forEach(function(name) {
43          result[name] = Object.getOwnPropertyDescriptor(obj, name);
44        });
45        return result;
46      }
47      // As long as obj is not frozen, the proxy won't allow itself to be fixed
48      return undefined; // will cause a TypeError to be thrown
49    }
50  };
51}
52var baseObj = {};
53var proxy1 = new Proxy({}, handlerMaker1(baseObj));
54var proxy2 = new Proxy({}, handlerMaker2(baseObj));
55var childObj1 = { __proto__: proxy1 };
56var childObj2 = { __proto__: proxy2 };
57var childObjAccessor1 = { set foo(_){}, set "1"(_){}, __proto__: proxy1 };
58var childObjAccessor2 = { set foo(_){}, set "1"(_){}, __proto__: proxy2 };
59
60(function() {
61  "use strong";
62  // TODO(conradw): These asserts are sanity checking V8's proxy implementation.
63  // Strong mode semantics for ES6 proxies still need to be explored.
64  assertDoesNotThrow(function(){proxy1.foo});
65  assertDoesNotThrow(function(){proxy1[1]});
66  assertDoesNotThrow(function(){proxy2.foo});
67  assertDoesNotThrow(function(){proxy2[1]});
68  assertDoesNotThrow(function(){childObj1.foo});
69  assertDoesNotThrow(function(){childObj1[1]});
70  assertDoesNotThrow(function(){childObj2.foo});
71  assertDoesNotThrow(function(){childObj2[1]});
72  assertThrows(function(){baseObj.foo}, TypeError);
73  assertThrows(function(){baseObj[1]}, TypeError);
74  assertThrows(function(){childObjAccessor1.foo}, TypeError);
75  assertThrows(function(){childObjAccessor1[1]}, TypeError);
76  assertThrows(function(){childObjAccessor2.foo}, TypeError);
77  assertThrows(function(){childObjAccessor2[1]}, TypeError);
78
79  // Once the proxy is no longer trapping, property access should have strong
80  // semantics.
81  Object.freeze(baseObj);
82
83  // TODO(neis): Reenable once proxies properly support freeze.
84  //
85  // Object.freeze(proxy1);
86  // assertThrows(function(){proxy1.foo}, TypeError);
87  // assertThrows(function(){proxy1[1]}, TypeError);
88  // assertThrows(function(){childObj1.foo}, TypeError);
89  // assertThrows(function(){childObj1[1]}, TypeError);
90  // assertThrows(function(){childObjAccessor1.foo}, TypeError);
91  // assertThrows(function(){childObjAccessor1[1]}, TypeError);
92  //
93  // Object.freeze(proxy2);
94  // assertThrows(function(){proxy2.foo}, TypeError);
95  // assertThrows(function(){proxy2[1]}, TypeError);
96  // assertThrows(function(){childObj2.foo}, TypeError);
97  // assertThrows(function(){childObj2[1]}, TypeError);
98  // assertThrows(function(){childObjAccessor2.foo}, TypeError);
99  // assertThrows(function(){childObjAccessor2[1]}, TypeError);
100})();
101