blob: cea2bb30ec85c94e6f12dbde05e2ca700c692bab [file] [log] [blame]
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Tests for the argumentList argument to Reflect.apply and Reflect.construct.
// Reflect.apply and Reflect.construct require an argumentList argument that must be an object.
assertThrowsInstanceOf(() => Reflect.apply(Math.min, undefined), // missing
TypeError);
assertThrowsInstanceOf(() => Reflect.construct(Object), // missing
TypeError);
for (var primitive of SOME_PRIMITIVE_VALUES) {
assertThrowsInstanceOf(() => Reflect.apply(Math.min, undefined, primitive),
TypeError);
assertThrowsInstanceOf(() => Reflect.construct(Object, primitive),
TypeError);
}
// Array used by several tests below.
var BOTH = [
Reflect.apply,
// Adapt Reflect.construct to accept the same arguments as Reflect.apply.
(target, thisArgument, argumentList) => Reflect.construct(target, argumentList)
];
// The argumentList is copied and becomes the list of arguments passed to the function.
function getRest(...x) { return x; }
var args = [1, 2, 3];
for (var method of BOTH) {
var result = method(getRest, undefined, args);
assertEq(result.join(), args.join());
assertEq(result !== args, true);
}
// argumentList.length can be less than func.length.
function testLess(a, b, c, d, e) {
assertEq(a, 1);
assertEq(b, true);
assertEq(c, "three");
assertEq(d, Symbol.for);
assertEq(e, undefined);
assertEq(arguments.length, 4);
assertEq(arguments !== args, true);
return "ok";
}
args = [1, true, "three", Symbol.for];
assertEq(Reflect.apply(testLess, undefined, args), "ok");
assertEq(Reflect.construct(testLess, args) instanceof testLess, true);
// argumentList.length can be more than func.length.
function testMoar(a) {
assertEq(a, args[0]);
return "good";
}
assertEq(Reflect.apply(testMoar, undefined, args), "good");
assertEq(Reflect.construct(testMoar, args) instanceof testMoar, true);
// argumentList can be any object with a .length property.
function getArgs(...args) {
return args;
}
for (var method of BOTH) {
assertDeepEq(method(getArgs, undefined, {length: 0}),
[]);
assertDeepEq(method(getArgs, undefined, {length: 1, "0": "zero"}),
["zero"]);
assertDeepEq(method(getArgs, undefined, {length: 2}),
[undefined, undefined]);
assertDeepEq(method(getArgs, undefined, function (a, b, c) {}),
[undefined, undefined, undefined]);
}
// The Iterable/Iterator interfaces are not used.
var funnyArgs = {
0: "zero",
1: "one",
length: 2,
[Symbol.iterator]() { throw "FAIL 1"; },
next() { throw "FAIL 2"; }
};
for (var method of BOTH) {
assertDeepEq(method(getArgs, undefined, funnyArgs),
["zero", "one"]);
}
// If argumentList has no .length property, no arguments are passed.
function count() { return {numArgsReceived: arguments.length}; }
for (var method of BOTH) {
assertEq(method(count, undefined, {"0": 0, "1": 1}).numArgsReceived,
0);
function* g() { yield 1; yield 2; }
assertEq(method(count, undefined, g()).numArgsReceived,
0);
}
// If argumentsList.length has a getter, it is called.
var log;
args = {
get length() { log += "L"; return 1; },
get "0"() { log += "0"; return "zero"; },
get "1"() { log += "1"; return "one"; }
};
for (var method of BOTH) {
log = "";
assertDeepEq(method(getArgs, undefined, args),
["zero"]);
assertEq(log, "L0");
}
// The argumentsList.length getter can throw; the exception is propagated.
var exc = {status: "bad"};
args = {
get length() { throw exc; }
};
for (var method of BOTH) {
assertThrowsValue(() => method(count, undefined, args), exc);
}
// If argumentsList.length is unreasonably huge, we get an error.
// (This is an implementation limit.)
for (var method of BOTH) {
for (var value of [1e12, 1e240, Infinity]) {
assertThrowsInstanceOf(() => method(count, undefined, {length: value}),
Error);
}
}
// argumentsList.length is converted to an integer.
for (var value of [1.7, "1", {valueOf() { return "1"; }}]) {
args = {
length: value,
"0": "ponies"
};
for (var method of BOTH) {
var result = method(getArgs, undefined, args);
assertEq(result.length, 1);
assertEq(result[0], "ponies");
}
}
// If argumentsList.length is negative or NaN, no arguments are passed.
for (var method of BOTH) {
for (var num of [-1, -0.1, -0, -1e99, -Infinity, NaN]) {
assertEq(method(count, undefined, {length: num}).numArgsReceived,
0);
}
}
// Many arguments can be passed.
var many = 65537;
var args = {length: many, 0: "zero", [many - 1]: "last"};
function testMany(...args) {
"use strict";
for (var i = 0; i < many; i++) {
assertEq(i in args, true);
assertEq(args[i], i === 0 ? "zero" : i === many - 1 ? "last" : undefined);
}
return this;
}
assertEq(Reflect.apply(testMany, "pass", args), "pass");
assertEq(Reflect.construct(testMany, args) instanceof testMany, true);
reportCompare(0, 0);