Bug 1914261 - Rename --noinstall to --no-install for raptor. r=perftest-reviewers...
[gecko.git] / js / src / tests / non262 / Reflect / set.js
blob83cd98b69182af83e827452f8ece749552423782
1 /* Any copyright is dedicated to the Public Domain.
2  * http://creativecommons.org/licenses/publicdomain/ */
4 // Reflect.set does property assignment.
5 // With three arguments, this is pretty straightforward.
6 var obj = {};
7 assertEq(Reflect.set(obj, "prop", "value"), true);
8 assertEq(obj.prop, "value");
11 // === Various targets
13 // It can assign array elements.
14 var arr = ["duck", "duck", "duck"];
15 assertEq(Reflect.set(arr, 2, "goose"), true);
16 assertEq(arr[2], "goose");
18 // It can extend an array.
19 assertEq(Reflect.set(arr, 3, "Model T"), true);
20 assertEq(arr.length, 4);
22 // It can truncate an array.
23 assertEq(Reflect.set(arr, "length", 1), true);
24 assertDeepEq(arr, ["duck"]);
26 // It won't assign to non-writable properties of String objects.
27 var str = new String("hello");
28 assertEq(Reflect.set(str, "0", "y"), false);
29 assertEq(str[0], "h");
30 assertEq(Reflect.set(str, "length", 700), false);
31 assertEq(str.length, 5);
34 // === Receivers
35 // The optional fourth argument is the receiver, which [[Set]] methods use for
36 // various things.
38 // On ordinary objects, if the property has a setter, the receiver is passed as
39 // the this-value to the setter.
40 var expected;
41 var obj = {
42     set prop(v) {
43         "use strict";
44         assertEq(v, 32);
45         assertEq(this, expected);
46     }
48 for (expected of [obj, {}, [], 37.3]) {
49     assertEq(Reflect.set(obj, "prop", 32, expected), true);
52 // If the property doesn't already exist, it is defined on the receiver.
53 obj = {};
54 var obj2 = {};
55 assertEq(Reflect.set(obj, "prop", 47, obj2), true);
56 assertDeepEq(obj, {});
57 assertDeepEq(Reflect.getOwnPropertyDescriptor(obj2, "prop"),
58              {value: 47, writable: true, enumerable: true, configurable: true});
60 // If the property doesn't already exist, and the receiver isn't an object, return false.
61 for (var v of SOME_PRIMITIVE_VALUES) {
62     assertEq(Reflect.set({}, "x", 0, v), false);
65 // Receiver defaults to the target.
66 obj = {};
67 var hits;
68 var expectedReceiver;
69 var proxy = new Proxy(obj, {
70     set(t, k, v, r) {
71         assertEq(t, obj);
72         assertEq(k, "key");
73         assertEq(v, "value");
74         assertEq(r, expectedReceiver); // not obj
75         hits++;
76         return true;
77     }
78 });
79 hits = 0;
80 expectedReceiver = proxy;
81 assertEq(Reflect.set(proxy, "key", "value"), true);
82 assertEq(hits, 1);
84 // But not if explicitly present and undefined.
85 hits = 0;
86 expectedReceiver = undefined;
87 assertEq(Reflect.set(proxy, "key", "value", undefined), true);
88 assertEq(hits, 1);
90 // Reflect.set can be used as fallback behavior in a proxy handler .set()
91 // method.
92 var log;
93 obj = {
94     set prop(v) {
95         log += "p";
96         assertEq(v, "value");
97         assertEq(this, proxy); // not obj!
98     }
100 proxy = new Proxy(obj, {
101     set(t, k, v, r) {
102         assertEq(t, obj);
103         assertEq(r, proxy);
104         log += "s";
105         return Reflect.set(t, k, v, r);
106     }
108 log = "";
109 assertEq(Reflect.set(proxy, "prop", "value"), true);
110 assertEq(log, "sp");
113 // === Cross-compartment wrapper behavior.
115 // When calling a cross-compartment wrapper, receiver is rewrapped for the
116 // target compartment.
117 var g = newGlobal();
118 if (!("assertEq" in g))
119     g.assertEq = assertEq;  // necessary in the browser
120 g.eval(`
121      var hits;
122      var obj = {
123          set x(v) {
124              "use strict";
125              assertEq(this, receiver);
126              assertEq(v, "xyzzy");
127              hits++;
128          }
129      };
130      var receiver = {};
132 g.hits = 0;
133 assertEq(Reflect.set(g.obj, "x", "xyzzy", g.receiver), true);
134 assertEq(g.hits, 1);
136 // ...even when receiver is from a different compartment than target.
137 var receiver = {};
138 g.receiver = receiver;
139 g.hits = 0;
140 assertEq(Reflect.set(g.obj, "x", "xyzzy", receiver), true);
141 assertEq(g.hits, 1);
143 // ...even when receiver is a primtive value, even undefined.
144 for (receiver of SOME_PRIMITIVE_VALUES) {
145     g.receiver = receiver;
146     g.hits = 0;
147     assertEq(Reflect.set(g.obj, "x", "xyzzy", receiver), true);
148     assertEq(g.hits, 1);
152 // === Less than 3 arguments
154 // With two arguments, the value is assumed to be undefined.
155 obj = {};
156 assertEq(Reflect.set(obj, "size"), true);
157 assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "size"),
158              {value: undefined, writable: true, enumerable: true, configurable: true});
160 // With just one argument, the key is "undefined".
161 obj = {};
162 assertEq(Reflect.set(obj), true);
163 assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "undefined"),
164              {value: undefined, writable: true, enumerable: true, configurable: true});
166 // For the no argument-case, see target.js.
169 // === Failure cases
171 // Non-writable data property
172 obj = {};
173 Reflect.defineProperty(obj, "x", {value: 0, writable: false});
174 assertEq(Reflect.set(obj, "x", 1), false);
175 assertEq(obj.x, 0);
177 // The same, but inherited from a prototype
178 var obj2 = Object.create(obj);
179 assertEq(Reflect.set(obj2, "x", 1), false);
180 assertEq(obj2.hasOwnProperty("x"), false);
181 assertEq(obj2.x, 0);
183 // Getter, no setter
184 obj = {};
185 var desc = {get: () => 12, set: undefined, enumerable: false, configurable: true};
186 Reflect.defineProperty(obj, "y", desc);
187 assertEq(Reflect.set(obj, "y", 13), false);
188 assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "y"), desc);
190 // The same, but inherited from a prototype
191 obj2 = Object.create(obj);
192 assertEq(Reflect.set(obj2, "y", 1), false);
193 assertEq(obj2.hasOwnProperty("y"), false);
194 assertDeepEq(Reflect.getOwnPropertyDescriptor(obj, "y"), desc);
196 // Proxy set handler returns a false value
197 for (var no of [false, ""]) {
198     var hits = 0;
199     obj = {};
200     var proxy = new Proxy(obj, {
201         set(t, k, v, r) {
202             assertEq(t, obj);
203             assertEq(k, "x");
204             assertEq(v, 33);
205             assertEq(r, proxy);
206             hits++;
207             return no;
208         }
209     });
210     assertEq(Reflect.set(proxy, "x", 33), false);
211     assertEq(hits, 1);
212     assertEq("x" in obj, false);
215 // Proxy handler method throws
216 obj = {};
217 proxy = new Proxy(obj, {
218     set(t, k, v, r) { throw "i don't like " + v; }
220 assertThrowsValue(() => Reflect.set(proxy, "food", "cheese"), "i don't like cheese");
222 // If a Proxy set handler breaks the object invariants, it's a TypeError.
223 for (obj of [{a: 0}, {get a() { return 0; }}]) {
224     Object.freeze(obj);
225     proxy = new Proxy(obj, {
226         set(t, k, v, r) { return true; }
227     });
228     assertThrowsInstanceOf(() => Reflect.set(proxy, "a", "b"), TypeError);
231 // Per spec, this should first call p.[[Set]]("0", 42, a) and
232 // then (since p has no own properties) a.[[Set]]("0", 42, a).
233 // The latter should not define a property on p.
234 var a = [0, 1, 2, 3];
235 var p = Object.create(a);
236 Reflect.set(p, "0", 42, a);
237 assertEq(p.hasOwnProperty("0"), false);
238 assertDeepEq(Reflect.getOwnPropertyDescriptor(a, "0"),
239              {value: 42, writable: true, enumerable: true, configurable: true});
241 // Test behavior of ordinary objects' [[Set]] method (ES6 9.1.9).
242 // On an ordinary object, if the property key isn't present, [[Set]] calls
243 // receiver.[[GetOwnProperty]]() and then receiver.[[DefineProperty]]().
244 var log;
245 obj = {};
246 var proxyTarget = {};
247 var existingDescriptor, expected, defineResult;
248 var receiver = new Proxy(proxyTarget, {
249     getOwnPropertyDescriptor(t, k) {
250         log += "g";
251         return existingDescriptor;
252     },
253     defineProperty(t, k, desc) {
254         log += "d";
255         assertEq(t, proxyTarget);
256         assertEq(k, "prop");
257         assertDeepEq(desc, expected);
258         return defineResult;
259     }
261 existingDescriptor = undefined;
262 expected = {value: 5, writable: true, enumerable: true, configurable: true};
263 for (var defineResult of [true, false]) {
264     log = "";
265     assertEq(Reflect.set(obj, "prop", 5, receiver), defineResult);
266     assertEq(log, "gd");
269 existingDescriptor = {value: 7, writable: true, enumerable: false, configurable: true};
270 expected = {value: 4};
271 for (var defineResult of [true, false]) {
272     log = "";
273     assertEq(Reflect.set(obj, "prop", 4, receiver), defineResult);
274     assertEq(log, "gd");
278 // For more Reflect.set tests, see target.js and propertyKeys.js.
280 reportCompare(0, 0);