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 --harmony-reflect
6
7var target = { target: 1 };
8target.__proto__ = {};
9var handler = { handler: 1 };
10var proxy = new Proxy(target, handler);
11
12assertSame(Object.getPrototypeOf(proxy), target.__proto__ );
13
14
15assertThrows(function() { Object.setPrototypeOf(proxy, undefined) }, TypeError);
16assertThrows(function() { Object.setPrototypeOf(proxy, 1) }, TypeError);
17
18var prototype = [1];
19assertSame(proxy, Object.setPrototypeOf(proxy, prototype));
20assertSame(prototype, Object.getPrototypeOf(proxy));
21assertSame(prototype, Object.getPrototypeOf(target));
22
23var pair = Proxy.revocable(target, handler);
24assertSame(pair.proxy, Object.setPrototypeOf(pair.proxy, prototype));
25assertSame(prototype, Object.getPrototypeOf(pair.proxy));
26pair.revoke();
27assertThrows('Object.setPrototypeOf(pair.proxy, prototype)', TypeError);
28
29handler.setPrototypeOf = function(target, proto) {
30  return false;
31};
32assertThrows(function() { Object.setPrototypeOf(proxy, {a:1}) }, TypeError);
33
34handler.setPrototypeOf = function(target, proto) {
35  return undefined;
36};
37assertThrows(function() { Object.setPrototypeOf(proxy, {a:2}) }, TypeError);
38
39handler.setPrototypeOf = function(proto) {};
40assertThrows(function() { Object.setPrototypeOf(proxy, {a:3}) }, TypeError);
41
42handler.setPrototypeOf = function(target, proto) {
43  throw Error();
44};
45assertThrows(function() { Object.setPrototypeOf(proxy, {a:4}) }, Error);
46
47var seen_prototype;
48var seen_target;
49handler.setPrototypeOf = function(target, proto) {
50  seen_target = target;
51  seen_prototype = proto;
52  return true;
53}
54assertSame(Object.setPrototypeOf(proxy, {a:5}), proxy);
55assertSame(target, seen_target);
56assertEquals({a:5}, seen_prototype);
57
58(function setPrototypeProxyTarget() {
59  var target = { target: 1 };
60  target.__proto__ = {};
61  var handler = {};
62  var handler2 = {};
63  var target2 = new Proxy(target, handler2);
64  var proxy2 = new Proxy(target2, handler);
65  assertSame(Object.getPrototypeOf(proxy2), target.__proto__ );
66
67  var prototype = [2,3];
68  assertSame(proxy2, Object.setPrototypeOf(proxy2, prototype));
69  assertSame(prototype, Object.getPrototypeOf(proxy2));
70  assertSame(prototype, Object.getPrototypeOf(target));
71})();
72
73(function testProxyTrapInconsistent() {
74  var target = { target: 1 };
75  target.__proto__ = {};
76  var handler = {};
77  var handler2 = {
78  };
79
80  var target2 = new Proxy(target, handler);
81  var proxy2 = new Proxy(target2, handler2);
82
83  // If the final target is extensible we can set any prototype.
84  var prototype = [1];
85  Reflect.setPrototypeOf(proxy2, prototype);
86  assertSame(prototype, Reflect.getPrototypeOf(target));
87
88  handler2.setPrototypeOf = function(target, value) {
89    Reflect.setPrototypeOf(target, value);
90    return true;
91  };
92  prototype = [2];
93  Reflect.setPrototypeOf(proxy2, prototype);
94  assertSame(prototype, Reflect.getPrototypeOf(target));
95
96  // Prevent getting the target's prototype used to check the invariant.
97  var gotPrototype = false;
98  handler.getPrototypeOf = function() {
99    gotPrototype = true;
100    throw TypeError()
101  };
102  // If the target is extensible we do not check the invariant.
103  prototype = [3];
104  Reflect.setPrototypeOf(proxy2, prototype);
105  assertFalse(gotPrototype);
106  assertSame(prototype, Reflect.getPrototypeOf(target));
107
108  // Changing the prototype of a non-extensible target will trigger the
109  // invariant-check and throw in the above handler.
110  Reflect.preventExtensions(target);
111  assertThrows(() => {Reflect.setPrototypeOf(proxy2, [4])}, TypeError);
112  assertTrue(gotPrototype);
113  assertEquals([3], Reflect.getPrototypeOf(target));
114
115  // Setting the prototype of a non-extensible target is fine if the prototype
116  // doesn't change.
117  delete handler.getPrototypeOf;
118  Reflect.setPrototypeOf(proxy2, prototype);
119  // Changing the prototype will throw.
120  prototype = [5];
121  assertThrows(() => {Reflect.setPrototypeOf(proxy2, prototype)}, TypeError);
122})();
123