1014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Copyright 2015 the V8 project authors. All rights reserved.
2014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// found in the LICENSE file.
4014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
5014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Flags: --harmony-proxies --harmony-reflect
6014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
7014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar target = { target: 1 };
8014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochtarget.__proto__ = {};
9014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar handler = { handler: 1 };
10014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar proxy = new Proxy(target, handler);
11014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
12014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertSame(Object.getPrototypeOf(proxy), target.__proto__ );
13014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
14014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
15014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertThrows(function() { Object.setPrototypeOf(proxy, undefined) }, TypeError);
16014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertThrows(function() { Object.setPrototypeOf(proxy, 1) }, TypeError);
17014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
18014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar prototype = [1];
19014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertSame(proxy, Object.setPrototypeOf(proxy, prototype));
20014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertSame(prototype, Object.getPrototypeOf(proxy));
21014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertSame(prototype, Object.getPrototypeOf(target));
22014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
23014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar pair = Proxy.revocable(target, handler);
24014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertSame(pair.proxy, Object.setPrototypeOf(pair.proxy, prototype));
25014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertSame(prototype, Object.getPrototypeOf(pair.proxy));
26014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochpair.revoke();
27014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertThrows('Object.setPrototypeOf(pair.proxy, prototype)', TypeError);
28014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
29014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochhandler.setPrototypeOf = function(target, proto) {
30014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return false;
31014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch};
32014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertThrows(function() { Object.setPrototypeOf(proxy, {a:1}) }, TypeError);
33014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
34014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochhandler.setPrototypeOf = function(target, proto) {
35014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return undefined;
36014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch};
37014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertThrows(function() { Object.setPrototypeOf(proxy, {a:2}) }, TypeError);
38014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
39014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochhandler.setPrototypeOf = function(proto) {};
40014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertThrows(function() { Object.setPrototypeOf(proxy, {a:3}) }, TypeError);
41014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
42014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochhandler.setPrototypeOf = function(target, proto) {
43014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  throw Error();
44014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch};
45014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertThrows(function() { Object.setPrototypeOf(proxy, {a:4}) }, Error);
46014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
47014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar seen_prototype;
48014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar seen_target;
49014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochhandler.setPrototypeOf = function(target, proto) {
50014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  seen_target = target;
51014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  seen_prototype = proto;
52014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return true;
53014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
54014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertSame(Object.setPrototypeOf(proxy, {a:5}), proxy);
55014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertSame(target, seen_target);
56014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochassertEquals({a:5}, seen_prototype);
57014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
58014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch(function setPrototypeProxyTarget() {
59014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var target = { target: 1 };
60014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  target.__proto__ = {};
61014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var handler = {};
62014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var handler2 = {};
63014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var target2 = new Proxy(target, handler2);
64014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var proxy2 = new Proxy(target2, handler);
65014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  assertSame(Object.getPrototypeOf(proxy2), target.__proto__ );
66014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
67014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var prototype = [2,3];
68014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  assertSame(proxy2, Object.setPrototypeOf(proxy2, prototype));
69014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  assertSame(prototype, Object.getPrototypeOf(proxy2));
70014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  assertSame(prototype, Object.getPrototypeOf(target));
71014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch})();
72014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
73014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch(function testProxyTrapInconsistent() {
74014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var target = { target: 1 };
75014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  target.__proto__ = {};
76014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var handler = {};
77014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var handler2 = {
78014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  };
79014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
80014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var target2 = new Proxy(target, handler);
81014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var proxy2 = new Proxy(target2, handler2);
82014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
83014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // If the final target is extensible we can set any prototype.
84014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var prototype = [1];
85014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Reflect.setPrototypeOf(proxy2, prototype);
86014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  assertSame(prototype, Reflect.getPrototypeOf(target));
87014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
88014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  handler2.setPrototypeOf = function(target, value) {
89014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    Reflect.setPrototypeOf(target, value);
90014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return true;
91014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  };
92014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  prototype = [2];
93014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Reflect.setPrototypeOf(proxy2, prototype);
94014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  assertSame(prototype, Reflect.getPrototypeOf(target));
95014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
96014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Prevent getting the target's prototype used to check the invariant.
97014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var gotPrototype = false;
98014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  handler.getPrototypeOf = function() {
99014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    gotPrototype = true;
100014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    throw TypeError()
101014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  };
102014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // If the target is extensible we do not check the invariant.
103014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  prototype = [3];
104014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Reflect.setPrototypeOf(proxy2, prototype);
105014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  assertFalse(gotPrototype);
106014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  assertSame(prototype, Reflect.getPrototypeOf(target));
107014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
108014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Changing the prototype of a non-extensible target will trigger the
109014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // invariant-check and throw in the above handler.
110014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Reflect.preventExtensions(target);
111014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  assertThrows(() => {Reflect.setPrototypeOf(proxy2, [4])}, TypeError);
112014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  assertTrue(gotPrototype);
113014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  assertEquals([3], Reflect.getPrototypeOf(target));
114014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
115014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Setting the prototype of a non-extensible target is fine if the prototype
116014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // doesn't change.
117014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  delete handler.getPrototypeOf;
118014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  Reflect.setPrototypeOf(proxy2, prototype);
119014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // Changing the prototype will throw.
120014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  prototype = [5];
121014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  assertThrows(() => {Reflect.setPrototypeOf(proxy2, prototype)}, TypeError);
122014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch})();
123