|
1 // Test ES6 Proxy trap compliance for Object.isExtensible() on exotic proxy |
|
2 // objects. |
|
3 var unsealed = {}; |
|
4 var sealed = Object.seal({}); |
|
5 var handler = {}; |
|
6 |
|
7 assertEq(Object.isExtensible(unsealed), true); |
|
8 assertEq(Object.isExtensible(sealed), false); |
|
9 |
|
10 var targetSealed = new Proxy(sealed, handler); |
|
11 var targetUnsealed = new Proxy(unsealed, handler); |
|
12 |
|
13 var handlerCalled = false; |
|
14 |
|
15 // without traps, forward to the target |
|
16 // First, make sure we get the obvious answer on a non-exotic target. |
|
17 assertEq(Object.isExtensible(targetSealed), false, "Must forward to target without hook."); |
|
18 assertEq(Object.isExtensible(targetUnsealed), true, "Must forward to target without hook."); |
|
19 |
|
20 // Now, keep everyone honest. What if the target itself is a proxy? |
|
21 function ensureCalled() { handlerCalled = true; return true; } |
|
22 var proxyTarget = new Proxy({}, { isExtensible : ensureCalled }); |
|
23 assertEq(Object.isExtensible(new Proxy(proxyTarget, {})), true, "Must forward to target without hook."); |
|
24 assertEq(handlerCalled, true, "Must forward to target without hook."); |
|
25 |
|
26 // with traps, makes sure that the handler is called, and that we throw if the |
|
27 // trap disagrees with the target |
|
28 function testExtensible(obj, shouldThrow, expectedResult) |
|
29 { |
|
30 handlerCalled = false; |
|
31 if (shouldThrow) |
|
32 assertThrowsInstanceOf(function () { Object.isExtensible(obj); }, |
|
33 TypeError, "Must throw if handler and target disagree."); |
|
34 else |
|
35 assertEq(Object.isExtensible(obj), expectedResult, "Must return the correct value."); |
|
36 assertEq(handlerCalled, true, "Must call handler trap if present"); |
|
37 } |
|
38 |
|
39 // What if the trap says it's necessarily sealed? |
|
40 function fakeSealed() { handlerCalled = true; return false; } |
|
41 handler.isExtensible = fakeSealed; |
|
42 testExtensible(targetSealed, false, false); |
|
43 testExtensible(targetUnsealed, true); |
|
44 |
|
45 // What if the trap says it's never sealed? |
|
46 function fakeUnsealed() { handlerCalled = true; return true; } |
|
47 handler.isExtensible = fakeUnsealed; |
|
48 testExtensible(targetSealed, true); |
|
49 testExtensible(targetUnsealed, false, true); |
|
50 |
|
51 // make sure we are able to prevent further extensions mid-flight and throw if the |
|
52 // hook tries to lie. |
|
53 function makeSealedTruth(target) { handlerCalled = true; Object.preventExtensions(target); return false; } |
|
54 function makeSealedLie(target) { handlerCalled = true; Object.preventExtensions(target); return true; } |
|
55 handler.isExtensible = makeSealedTruth; |
|
56 testExtensible(new Proxy({}, handler), false, false); |
|
57 handler.isExtensible = makeSealedLie; |
|
58 testExtensible(new Proxy({}, handler), true); |
|
59 |
|
60 // What if the trap doesn't directly return a boolean? |
|
61 function falseyNonBool() { handlerCalled = true; return undefined; } |
|
62 handler.isExtensible = falseyNonBool; |
|
63 testExtensible(targetSealed, false, false); |
|
64 testExtensible(targetUnsealed, true); |
|
65 |
|
66 function truthyNonBool() { handlerCalled = true; return {}; } |
|
67 handler.isExtensible = truthyNonBool; |
|
68 testExtensible(targetSealed, true); |
|
69 testExtensible(targetUnsealed, false, true); |
|
70 |
|
71 // What if the trap throws? |
|
72 function ExtensibleError() { } |
|
73 ExtensibleError.prototype = new Error(); |
|
74 ExtensibleError.prototype.constructor = ExtensibleError; |
|
75 function throwFromTrap() { throw new ExtensibleError(); } |
|
76 handler.isExtensible = throwFromTrap; |
|
77 |
|
78 // exercise some other code paths and make sure that they invoke the trap and |
|
79 // can handle the ensuing error. |
|
80 assertThrowsInstanceOf(function () { Object.isExtensible(targetSealed); }, |
|
81 ExtensibleError, "Must throw if the trap does."); |
|
82 assertThrowsInstanceOf(function () { Object.isFrozen(targetSealed); }, |
|
83 ExtensibleError, "Must throw if the trap does."); |
|
84 assertThrowsInstanceOf(function () { Object.isSealed(targetSealed); }, |
|
85 ExtensibleError, "Must throw if the trap does."); |
|
86 |
|
87 |
|
88 // What if the trap likes to re-ask old questions? |
|
89 function recurse() { return Object.isExtensible(targetSealed); } |
|
90 handler.isExtensible = recurse; |
|
91 assertThrowsInstanceOf(function () { Object.isExtensible(targetSealed); }, |
|
92 InternalError, "Should allow and detect infinite recurison."); |
|
93 |
|
94 reportCompare(0, 0, "OK"); |