proxies-set-prototype-of.js 4.19 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
// 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 = { target: 1 };
target.__proto__ = {};
var handler = { handler: 1 };
var proxy = new Proxy(target, handler);

assertSame(Object.getPrototypeOf(proxy), target.__proto__ );

12

13 14 15 16 17 18 19 20
assertThrows(function() { Object.setPrototypeOf(proxy, undefined) }, TypeError);
assertThrows(function() { Object.setPrototypeOf(proxy, 1) }, TypeError);

var prototype = [1];
assertSame(proxy, Object.setPrototypeOf(proxy, prototype));
assertSame(prototype, Object.getPrototypeOf(proxy));
assertSame(prototype, Object.getPrototypeOf(target));

21 22 23 24 25 26
var pair = Proxy.revocable(target, handler);
assertSame(pair.proxy, Object.setPrototypeOf(pair.proxy, prototype));
assertSame(prototype, Object.getPrototypeOf(pair.proxy));
pair.revoke();
assertThrows('Object.setPrototypeOf(pair.proxy, prototype)', TypeError);

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
handler.setPrototypeOf = function(target, proto) {
  return false;
};
assertThrows(function() { Object.setPrototypeOf(proxy, {a:1}) }, TypeError);

handler.setPrototypeOf = function(target, proto) {
  return undefined;
};
assertThrows(function() { Object.setPrototypeOf(proxy, {a:2}) }, TypeError);

handler.setPrototypeOf = function(proto) {};
assertThrows(function() { Object.setPrototypeOf(proxy, {a:3}) }, TypeError);

handler.setPrototypeOf = function(target, proto) {
  throw Error();
};
assertThrows(function() { Object.setPrototypeOf(proxy, {a:4}) }, Error);

var seen_prototype;
var seen_target;
handler.setPrototypeOf = function(target, proto) {
  seen_target = target;
  seen_prototype = proto;
  return true;
}
assertSame(Object.setPrototypeOf(proxy, {a:5}), proxy);
assertSame(target, seen_target);
assertEquals({a:5}, seen_prototype);

56 57 58 59 60 61 62 63
(function setPrototypeProxyTarget() {
  var target = { target: 1 };
  target.__proto__ = {};
  var handler = {};
  var handler2 = {};
  var target2 = new Proxy(target, handler2);
  var proxy2 = new Proxy(target2, handler);
  assertSame(Object.getPrototypeOf(proxy2), target.__proto__ );
64

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
  var prototype = [2,3];
  assertSame(proxy2, Object.setPrototypeOf(proxy2, prototype));
  assertSame(prototype, Object.getPrototypeOf(proxy2));
  assertSame(prototype, Object.getPrototypeOf(target));
})();

(function testProxyTrapInconsistent() {
  var target = { target: 1 };
  target.__proto__ = {};
  var handler = {};
  var handler2 = {
  };

  var target2 = new Proxy(target, handler);
  var proxy2 = new Proxy(target2, handler2);

  // If the final target is extensible we can set any prototype.
  var prototype = [1];
  Reflect.setPrototypeOf(proxy2, prototype);
  assertSame(prototype, Reflect.getPrototypeOf(target));

  handler2.setPrototypeOf = function(target, value) {
    Reflect.setPrototypeOf(target, value);
    return true;
  };
  prototype = [2];
  Reflect.setPrototypeOf(proxy2, prototype);
  assertSame(prototype, Reflect.getPrototypeOf(target));

  // Prevent getting the target's prototype used to check the invariant.
  var gotPrototype = false;
  handler.getPrototypeOf = function() {
    gotPrototype = true;
    throw TypeError()
  };
  // If the target is extensible we do not check the invariant.
  prototype = [3];
  Reflect.setPrototypeOf(proxy2, prototype);
  assertFalse(gotPrototype);
  assertSame(prototype, Reflect.getPrototypeOf(target));

  // Changing the prototype of a non-extensible target will trigger the
  // invariant-check and throw in the above handler.
  Reflect.preventExtensions(target);
  assertThrows(() => {Reflect.setPrototypeOf(proxy2, [4])}, TypeError);
  assertTrue(gotPrototype);
  assertEquals([3], Reflect.getPrototypeOf(target));

  // Setting the prototype of a non-extensible target is fine if the prototype
  // doesn't change.
  delete handler.getPrototypeOf;
  Reflect.setPrototypeOf(proxy2, prototype);
  // Changing the prototype will throw.
  prototype = [5];
  assertThrows(() => {Reflect.setPrototypeOf(proxy2, prototype)}, TypeError);
})();
121 122 123 124 125 126 127 128

(function testProxyTrapReturnsFalse() {
  var handler = {};
  handler.setPrototypeOf = () => false;
  var target = new Proxy({}, {isExtensible: () => assertUnreachable()});
  var object = new Proxy(target, handler);
  assertFalse(Reflect.setPrototypeOf(object, {}));
})();