Index: test/mjsunit/harmony/proxies-set.js |
diff --git a/test/mjsunit/harmony/proxies-set.js b/test/mjsunit/harmony/proxies-set.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7c6cef6d43f76e83f17866cd5c8ce3b80f5b3171 |
--- /dev/null |
+++ b/test/mjsunit/harmony/proxies-set.js |
@@ -0,0 +1,237 @@ |
+// 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. |
+ |
+// Flags: --harmony-proxies --harmony-reflect |
+ |
+ |
+// TODO(neis): There is so much more we could test, for instance: |
+// - Test with non-trivial receiver argument. |
+// - Test with function proxies as setters/getters. |
+// - Test with proxies in the prototype chain. |
+// - Check that non-object receiver is passed to proxy in prototype |
+// chain. |
+ |
+ |
+function sloppyDefaultSet(o, p, v) { return o[p] = v } |
+function sloppyReflectSet(o, p, v) { return Reflect.set(o, p, v) } |
+function strictDefaultSet(o, p, v) { "use strict"; return o[p] = v } |
+function strictReflectSet(o, p, v) { "use strict"; return Reflect.set(o, p, v) } |
+ |
+sloppyDefaultSet.shouldThrow = false; |
+sloppyReflectSet.shouldThrow = false; |
+strictDefaultSet.shouldThrow = true; |
+strictReflectSet.shouldThrow = false; |
+ |
+sloppyDefaultSet.returnsBool = false; |
+sloppyReflectSet.returnsBool = true; |
+strictDefaultSet.returnsBool = false; |
+strictReflectSet.returnsBool = true; |
+ |
+ |
+function assertTrueIf(flag, x) { if (flag) assertTrue(x) } |
+function assertFalseIf(flag, x) { if (flag) assertFalse(x) } |
+function assertSetFails(mySet, o, p, v) { |
+ if (mySet.shouldThrow) { |
+ assertThrows(() => mySet(o, p, v), TypeError); |
+ } else { |
+ assertFalseIf(mySet.returnsBool, mySet(o, p, v)); |
+ } |
+} |
+ |
+ |
+function dataDescriptor(x) { |
+ return {value: x, writable: true, enumerable: true, configurable: true}; |
+} |
+ |
+ |
+function toKey(x) { |
+ if (typeof x === "symbol") return x; |
+ return String(x); |
+} |
+ |
+ |
+var properties = |
+ ["bla", "0", 1, Symbol(), {[Symbol.toPrimitive]() {return "a"}}]; |
+ |
+ |
+function TestForwarding(handler, mySet) { |
+ assertTrue(undefined == handler.set); |
+ assertTrue(undefined == handler.getOwnPropertyDescriptor); |
+ assertTrue(undefined == handler.defineProperty); |
+ |
+ var target = {}; |
+ var proxy = new Proxy(target, handler); |
+ |
+ // Property does not exist on target. |
+ for (var p of properties) { |
+ assertTrueIf(mySet.returnsBool, mySet(proxy, p, 42)); |
+ assertSame(42, target[p]); |
+ } |
+ |
+ // Property exists as writable data on target. |
+ for (var p of properties) { |
+ assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0)); |
+ assertSame(0, target[p]); |
+ } |
+ |
+ // Property exists as non-writable data on target. |
+ for (var p of properties) { |
+ Object.defineProperty(target, p, |
+ {value: 42, configurable: true, writable: false}); |
+ assertSetFails(mySet, proxy, p, 42); |
+ assertSetFails(mySet, proxy, p, 0); |
+ assertEquals(42, target[p]); |
+ } |
+}; |
+ |
+ |
+(function () { |
+ // No trap. |
+ |
+ var handler = {}; |
+ |
+ TestForwarding(handler, sloppyDefaultSet); |
+ TestForwarding(handler, sloppyReflectSet); |
+ TestForwarding(handler, strictDefaultSet); |
+ TestForwarding(handler, strictReflectSet); |
+})(); |
+ |
+ |
+(function () { |
+ // "Undefined" trap. |
+ |
+ var handler = { set: null }; |
+ |
+ TestForwarding(handler, sloppyDefaultSet); |
+ TestForwarding(handler, sloppyReflectSet); |
+ TestForwarding(handler, strictDefaultSet); |
+ TestForwarding(handler, strictReflectSet); |
+})(); |
+ |
+ |
+function TestForwarding2(mySet) { |
+ // Check that setting on a proxy without "set" trap correctly triggers its |
+ // "getOwnProperty" trap and its "defineProperty" trap. |
+ |
+ var target = {}; |
+ var handler = {}; |
+ var observations = []; |
+ var proxy = new Proxy(target, handler); |
+ |
+ handler.getOwnPropertyDescriptor = function() { |
+ observations.push(arguments); |
+ return Reflect.getOwnPropertyDescriptor(...arguments); |
+ } |
+ |
+ handler.defineProperty = function() { |
+ observations.push(arguments); |
+ return Reflect.defineProperty(...arguments); |
+ } |
+ |
+ for (var p of properties) { |
+ Reflect.set(proxy, p, 42); |
+ assertEquals(2, observations.length) |
+ assertArrayEquals([target, toKey(p)], observations[0]); |
+ assertArrayEquals([target, toKey(p), dataDescriptor(42)], observations[1]); |
+ observations = []; |
+ |
+ Reflect.set(proxy, p, 42); |
+ assertEquals(2, observations.length) |
+ assertArrayEquals([target, toKey(p)], observations[0]); |
+ assertArrayEquals([target, toKey(p), {value: 42}], observations[1]); |
+ observations = []; |
+ } |
+} |
+ |
+ |
+TestForwarding2(sloppyDefaultSet); |
+TestForwarding2(sloppyReflectSet); |
+TestForwarding2(strictDefaultSet); |
+TestForwarding2(strictReflectSet); |
+ |
+ |
+function TestInvalidTrap(proxy, mySet) { |
+ for (var p of properties) { |
+ assertThrows(() => mySet(proxy, p, 42), TypeError); |
+ } |
+} |
+ |
+ |
+(function () { |
+ var target = {}; |
+ var handler = { set: true }; |
+ var proxy = new Proxy(target, handler); |
+ |
+ TestInvalidTrap(proxy, sloppyDefaultSet); |
+ TestInvalidTrap(proxy, sloppyReflectSet); |
+ TestInvalidTrap(proxy, strictDefaultSet); |
+ TestInvalidTrap(proxy, strictReflectSet); |
+})(); |
+ |
+ |
+function TestTrappingFalsish(mySet) { |
+ var target = {}; |
+ var handler = { set() {return ""} }; |
+ var proxy = new Proxy(target, handler); |
+ |
+ for (var p of properties) { |
+ assertSetFails(mySet, proxy, p, 42); |
+ } |
+} |
+ |
+ |
+TestTrappingFalsish(sloppyDefaultSet); |
+TestTrappingFalsish(sloppyReflectSet); |
+TestTrappingFalsish(strictDefaultSet); |
+TestTrappingFalsish(strictReflectSet); |
+ |
+ |
+function TestTrappingTrueish(mySet) { |
+ var target = {}; |
+ var handler = { set() {return 42} }; |
+ var proxy = new Proxy(target, handler); |
+ |
+ // Trap returns trueish and property does not exist in target. |
+ for (var p of properties) { |
+ assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0)); |
+ } |
+ |
+ // Trap returns trueish and target property is configurable or writable. |
+ for (var p of properties) { |
+ Object.defineProperty(target, p, {configurable: true, writable: true}); |
+ assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0)); |
+ Object.defineProperty(target, p, {configurable: true, writable: false}); |
+ assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0)); |
+ Object.defineProperty(target, p, {configurable: false, writable: true}); |
+ assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0)); |
+ } |
+} |
+ |
+ |
+TestTrappingTrueish(sloppyDefaultSet); |
+TestTrappingTrueish(sloppyReflectSet); |
+TestTrappingTrueish(strictDefaultSet); |
+TestTrappingTrueish(strictReflectSet); |
+ |
+ |
+function TestTrappingTrueish2(mySet) { |
+ var target = {}; |
+ var handler = { set() {return 42} }; |
+ var proxy = new Proxy(target, handler); |
+ |
+ // Trap returns trueish but target property is frozen. |
+ for (var p of properties) { |
+ Object.defineProperty(target, p, { |
+ configurable: false, writable: false, value: 0 |
+ }); |
+ assertThrows(() => mySet(proxy, p, 666), TypeError); // New value. |
+ assertTrueIf(mySet.returnsBool, mySet(proxy, p, 0)); // Old value. |
+ } |
+}; |
+ |
+ |
+TestTrappingTrueish2(sloppyDefaultSet); |
+TestTrappingTrueish2(sloppyReflectSet); |
+TestTrappingTrueish2(strictDefaultSet); |
+TestTrappingTrueish2(strictReflectSet); |