]>
Lady’s Gitweb - Pisces/blob - function.test.js
1 // SPDX-FileCopyrightText: 2022, 2023, 2025 Lady <https://www.ladys.computer/about/#lady>
2 // SPDX-License-Identifier: MPL-2.0
4 * ⁌ ♓🧩 Piscēs ∷ function.test.js
6 * Copyright © 2022–2023, 2025 Lady [@ Ladys Computer].
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
16 assertNotStrictEquals
,
24 } from "./dev-deps.js";
31 createCallableFunction
,
32 createIllegalConstructor
,
33 createProxyConstructor
,
39 } from "./function.js";
41 describe("bind", () => {
42 it("[[Call]] binds this", () => {
55 it("[[Call]] binds arguments", () => {
59 return [this, ...args
];
63 ).call("failure", "cmfwyp"),
64 ["etaoin", "shrdlu", "cmfwyp"],
68 it("[[Call]] works with any arraylike third argument", () => {
72 return [this, ...args
];
80 ).call("failure", "cmfwyp"),
81 ["etaoin", undefined, "shrdlu", undefined, "cmfwyp"],
85 it("[[Construct]] throws an error", () => {
86 assertThrows(() => new bind(function () {}));
89 describe(".length", () => {
90 it("[[Get]] returns the correct length", () => {
91 assertStrictEquals(bind
.length
, 3);
95 describe(".name", () => {
96 it("[[Get]] returns the correct name", () => {
97 assertStrictEquals(bind
.name
, "bind");
102 describe("call", () => {
103 it("[[Call]] calls with the provided this value", () => {
116 it("[[Call]] calls with the provided arguments", () => {
120 return [this, ...args
];
123 ["shrdlu", "cmfwyp"],
125 ["etaoin", "shrdlu", "cmfwyp"],
129 it("[[Call]] works with any arraylike third argument", () => {
133 return [this, ...args
];
143 ["etaoin", undefined, "shrdlu", undefined, "cmfwyp"],
147 it("[[Construct]] throws an error", () => {
148 assertThrows(() => new call(function () {}, null, []));
151 describe(".length", () => {
152 it("[[Get]] returns the correct length", () => {
153 assertStrictEquals(call
.length
, 3);
157 describe(".name", () => {
158 it("[[Get]] returns the correct name", () => {
159 assertStrictEquals(call
.name
, "call");
164 describe("completesNormally", () => {
165 it("[[Call]] returns true for functions which complete normally", () => {
166 assertStrictEquals(completesNormally(() => {}), true);
169 it("[[Call]] returns false for functions which throw", () => {
171 completesNormally(() => {
178 it("[[Call]] throws when the argument is not callable", () => {
179 assertThrows(() => completesNormally(null));
182 it("[[Call]] throws when the argument is not provided", () => {
183 assertThrows(() => completesNormally());
186 it("[[Construct]] throws an error", () => {
187 assertThrows(() => new completesNormally(function () {}));
190 describe(".length", () => {
191 it("[[Get]] returns the correct length", () => {
192 assertStrictEquals(completesNormally
.length
, 1);
196 describe(".name", () => {
197 it("[[Get]] returns the correct name", () => {
198 assertStrictEquals(completesNormally
.name
, "completesNormally");
203 describe("construct", () => {
204 it("[[Call]] defaults to the constructor as the target", () => {
205 const constructor = class {};
207 Object
.getPrototypeOf(construct(
211 constructor.prototype,
215 it("[[Call]] constructs with the provided new target", () => {
216 const target = function () {};
229 it("[[Call]] constructs with the provided arguments", () => {
233 return [new.target
.value
, ...args
];
235 ["shrdlu", "cmfwyp"],
236 Object
.assign(function () {}, { value: "etaoin" }),
238 ["etaoin", "shrdlu", "cmfwyp"],
242 it("[[Call]] works with any arraylike third argument", () => {
246 return [new.target
.value
, ...args
];
254 Object
.assign(function () {}, { value: "etaoin" }),
256 ["etaoin", undefined, "shrdlu", undefined, "cmfwyp"],
260 it("[[Construct]] throws an error", () => {
261 assertThrows(() => new construct(function () {}, []));
264 describe(".length", () => {
265 it("[[Get]] returns the correct length", () => {
266 assertStrictEquals(construct
.length
, 2);
270 describe(".name", () => {
271 it("[[Get]] returns the correct name", () => {
272 assertStrictEquals(construct
.name
, "construct");
277 describe("createArrowFunction", () => {
278 it("[[Call]] sets this to undefined", () => {
289 it("[[Call]] transfers the provided arguments", () => {
293 return [this, ...args
];
295 ).call("failure", "etaoin", "shrdlu", "cmfwyp"),
296 [undefined, "etaoin", "shrdlu", "cmfwyp"],
300 it("[[Call]] correctly sets the length", () => {
303 function (_a
, _b
, _c
) {},
309 it("[[Call]] correctly sets the name", () => {
312 function etaoin() {},
318 it("[[Call]] allows the length to be overridden", () => {
321 function etaoin() {},
328 it("[[Call]] allows the name to be overridden", () => {
331 function etaoin() {},
338 it("[[Call]] returns an arrow function", () => {
339 assertThrows(() => new (createArrowFunction(function () {}))());
342 it("[[Call]] returns a function with no prototype property", () => {
345 in createArrowFunction(function () {}, { prototype: {} })),
349 it("[[Construct]] throws an error", () => {
350 assertThrows(() => new createArrowFunction(function () {}));
353 describe(".length", () => {
354 it("[[Get]] returns the correct length", () => {
355 assertStrictEquals(createArrowFunction
.length
, 1);
359 describe(".name", () => {
360 it("[[Get]] returns the correct name", () => {
362 createArrowFunction
.name
,
363 "createArrowFunction",
369 describe("createCallableFunction", () => {
370 it("[[Call]] transfers the first argument to this", () => {
372 createCallableFunction(
376 ).call("fail", "pass"),
381 it("[[Call]] transfers the remaining arguments", () => {
383 createCallableFunction(
385 return [this, ...args
];
387 ).call("failure", "etaoin", "shrdlu", "cmfwyp"),
388 ["etaoin", "shrdlu", "cmfwyp"],
392 it("[[Call]] correctly sets the length", () => {
394 createCallableFunction(
395 function (_a
, _b
, _c
) {},
401 it("[[Call]] correctly sets the name", () => {
403 createCallableFunction(
404 function etaoin() {},
410 it("[[Call]] allows the length to be overridden", () => {
412 createCallableFunction(
413 function etaoin() {},
420 it("[[Call]] allows the name to be overridden", () => {
422 createCallableFunction(
423 function etaoin() {},
430 it("[[Call]] returns an arrow function", () => {
431 assertThrows(() => new (createCallableFunction(function () {}))());
434 it("[[Call]] returns a function with no prototype property", () => {
437 in createCallableFunction(function () {}, { prototype: {} })),
441 it("[[Construct]] throws an error", () => {
442 assertThrows(() => new createCallableFunction(function () {}));
445 describe(".length", () => {
446 it("[[Get]] returns the correct length", () => {
447 assertStrictEquals(createCallableFunction
.length
, 1);
451 describe(".name", () => {
452 it("[[Get]] returns the correct name", () => {
454 createCallableFunction
.name
,
455 "createCallableFunction",
461 describe("createIllegalConstructor", () => {
462 it("[[Call]] returns a constructor", () => {
463 assert(isConstructor(createIllegalConstructor()));
466 it("[[Call]] works as expected when provided with no arguments", () => {
467 const constructor = createIllegalConstructor();
469 Object
.getPrototypeOf(constructor),
473 Object
.getPrototypeOf(constructor.prototype),
477 constructor.prototype,
478 Object
.create(Object
.prototype, {
488 !Object
.getOwnPropertyDescriptor(constructor, "prototype")
491 assertStrictEquals(constructor.name
, "");
494 it("[[Call]] returns a correctly‐formed constructor when provided one argument", () => {
495 const constructorPrototype
= Object
.create(null, {
496 name: { value: "etaoin" },
497 length: { value: "3" },
498 prototype: { value: {} },
500 const constructor = createIllegalConstructor(
501 Object
.create(constructorPrototype
),
503 assert(isConstructor(constructor));
505 Object
.getPrototypeOf(constructor),
506 constructorPrototype
,
508 assert(Object
.hasOwn(constructor, "prototype"));
510 constructor.prototype,
511 constructorPrototype
.prototype,
514 !Object
.getOwnPropertyDescriptor(constructor, "prototype")
517 assertStrictEquals(constructor.name
, "etaoin");
518 assertStrictEquals(constructor.length
, 3);
521 it("[[Call]] allows the length to be overridden", () => {
523 createIllegalConstructor(
524 function etaoin() {},
531 it("[[Call]] allows the name to be overridden", () => {
533 createIllegalConstructor(
534 function etaoin() {},
541 it("[[Call]] allows the prototype to be overridden", () => {
544 createIllegalConstructor(
545 function etaoin() {},
552 it("[[Construct]] throws an error", () => {
553 assertThrows(() => new createIllegalConstructor(function () {}));
556 describe(".length", () => {
557 it("[[Get]] returns the correct length", () => {
558 assertStrictEquals(createIllegalConstructor
.length
, 1);
562 describe(".name", () => {
563 it("[[Get]] returns the correct name", () => {
565 createIllegalConstructor
.name
,
566 "createIllegalConstructor",
571 describe("~", () => {
572 it("[[Call]] throws an error", () => {
574 createIllegalConstructor(function () {})();
578 it("[[Construct]] throws an error", () => {
580 createIllegalConstructor(function () {})();
586 describe("createProxyConstructor", () => {
587 it("[[Call]] returns a constructor", () => {
588 assert(isConstructor(createProxyConstructor({})));
591 it("[[Call]] throws with no arguments", () => {
592 assertThrows(() => createProxyConstructor());
595 it("[[Call]] throws if the second argument is not a constructor or undefined", () => {
596 assertThrows(() => createProxyConstructor({}, () => {}));
599 it("[[Call]] throws if the third argument is not a constructor or undefined", () => {
601 createProxyConstructor({}, undefined, () => {})
605 it("[[Call]] creates a proper proxy constructor", () => {
606 const constructorPrototype
= function etaoin(_
) {};
607 const constructor = class Constructor
608 extends constructorPrototype
{
609 constructor(_1
, _2
, _3
) {}
611 const proxyConstructor
= createProxyConstructor(
615 assert(isConstructor(proxyConstructor
));
617 Object
.getPrototypeOf(proxyConstructor
),
620 assertStrictEquals(proxyConstructor
.prototype, undefined);
621 assertStrictEquals(proxyConstructor
.name
, "ConstructorProxy");
622 assertStrictEquals(proxyConstructor
.length
, 3);
625 it("[[Call]] allows the length to be overridden", () => {
627 createProxyConstructor({}, undefined, undefined, {
634 it("[[Call]] allows the name to be overridden", () => {
636 createProxyConstructor({}, function etaoin() {}, undefined, {
643 it("[[Call]] does not allow the prototype to be overridden", () => {
645 createProxyConstructor({}, undefined, undefined, {
652 it("[[Construct]] throws an error", () => {
653 assertThrows(() => new createProxyConstructor({}));
656 describe(".length", () => {
657 it("[[Get]] returns the correct length", () => {
658 assertStrictEquals(createProxyConstructor
.length
, 2);
662 describe(".name", () => {
663 it("[[Get]] returns the correct name", () => {
665 createProxyConstructor
.name
,
666 "createProxyConstructor",
671 describe("~", () => {
672 it("[[Call]] throws an error", () => {
674 createProxyConstructor({})();
678 it("[[Construct]] produces a proxy", () => {
680 const proxyConstructor
= createProxyConstructor({
681 get(O
, P
, Receiver
) {
682 if (P
=== "etaoin") {
683 return Reflect
.get(O
, P
, Receiver
) ?? "success";
685 return Reflect
.get(O
, P
, Receiver
);
691 const proxy
= new proxyConstructor();
692 assertStrictEquals(proxy
.etaoin
, "success");
693 obj
.etaoin
= "shrdlu";
694 assertStrictEquals(proxy
.etaoin
, "shrdlu");
697 it("[[Construct]] receives the expected new.target", () => {
698 const constructor = function Constructor() {
699 return { name: new.target
.name
};
702 new (createProxyConstructor({}, constructor))().name
,
706 new (createProxyConstructor(
709 function NewTarget() {},
716 describe("~is[[.name]]", () => {
717 it("[[GetOwnProperty]] defines the appropriate method", () => {
718 assertNotStrictEquals(
719 Object
.getOwnPropertyDescriptor(
720 createProxyConstructor({}),
725 assertNotStrictEquals(
726 Object
.getOwnPropertyDescriptor(
727 createProxyConstructor({}, function Base() {}),
732 assertNotStrictEquals(
733 Object
.getOwnPropertyDescriptor(
734 createProxyConstructor({}, function Bad() {}, undefined, {
743 it("[[GetOwnProperty]] has the correct descriptor", () => {
744 const proxyConstructor
= createProxyConstructor({});
746 Object
.getOwnPropertyDescriptor(
753 value: proxyConstructor
.isProxy
,
759 it("[[Call]] returns true for created proxies", () => {
760 const proxyConstructor
= createProxyConstructor({});
761 const proxy
= new proxyConstructor();
763 proxyConstructor
.isProxy(proxy
),
768 it("[[Call]] returns false for nonproxies", () => {
769 const constructor = function Base() {};
770 const proxyConstructor
= createProxyConstructor({}, constructor);
772 proxyConstructor
.isBaseProxy(new constructor()),
777 it("[[Construct]] throws an error", () => {
778 const proxyConstructor
= createProxyConstructor({});
779 assertThrows(() => new proxyConstructor
.isProxy({}));
782 describe(".length", () => {
783 it("[[Get]] returns the correct length", () => {
784 const proxyConstructor
= createProxyConstructor({});
785 assertStrictEquals(proxyConstructor
.isProxy
.length
, 1);
789 describe(".name", () => {
790 it("[[Get]] returns the correct name", () => {
791 const proxyConstructor
= createProxyConstructor({});
792 assertStrictEquals(proxyConstructor
.isProxy
.name
, "isProxy");
793 const otherProxyConstructor
= createProxyConstructor(
798 otherProxyConstructor
.isBaseProxy
.name
,
805 describe("~length", () => {
806 it("[[GetOwnProperty]] has the correct descriptor", () => {
808 Object
.getOwnPropertyDescriptor(
809 createProxyConstructor({}),
822 describe("~name", () => {
823 it("[[GetOwnProperty]] has the correct descriptor", () => {
825 Object
.getOwnPropertyDescriptor(
826 createProxyConstructor({}),
839 describe("~prototype", () => {
840 it("[[GetOwnProperty]] has the correct descriptor", () => {
842 Object
.getOwnPropertyDescriptor(
843 createProxyConstructor({}),
856 describe("~revocable", () => {
857 it("[[Call]] produces a revocable proxy", () => {
859 const proxyConstructor
= createProxyConstructor({
860 get(O
, P
, Receiver
) {
861 if (P
=== "etaoin") {
862 return Reflect
.get(O
, P
, Receiver
) ?? "success";
864 return Reflect
.get(O
, P
, Receiver
);
870 const { proxy
, revoke
} = proxyConstructor
.revocable();
871 assertStrictEquals(proxy
.etaoin
, "success");
872 obj
.etaoin
= "shrdlu";
873 assertStrictEquals(proxy
.etaoin
, "shrdlu");
875 assertThrows(() => proxy
.etaoin
);
878 it("[[Call]] receives the expected new.target", () => {
879 const constructor = function Constructor() {
880 return { name: new.target
.name
};
883 createProxyConstructor({}, constructor).revocable().proxy
.name
,
887 createProxyConstructor(
890 function NewTarget() {},
891 ).revocable().proxy
.name
,
896 it("[[Construct]] throws an error", () => {
897 assertThrows(() => new (createProxyConstructor({})).revocable());
900 it("[[GetOwnProperty]] has the correct descriptor", () => {
901 const proxyConstructor
= createProxyConstructor({});
903 Object
.getOwnPropertyDescriptor(proxyConstructor
, "revocable"),
907 value: proxyConstructor
.revocable
,
915 describe("identity", () => {
916 it("[[Call]] returns what it is given", () => {
918 assertStrictEquals(identity(value
), value
);
921 it("[[Construct]] is constructable", () => {
923 assertStrictEquals(new identity(value
), value
);
926 it("[[Construct]] is subclassable", () => {
928 assertStrictEquals(new class extends identity
{}(value
), value
);
931 describe(".length", () => {
932 it("[[Get]] returns the correct length", () => {
933 assertStrictEquals(identity
.length
, 1);
937 describe(".name", () => {
938 it("[[Get]] returns the correct name", () => {
939 assertStrictEquals(identity
.name
, "identity");
944 describe("isCallable", () => {
945 it("[[Call]] returns true for ordinary functions", () => {
946 assertStrictEquals(isCallable(function () {}), true);
949 it("[[Call]] returns true for arrow functions", () => {
950 assertStrictEquals(isCallable(() => {}), true);
953 it("[[Call]] returns true for generator functions", () => {
954 assertStrictEquals(isCallable(function* () {}), true);
957 it("[[Call]] returns true for classes", () => {
958 assertStrictEquals(isCallable(class {}), true);
961 it("[[Call]] returns true for builtin functions", () => {
962 assertStrictEquals(isCallable(Math
.ceil
), true);
965 it("[[Call]] returns true for getters", () => {
968 Object
.getOwnPropertyDescriptor({
978 it("[[Call]] returns true for setters", () => {
981 Object
.getOwnPropertyDescriptor({
991 it("[[Call]] returns false for null", () => {
992 assertStrictEquals(isCallable(null), false);
995 it("[[Call]] returns false for objects", () => {
996 assertStrictEquals(isCallable({}), false);
999 it("[[Construct]] throws an error", () => {
1000 assertThrows(() => new isCallable(function () {}));
1003 describe(".length", () => {
1004 it("[[Get]] returns the correct length", () => {
1005 assertStrictEquals(isCallable
.length
, 1);
1009 describe(".name", () => {
1010 it("[[Get]] returns the correct name", () => {
1011 assertStrictEquals(isCallable
.name
, "isCallable");
1016 describe("isConstructor", () => {
1017 it("[[Call]] returns true for ordinary functions", () => {
1018 assertStrictEquals(isConstructor(function () {}), true);
1021 it("[[Call]] returns false for arrow functions", () => {
1022 assertStrictEquals(isConstructor(() => {}), false);
1025 it("[[Call]] returns false for generator functions", () => {
1026 assertStrictEquals(isConstructor(function* () {}), false);
1029 it("[[Call]] returns true for classes", () => {
1030 assertStrictEquals(isConstructor(class {}), true);
1033 it("[[Call]] returns false for builtin functions", () => {
1034 assertStrictEquals(isConstructor(Math
.ceil
), false);
1037 it("[[Call]] returns false for getters", () => {
1040 Object
.getOwnPropertyDescriptor({
1050 it("[[Call]] returns false for setters", () => {
1053 Object
.getOwnPropertyDescriptor({
1063 it("[[Call]] returns false for null", () => {
1064 assertStrictEquals(isConstructor(null), false);
1067 it("[[Call]] returns false for objects", () => {
1068 assertStrictEquals(isConstructor({}), false);
1071 it("[[Construct]] throws an error", () => {
1072 assertThrows(() => new isConstructor(function () {}));
1075 describe(".length", () => {
1076 it("[[Get]] returns the correct length", () => {
1077 assertStrictEquals(isConstructor
.length
, 1);
1081 describe(".name", () => {
1082 it("[[Get]] returns the correct name", () => {
1083 assertStrictEquals(isConstructor
.name
, "isConstructor");
1088 describe("maybe", () => {
1089 it("[[Call]] calls if not nullish", () => {
1090 const wrapper
= spy(() => "success");
1091 assertStrictEquals(maybe(0, wrapper
), "success");
1092 assertSpyCalls(wrapper
, 1);
1093 assertSpyCall(wrapper
, 0, {
1096 returned: "success",
1100 it("[[Call]] does not call if nullish", () => {
1101 const wrapper
= spy(() => "success");
1102 assertStrictEquals(maybe(null, wrapper
), null);
1103 assertStrictEquals(maybe(undefined, wrapper
), undefined);
1104 assertSpyCalls(wrapper
, 0);
1107 it("[[Construct]] throws an error", () => {
1108 assertThrows(() => new maybe(true, ($) => $));
1111 describe(".length", () => {
1112 it("[[Get]] returns the correct length", () => {
1113 assertStrictEquals(maybe
.length
, 2);
1117 describe(".name", () => {
1118 it("[[Get]] returns the correct name", () => {
1119 assertStrictEquals(maybe
.name
, "maybe");
1124 describe("ordinaryHasInstance", () => {
1125 it("[[Call]] walks the prototype chain", () => {
1126 const constructor = class {
1127 [Symbol
.hasInstance
]() {
1132 ordinaryHasInstance(
1134 new class extends constructor {}(),
1140 it("[[Construct]] throws an error", () => {
1141 assertThrows(() => new ordinaryHasInstance(function () {}, {}));
1144 describe(".length", () => {
1145 it("[[Get]] returns the correct length", () => {
1146 assertStrictEquals(ordinaryHasInstance
.length
, 2);
1150 describe(".name", () => {
1151 it("[[Get]] returns the correct name", () => {
1153 ordinaryHasInstance
.name
,
1154 "ordinaryHasInstance",
This page took 0.930036 seconds and 5 git commands to generate.