Update tests for Proxy.[[SetPrototypeOf]] (#716)

* Update tests for Proxy.[[SetPrototypeOf]]

Expand coverage for proxies' [[SetPrototypeOf]] and update tests to
verify that target's [[IsExtensible]] is not called anymore if trap
returns a falsy value.

Ref tc39/ecma262#331
This commit is contained in:
Leo Balter 2016-07-19 18:51:02 -03:00 committed by Tom Care
parent 2c5138a4c7
commit e8e0fb9d34
14 changed files with 371 additions and 79 deletions

View File

@ -1,28 +0,0 @@
// Copyright (C) 2015 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 9.5.2
description: >
Return a boolean trap result if target is extensible.
info: >
[[SetPrototypeOf]] (V)
...
13. If extensibleTarget is true, return booleanTrapResult.
...
flags: [onlyStrict]
features: [Reflect]
---*/
var target = {};
var p = new Proxy(target, {
setPrototypeOf: function(t, v) {
return v.attr;
}
});
var result = Reflect.setPrototypeOf(p, { attr: 0 });
assert.sameValue(result, false);
result = Reflect.setPrototypeOf(p, { attr: 1 });
assert.sameValue(result, true);

View File

@ -0,0 +1,48 @@
// Copyright (C) 2016 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v
description: >
Calls target.[[GetPrototypeOf]] after trap result as false and not extensible
target
info: |
[[SetPrototypeOf]] (V)
8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, V »)).
9. If booleanTrapResult is false, return false.
10. Let extensibleTarget be ? IsExtensible(target).
11. If extensibleTarget is true, return true.
12. Let targetProto be ? target.[[GetPrototypeOf]]().
features: [Reflect.setPrototypeOf]
---*/
var calls = [];
var proto = {};
var target = new Proxy(Object.create(proto), {
isExtensible: function() {
calls.push("target.[[IsExtensible]]");
return false;
},
getPrototypeOf: function() {
calls.push("target.[[GetPrototypeOf]]");
return proto;
}
});
// Proxy must report same extensiblitity as target
Object.preventExtensions(target);
var proxy = new Proxy(target, {
setPrototypeOf: function() {
calls.push("proxy.[[setPrototypeOf]]");
return true;
}
});
assert.sameValue(Reflect.setPrototypeOf(proxy, proto), false);
assert.sameValue(calls.length, 3);
assert.sameValue(calls[0], "proxy.[[setPrototypeOf]]");
assert.sameValue(calls[1], "target.[[IsExtensible]]");
assert.sameValue(calls[2], "target.[[GetPrototypeOf]]");

View File

@ -21,18 +21,33 @@ info: >
16. If booleanTrapResult is true and SameValue(V, targetProto) is false,
throw a TypeError exception.
...
features: [Reflect.setPrototypeOf]
---*/
var target = {};
var p = new Proxy(target, {
setPrototypeOf: function(t, v) {
return true;
}
var target, proxy;
target = {};
proxy = new Proxy(target, {
setPrototypeOf: function() {
return true;
}
});
Object.preventExtensions(target);
assert.throws(TypeError, function() {
Object.setPrototypeOf(p, {});
Reflect.setPrototypeOf(proxy, {});
}, "target prototype is different");
var proto = {};
target = Object.setPrototypeOf({}, proto);
proxy = new Proxy(target, {
setPrototypeOf: function() {
Object.setPrototypeOf(target, {});
Object.preventExtensions(target);
return true;
}
});
assert.throws(TypeError, function() {
Reflect.setPrototypeOf(proxy, proto);
}, "target prototype is changed inside trap handler");

View File

@ -1,20 +1,55 @@
// Copyright (C) 2015 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v
es6id: 9.5.2
description: >
Return true if boolean trap result is true, target is not extensible, and
given parameter is the same as target prototype.
features: [Reflect]
Handler can only return true for non-extensible targets if the given prototype
is the same as target's prototype
info: |
[[SetPrototypeOf]] (V)
12. Let targetProto be ? target.[[GetPrototypeOf]]().
13. If SameValue(V, targetProto) is false, throw a TypeError exception.
14. Return true.
features: [Reflect.setPrototypeOf]
---*/
var target = Object.create(Array.prototype);
var p = new Proxy(target, {
setPrototypeOf: function(t, v) {
return true;
}
});
var proto = {};
var target = Object.setPrototypeOf({}, proto);
Object.preventExtensions(target);
assert(Reflect.setPrototypeOf(p, Array.prototype));
var proxy;
proxy = new Proxy(target, {
setPrototypeOf: function() {
return true;
}
});
assert.sameValue(
Reflect.setPrototypeOf(proxy, proto),
true,
"prototype arg is the same in target"
);
var outro = {};
proxy = new Proxy(outro, {
setPrototypeOf: function(t, p) {
Object.setPrototypeOf(t, p);
Object.preventExtensions(t);
return true;
}
});
assert.sameValue(
Reflect.setPrototypeOf(proxy, proto),
true,
"prototype is set to target inside handler trap"
);
assert.sameValue(
Object.getPrototypeOf(outro),
proto,
"target has the custom set prototype"
);

View File

@ -1,19 +0,0 @@
// Copyright (C) 2015 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 9.5.2
description: >
Return false if boolean trap result is false.
features: [Reflect]
---*/
var target = [];
var p = new Proxy(target, {
setPrototypeOf: function(t, v) {
return false;
}
});
Object.preventExtensions(target);
assert.sameValue(Reflect.setPrototypeOf(p, {}), false);

View File

@ -0,0 +1,24 @@
// Copyright (C) 2016 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 9.5.2
esid: sec-proxy-object-internal-methods-and-internal-slots-call-thisargument-argumentslist
description: >
Return abrupt getting handler trap
info: |
[[SetPrototypeOf]] (V)
6. Let trap be ? GetMethod(handler, "setPrototypeOf").
---*/
var handler = Object.defineProperty({}, "setPrototypeOf", {
get: function() {
throw new Test262Error();
}
});
var proxy = new Proxy({}, handler);
assert.throws(Test262Error, function() {
Object.setPrototypeOf(proxy, {});
});

View File

@ -0,0 +1,28 @@
// Copyright (C) 2016 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v
description: >
Return abrupt from IsExtensible(target)
info: |
[[SetPrototypeOf]] (V)
10. Let extensibleTarget be ? IsExtensible(target).
---*/
var target = new Proxy({}, {
isExtensible: function() {
throw new Test262Error();
}
});
var proxy = new Proxy(target, {
setPrototypeOf: function() {
return true;
}
});
assert.throws(Test262Error, function() {
Object.setPrototypeOf(proxy, {});
});

View File

@ -0,0 +1,30 @@
// Copyright (C) 2016 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v
description: >
Return abrupt from target.[[GetPrototypeOf]]()
info: |
[[SetPrototypeOf]] (V)
12. Let targetProto be ? target.[[GetPrototypeOf]]().
---*/
var target = new Proxy({}, {
getPrototypeOf: function() {
throw new Test262Error();
}
});
Object.preventExtensions(target);
var proxy = new Proxy(target, {
setPrototypeOf: function() {
return true;
}
});
assert.throws(Test262Error, function() {
Object.setPrototypeOf(proxy, {});
});

View File

@ -0,0 +1,61 @@
// Copyright (C) 2016 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v
description: >
Return false if ToBoolean(trap result) is false, without checking
target.[[IsExtensible]]
info: |
[[SetPrototypeOf]] (V)
8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, V »)).
9. If booleanTrapResult is false, return false.
10. Let extensibleTarget be ? IsExtensible(target).
11. If extensibleTarget is true, return true.
features: [Reflect.setPrototypeOf]
---*/
var called = 0;
var target = new Proxy({}, {
isExtensible: function() {
called += 1;
}
});
var p = new Proxy(target, {
setPrototypeOf: function(t, v) {
return v.attr;
}
});
var result;
result = Reflect.setPrototypeOf(p, { attr: false });
assert.sameValue(result, false, "false");
assert.sameValue(called, 0, "false - isExtensible is not called");
result = Reflect.setPrototypeOf(p, { attr: "" });
assert.sameValue(result, false, "the empty string");
assert.sameValue(called, 0, "the empty string - isExtensible is not called");
result = Reflect.setPrototypeOf(p, { attr: 0 });
assert.sameValue(result, false, "0");
assert.sameValue(called, 0, "0 - isExtensible is not called");
result = Reflect.setPrototypeOf(p, { attr: -0 });
assert.sameValue(result, false, "-0");
assert.sameValue(called, 0, "-0 - isExtensible is not called");
result = Reflect.setPrototypeOf(p, { attr: null });
assert.sameValue(result, false, "null");
assert.sameValue(called, 0, "null - isExtensible is not called");
result = Reflect.setPrototypeOf(p, { attr: undefined });
assert.sameValue(result, false, "undefined");
assert.sameValue(called, 0, "undefined - isExtensible is not called");
result = Reflect.setPrototypeOf(p, { attr: NaN });
assert.sameValue(result, false, "NaN");
assert.sameValue(called, 0, "NaN - isExtensible is not called");

View File

@ -0,0 +1,66 @@
// Copyright (C) 2016 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v
description: >
Return true if ToBoolean(trap result) is true, and target.[[IsExtensible]] is
true
info: |
[[SetPrototypeOf]] (V)
8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, V »)).
9. If booleanTrapResult is false, return false.
10. Let extensibleTarget be ? IsExtensible(target).
11. If extensibleTarget is true, return true.
features: [Reflect.setPrototypeOf, Symbol]
---*/
var called;
var target = new Proxy({}, {
isExtensible: function() {
called += 1;
return true;
},
getPrototypeOf: function() {
throw new Test262Error("target.[[GetPrototypeOf]] is not called");
}
});
var p = new Proxy(target, {
setPrototypeOf: function(t, v) {
return v.attr;
}
});
var result;
called = 0;
result = Reflect.setPrototypeOf(p, { attr: true });
assert.sameValue(result, true, "true");
assert.sameValue(called, 1, "true - isExtensible is called");
called = 0;
result = Reflect.setPrototypeOf(p, { attr: "false" });
assert.sameValue(result, true, "string");
assert.sameValue(called, 1, "string - isExtensible is called");
called = 0;
result = Reflect.setPrototypeOf(p, { attr: 42 });
assert.sameValue(result, true, "42");
assert.sameValue(called, 1, "number - isExtensible is called");
called = 0;
result = Reflect.setPrototypeOf(p, { attr: p });
assert.sameValue(result, true, "p");
assert.sameValue(called, 1, "object - isExtensible is called");
called = 0;
result = Reflect.setPrototypeOf(p, { attr: [] });
assert.sameValue(result, true, "[]");
assert.sameValue(called, 1, "[] - isExtensible is called");
called = 0;
result = Reflect.setPrototypeOf(p, { attr: Symbol(1) });
assert.sameValue(result, true, "symbol");
assert.sameValue(called, 1, "symbol - isExtensible is called");

View File

@ -18,6 +18,7 @@ info: >
2. Let func be GetV(O, P).
5. If IsCallable(func) is false, throw a TypeError exception.
...
features: [Reflect.setPrototypeOf]
---*/
var target = {};
@ -26,7 +27,7 @@ var p = new Proxy(target, {
});
assert.throws(TypeError, function() {
Object.setPrototypeOf(p, {
Reflect.setPrototypeOf(p, {
value: 1
});
});

View File

@ -0,0 +1,45 @@
// Copyright (C) 2015 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 9.5.2
esid: sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v
description: >
Return target.[[SetPrototypeOf]] (V) if trap is undefined or null.
info: |
[[SetPrototypeOf]] (V)
6. Let trap be ? GetMethod(handler, "setPrototypeOf").
7. If trap is undefined, then
a. Return ? target.[[SetPrototypeOf]](V).
GetMethod (V, P)
2. Let func be ? GetV(V, P).
3. If func is either undefined or null, return undefined.
---*/
var proxy, called, value;
var target = new Proxy({}, {
setPrototypeOf: function(t, v) {
called += 1;
value = v;
return true;
}
});
var proto = {};
proxy = new Proxy(target, {});
called = 0;
value = false;
Object.setPrototypeOf(proxy, proto);
assert.sameValue(called, 1, "undefined, target.[[SetPrototypeOf]] is called");
assert.sameValue(value, proto, "undefined, called with V");
proxy = new Proxy(target, {
setPrototypeOf: null
});
called = 0;
value = false;
Object.setPrototypeOf(proxy, proto);
assert.sameValue(called, 1, "null, target.[[SetPrototypeOf]] is called");
assert.sameValue(value, proto, "null, called with V");

View File

@ -1,14 +0,0 @@
// Copyright (C) 2015 the V8 project authors. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
es6id: 9.5.2
description: >
Return target.[[SetPrototypeOf]] (V) if trap is undefined.
---*/
var target = {};
var p = new Proxy(target, {});
Object.setPrototypeOf(p, {attr: 1});
assert.sameValue(target.attr, 1);