1// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Flags: --harmony-reflect
6
7
8(function testReflectConstructArity() {
9  assertEquals(2, Reflect.construct.length);
10})();
11
12
13(function testReflectConstructNonConstructor() {
14  assertThrows(function() {
15    new Reflect.construct(function(){}, []);
16  }, TypeError);
17})();
18
19
20(function testReflectConstructBasic() {
21  function Constructor() { "use strict"; }
22  assertInstanceof(Reflect.construct(Constructor, []), Constructor);
23})();
24
25
26(function testReflectConstructBasicSloppy() {
27  function Constructor() {}
28  assertInstanceof(Reflect.construct(Constructor, []), Constructor);
29})();
30
31
32(function testReflectConstructReturnSomethingElseStrict() {
33  var R = {};
34  function Constructor() { "use strict"; return R; }
35  assertSame(R, Reflect.construct(Constructor, []));
36})();
37
38
39(function testReflectConstructReturnSomethingElseSloppy() {
40  var R = {};
41  function Constructor() { return R; }
42  assertSame(R, Reflect.construct(Constructor, []));
43})();
44
45
46(function testReflectConstructNewTargetStrict() {
47  "use strict";
48  function Constructor() { this[9] = 1; }
49  var O = Reflect.construct(Constructor, [], Array);
50  assertEquals(1, O[9]);
51  // Ordinary object with Array.prototype --- no exotic Array magic
52  assertFalse(Array.isArray(O));
53  assertEquals(0, O.length);
54  assertSame(Array.prototype, Object.getPrototypeOf(O));
55})();
56
57
58(function testReflectConstructNewTargetSloppy() {
59  function Constructor() { this[9] = 1; }
60  var O = Reflect.construct(Constructor, [], Array);
61  assertEquals(1, O[9]);
62  // Ordinary object with Array.prototype --- no exotic Array magic
63  assertFalse(Array.isArray(O));
64  assertEquals(0, O.length);
65  assertSame(Array.prototype, Object.getPrototypeOf(O));
66})();
67
68
69(function testReflectConstructNewTargetStrict2() {
70  "use strict";
71  function Constructor() { this[9] = 1; }
72  Constructor.prototype.add = function(x) {
73    this[this.length] = x; return this;
74  }
75  var O = Reflect.construct(Array, [1, 2, 3], Constructor);
76  // Exotic Array object with Constructor.prototype
77  assertTrue(Array.isArray(O));
78  assertSame(Constructor.prototype, Object.getPrototypeOf(O));
79  assertFalse(O instanceof Array);
80  assertEquals(3, O.length);
81  assertEquals(undefined, O[9]);
82  assertSame(O, O.add(4));
83  assertEquals(4, O.length);
84  assertEquals(4, O[3]);
85})();
86
87
88(function testReflectConstructNewTargetSloppy2() {
89  function Constructor() { this[9] = 1; }
90  Constructor.prototype.add = function(x) {
91    this[this.length] = x; return this;
92  }
93  var O = Reflect.construct(Array, [1, 2, 3], Constructor);
94  // Exotic Array object with Constructor.prototype
95  assertTrue(Array.isArray(O));
96  assertSame(Constructor.prototype, Object.getPrototypeOf(O));
97  assertFalse(O instanceof Array);
98  assertEquals(3, O.length);
99  assertEquals(undefined, O[9]);
100  assertSame(O, O.add(4));
101  assertEquals(4, O.length);
102  assertEquals(4, O[3]);
103})();
104
105
106(function testReflectConstructNewTargetStrict3() {
107  "use strict";
108  function A() {}
109  function B() {}
110  var O = Reflect.construct(A, [], B);
111  // TODO(caitp): bug: newTarget prototype is not used if it is not
112  // explicitly set.
113  //assertSame(B.prototype, Object.getPrototypeOf(O));
114})();
115
116
117(function testReflectConstructNewTargetSloppy3() {
118  function A() {}
119  function B() {}
120  var O = Reflect.construct(A, [], B);
121  // TODO(caitp): bug: newTarget prototype is not used if it is not
122  // explicitly set.
123  //assertSame(B.prototype, Object.getPrototypeOf(O));
124})();
125
126
127(function testAppliedArgumentsLength() {
128  function lengthStrict() { 'use strict'; this.a = arguments.length; }
129  function lengthSloppy() { this.a = arguments.length; }
130
131  assertEquals(0, Reflect.construct(lengthStrict, []).a);
132  assertEquals(0, Reflect.construct(lengthSloppy, []).a);
133  assertEquals(0, Reflect.construct(lengthStrict, {}).a);
134  assertEquals(0, Reflect.construct(lengthSloppy, {}).a);
135
136  for (var i = 0; i < 256; ++i) {
137    assertEquals(i, Reflect.construct(lengthStrict, new Array(i)).a);
138    assertEquals(i, Reflect.construct(lengthSloppy, new Array(i)).a);
139    assertEquals(i, Reflect.construct(lengthStrict, { length: i }).a);
140    assertEquals(i, Reflect.construct(lengthSloppy, { length: i }).a);
141  }
142})();
143
144
145(function testAppliedArgumentsLengthThrows() {
146  function noopStrict() { 'use strict'; }
147  function noopSloppy() { }
148  function MyError() {}
149
150  var argsList = {};
151  Object.defineProperty(argsList, "length", {
152    get: function() { throw new MyError(); }
153  });
154
155  assertThrows(function() {
156    Reflect.construct(noopStrict, argsList);
157  }, MyError);
158
159  assertThrows(function() {
160    Reflect.construct(noopSloppy, argsList);
161  }, MyError);
162})();
163
164
165(function testAppliedArgumentsElementThrows() {
166  function noopStrict() { 'use strict'; }
167  function noopSloppy() { }
168  function MyError() {}
169
170  var argsList = { length: 1 };
171  Object.defineProperty(argsList, "0", {
172    get: function() { throw new MyError(); }
173  });
174
175  assertThrows(function() {
176    Reflect.construct(noopStrict, argsList);
177  }, MyError);
178
179  assertThrows(function() {
180    Reflect.construct(noopSloppy, argsList);
181  }, MyError);
182})();
183
184
185(function testAppliedNonFunctionStrict() {
186  'use strict';
187  assertThrows(function() { Reflect.construct(void 0, []); }, TypeError);
188  assertThrows(function() { Reflect.construct(null, []); }, TypeError);
189  assertThrows(function() { Reflect.construct(123, []); }, TypeError);
190  assertThrows(function() { Reflect.construct("str", []); }, TypeError);
191  assertThrows(function() { Reflect.construct(Symbol("x"), []); }, TypeError);
192  assertThrows(function() { Reflect.construct(/123/, []); }, TypeError);
193  assertThrows(function() { Reflect.construct(NaN, []); }, TypeError);
194  assertThrows(function() { Reflect.construct({}, []); }, TypeError);
195  assertThrows(function() { Reflect.construct([], []); }, TypeError);
196})();
197
198
199(function testAppliedNonFunctionSloppy() {
200  assertThrows(function() { Reflect.construct(void 0, []); }, TypeError);
201  assertThrows(function() { Reflect.construct(null, []); }, TypeError);
202  assertThrows(function() { Reflect.construct(123, []); }, TypeError);
203  assertThrows(function() { Reflect.construct("str", []); }, TypeError);
204  assertThrows(function() { Reflect.construct(Symbol("x"), []); }, TypeError);
205  assertThrows(function() { Reflect.construct(/123/, []); }, TypeError);
206  assertThrows(function() { Reflect.construct(NaN, []); }, TypeError);
207  assertThrows(function() { Reflect.construct({}, []); }, TypeError);
208  assertThrows(function() { Reflect.construct([], []); }, TypeError);
209})();
210
211
212(function testAppliedArgumentsNonList() {
213  function noopStrict() { 'use strict'; }
214  function noopSloppy() {}
215  assertThrows(function() { Reflect.construct(noopStrict, null); }, TypeError);
216  assertThrows(function() { Reflect.construct(noopSloppy, null); }, TypeError);
217  assertThrows(function() { Reflect.construct(noopStrict, 1); }, TypeError);
218  assertThrows(function() { Reflect.construct(noopSloppy, 1); }, TypeError);
219  assertThrows(function() { Reflect.construct(noopStrict, "BAD"); }, TypeError);
220  assertThrows(function() { Reflect.construct(noopSloppy, "BAD"); }, TypeError);
221  assertThrows(function() { Reflect.construct(noopStrict, true); }, TypeError);
222  assertThrows(function() { Reflect.construct(noopSloppy, true); }, TypeError);
223  var sym = Symbol("x");
224  assertThrows(function() { Reflect.construct(noopStrict, sym); }, TypeError);
225  assertThrows(function() { Reflect.construct(noopSloppy, sym); }, TypeError);
226})();
227
228
229(function testAppliedArgumentValue() {
230  function firstStrict(a) { 'use strict'; this.a = a; }
231  function firstSloppy(a) { this.a = a; }
232  function lastStrict(a) {
233    'use strict'; this.a = arguments[arguments.length - 1]; }
234  function lastSloppy(a) { this.a = arguments[arguments.length - 1]; }
235  function sumStrict() {
236    'use strict';
237    var sum = arguments[0];
238    for (var i = 1; i < arguments.length; ++i) {
239      sum += arguments[i];
240    }
241    this.a = sum;
242  }
243  function sumSloppy() {
244    var sum = arguments[0];
245    for (var i = 1; i < arguments.length; ++i) {
246      sum += arguments[i];
247    }
248    this.a = sum;
249  }
250
251  assertEquals("OK!", Reflect.construct(firstStrict, ["OK!"]).a);
252  assertEquals("OK!", Reflect.construct(firstSloppy, ["OK!"]).a);
253  assertEquals("OK!", Reflect.construct(firstStrict,
254                                        { 0: "OK!", length: 1 }).a);
255  assertEquals("OK!", Reflect.construct(firstSloppy,
256                                        { 0: "OK!", length: 1 }).a);
257  assertEquals("OK!", Reflect.construct(lastStrict,
258                                        [0, 1, 2, 3, 4, 5, 6, 7, 8, "OK!"]).a);
259  assertEquals("OK!", Reflect.construct(lastSloppy,
260                                        [0, 1, 2, 3, 4, 5, 6, 7, 8, "OK!"]).a);
261  assertEquals("OK!", Reflect.construct(lastStrict,
262                                        { 9: "OK!", length: 10 }).a);
263  assertEquals("OK!", Reflect.construct(lastSloppy,
264                                        { 9: "OK!", length: 10 }).a);
265  assertEquals("TEST", Reflect.construct(sumStrict,
266                                         ["T", "E", "S", "T"]).a);
267  assertEquals("TEST!!", Reflect.construct(sumStrict,
268                                           ["T", "E", "S", "T", "!", "!"]).a);
269  assertEquals(10, Reflect.construct(sumStrict,
270                                     { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 }).a);
271  assertEquals("TEST", Reflect.construct(sumSloppy,
272                                         ["T", "E", "S", "T"]).a);
273  assertEquals("TEST!!", Reflect.construct(sumSloppy,
274                                           ["T", "E", "S", "T", "!", "!"]).a);
275  assertEquals(10, Reflect.construct(sumSloppy,
276                                     { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 }).a);
277})();
278
279(function() {
280  function* f() { yield 1; yield 2; }
281  function* g() { yield 3; yield 4; }
282  var o = Reflect.construct(f, [], g);
283  assertEquals([1, 2], [...o]);
284  assertTrue(o.__proto__ === g.prototype);
285  assertTrue(o.__proto__ !== f.prototype);
286})();
287
288(function () {
289  var realm1 = Realm.create();
290  var realm2 = Realm.create();
291
292  var well_known_intrinsic_constructors = [
293      "Array",
294      "ArrayBuffer",
295      "Boolean",
296      ["DataView", [new ArrayBuffer()]],
297      "Date",
298      "Error",
299      "EvalError",
300      "Float32Array",
301      "Float64Array",
302      ["Function", ["return 153;"]],
303      ["Function", ["'use strict'; return 153;"]],
304      ["Function", ["'use strong'; return 153;"]],
305      ["((function*(){}).constructor)", ["yield 153;"]],  // GeneratorFunction
306      ["((function*(){}).constructor)", ["'use strict'; yield 153;"]],
307      ["((function*(){}).constructor)", ["'use strong'; yield 153;"]],
308      "Int8Array",
309      "Int16Array",
310      "Int32Array",
311      "Map",
312      "Number",
313      "Object",
314      ["Promise", [(resolve, reject)=>{}]],
315      "RangeError",
316      "ReferenceError",
317      "RegExp",
318      "Set",
319      "String",
320      "SyntaxError",
321      // %TypedArray%?
322      "TypeError",
323      "Uint8Array",
324      "Uint8ClampedArray",
325      "Uint16Array",
326      "Uint32Array",
327      "URIError",
328      "WeakMap",
329      "WeakSet"
330  ];
331
332  function getname(v) {
333    return typeof v === "string" ? v : v[0];
334  }
335
336  function getargs(v) {
337    return typeof v === "string" ? [] : v[1];
338  }
339
340  function test_intrinsic_prototype(name) {
341    var own = Realm.eval(realm1, name);
342
343    // Ensure that constructor.prototype is non-writable, non-configurable.
344    var desc = Object.getOwnPropertyDescriptor(own, "prototype");
345    assertFalse(desc.configurable, name);
346    assertFalse(desc.writable, name);
347  }
348
349  for (var intrinsic of well_known_intrinsic_constructors) {
350    test_intrinsic_prototype(getname(intrinsic));
351  }
352
353  function function_with_non_instance_prototype(realm) {
354    var f = Realm.eval(realm, "(function(){})");
355    f.prototype = 1;
356    return f;
357  }
358
359  function test_intrinsic_default(realm, name, args, convert) {
360    var own = Realm.eval(realm1, name);
361    var other = Realm.eval(realm, name);
362    var o = Reflect.construct(
363        convert(own), args, function_with_non_instance_prototype(realm));
364
365    // Ensure the intrisicDefaultProto is fetched from the correct realm.
366    assertTrue(realm == realm1 || o.__proto__ !== own.prototype, [...arguments]);
367    assertTrue(o.__proto__ === other.prototype, [...arguments]);
368  }
369
370  function test_all(test, convert) {
371    for (var intrinsic of well_known_intrinsic_constructors) {
372      for (var realm of [realm1, realm2]) {
373        test(realm, getname(intrinsic), getargs(intrinsic), convert);
374      }
375    }
376  }
377
378  test_all(test_intrinsic_default, (v)=>v);
379  test_all(test_intrinsic_default,
380           (v)=>{ "use strict"; return class extends v {}});
381})();
382