summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/Reflect/apply.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/tests/non262/Reflect/apply.js')
-rw-r--r--js/src/tests/non262/Reflect/apply.js130
1 files changed, 130 insertions, 0 deletions
diff --git a/js/src/tests/non262/Reflect/apply.js b/js/src/tests/non262/Reflect/apply.js
new file mode 100644
index 0000000000..fbd9db2a4b
--- /dev/null
+++ b/js/src/tests/non262/Reflect/apply.js
@@ -0,0 +1,130 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/ */
+
+// Reflect.apply calls functions.
+assertEq(Reflect.apply(Math.floor, undefined, [1.75]), 1);
+
+// Reflect.apply requires a target object that's callable.
+var nonCallable = [{}, [], (class clsX { constructor() {} })];
+for (var value of nonCallable) {
+ assertThrowsInstanceOf(() => Reflect.apply(nonCallable), TypeError);
+}
+
+// When target is not callable, Reflect.apply does not try to get argumentList.length before throwing.
+var hits = 0;
+var bogusArgumentList = {get length() { hit++; throw "FAIL";}};
+assertThrowsInstanceOf(() => Reflect.apply({callable: false}, null, bogusArgumentList),
+ TypeError);
+assertEq(hits, 0);
+
+// Reflect.apply works on a range of different callable objects.
+// Builtin functions (we also tested Math.floor above):
+assertEq(Reflect.apply(String.fromCharCode,
+ undefined,
+ [104, 101, 108, 108, 111]),
+ "hello");
+
+// Builtin methods:
+assertEq(Reflect.apply(RegExp.prototype.exec,
+ /ab/,
+ ["confabulation"]).index,
+ 4);
+
+// Builtin methods of primitive objects:
+assertEq(Reflect.apply("".charAt,
+ "ponies",
+ [3]),
+ "i");
+
+// Bound functions:
+assertEq(Reflect.apply(function () { return this; }.bind(Math),
+ Function,
+ []),
+ Math);
+assertEq(Reflect.apply(Array.prototype.concat.bind([1, 2], [3]),
+ [4, 5],
+ [[6, 7, 8]]).join(),
+ "1,2,3,6,7,8");
+
+// Generator functions:
+function* g(arg) { yield "pass" + arg; }
+assertEq(Reflect.apply(g,
+ undefined,
+ ["word"]).next().value,
+ "password");
+
+// Proxies:
+function f() { return 13; }
+assertEq(Reflect.apply(new Proxy(f, {}),
+ undefined,
+ []),
+ 13);
+
+// Cross-compartment wrappers:
+var gw = newGlobal();
+assertEq(Reflect.apply(gw.parseInt,
+ undefined,
+ ["45"]),
+ 45);
+assertEq(Reflect.apply(gw.Symbol.for,
+ undefined,
+ ["moon"]),
+ Symbol.for("moon"));
+
+gw.eval("function q() { return q; }");
+assertEq(Reflect.apply(gw.q,
+ undefined,
+ []),
+ gw.q);
+
+
+// Exceptions are propagated.
+var nope = new Error("nope");
+function fail() {
+ throw nope;
+}
+assertThrowsValue(() => Reflect.apply(fail, undefined, []),
+ nope);
+
+// Exceptions thrown by cross-compartment wrappers are re-wrapped for the
+// calling compartment.
+var gxw = gw.eval("var x = new Error('x'); x");
+gw.eval("function fail() { throw x; }");
+assertThrowsValue(() => Reflect.apply(gw.fail, undefined, []),
+ gxw);
+
+// The thisArgument is passed to the target function as the 'this' value.
+var obj = {};
+hits = 0;
+assertEq(Reflect.apply(function () { hits++; assertEq(this, obj); },
+ obj,
+ []),
+ undefined);
+assertEq(hits, 1);
+
+// Primitive values can be thisArgument.
+function strictThis() { "use strict"; return this; }
+for (var value of [null, undefined, 0, -0, NaN, Symbol("moon")]) {
+ assertEq(Reflect.apply(strictThis, value, []),
+ value);
+}
+
+// If the target is a non-strict function and thisArgument is a primitive value
+// other than null or undefined, then thisArgument is converted to a wrapper
+// object.
+var testValues = [true, 1e9, "ok", Symbol("ok")];
+function nonStrictThis(expected) {
+ assertEq(typeof this, "object");
+ assertEq(Reflect.apply(Object.prototype.toString, this, []).toLowerCase(), expected);
+ return "ok";
+}
+for (var value of testValues) {
+ assertEq(Reflect.apply(nonStrictThis,
+ value,
+ ["[object " + typeof value + "]"]),
+ "ok");
+}
+
+// For more Reflect.apply tests, see target.js and argumentsList.js.
+
+reportCompare(0, 0);