]>
Lady’s Gitweb - Pisces/blob - function.test.js
1 // ♓🌟 Piscēs ∷ function.test.js
2 // ====================================================================
4 // Copyright © 2022–2023 Lady [@ Lady’s Computer].
6 // This Source Code Form is subject to the terms of the Mozilla Public
7 // License, v. 2.0. If a copy of the MPL was not distributed with this
8 // file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
13 assertNotStrictEquals
,
21 } from "./dev-deps.js";
28 createCallableFunction
,
29 createIllegalConstructor
,
30 createProxyConstructor
,
36 } from "./function.js";
38 describe("bind", () => {
39 it("[[Call]] binds this", () => {
52 it("[[Call]] binds arguments", () => {
56 return [this, ...args
];
60 ).call("failure", "cmfwyp"),
61 ["etaoin", "shrdlu", "cmfwyp"],
65 it("[[Call]] works with any arraylike third argument", () => {
69 return [this, ...args
];
77 ).call("failure", "cmfwyp"),
78 ["etaoin", undefined, "shrdlu", undefined, "cmfwyp"],
82 it("[[Construct]] throws an error", () => {
83 assertThrows(() => new bind(function () {}));
86 describe(".length", () => {
87 it("[[Get]] returns the correct length", () => {
88 assertStrictEquals(bind
.length
, 3);
92 describe(".name", () => {
93 it("[[Get]] returns the correct name", () => {
94 assertStrictEquals(bind
.name
, "bind");
99 describe("call", () => {
100 it("[[Call]] calls with the provided this value", () => {
113 it("[[Call]] calls with the provided arguments", () => {
117 return [this, ...args
];
120 ["shrdlu", "cmfwyp"],
122 ["etaoin", "shrdlu", "cmfwyp"],
126 it("[[Call]] works with any arraylike third argument", () => {
130 return [this, ...args
];
140 ["etaoin", undefined, "shrdlu", undefined, "cmfwyp"],
144 it("[[Construct]] throws an error", () => {
145 assertThrows(() => new call(function () {}, null, []));
148 describe(".length", () => {
149 it("[[Get]] returns the correct length", () => {
150 assertStrictEquals(call
.length
, 3);
154 describe(".name", () => {
155 it("[[Get]] returns the correct name", () => {
156 assertStrictEquals(call
.name
, "call");
161 describe("completesNormally", () => {
162 it("[[Call]] returns true for functions which complete normally", () => {
163 assertStrictEquals(completesNormally(() => {}), true);
166 it("[[Call]] returns false for functions which throw", () => {
168 completesNormally(() => {
175 it("[[Call]] throws when the argument is not callable", () => {
176 assertThrows(() => completesNormally(null));
179 it("[[Call]] throws when the argument is not provided", () => {
180 assertThrows(() => completesNormally());
183 it("[[Construct]] throws an error", () => {
184 assertThrows(() => new completesNormally(function () {}));
187 describe(".length", () => {
188 it("[[Get]] returns the correct length", () => {
189 assertStrictEquals(completesNormally
.length
, 1);
193 describe(".name", () => {
194 it("[[Get]] returns the correct name", () => {
195 assertStrictEquals(completesNormally
.name
, "completesNormally");
200 describe("construct", () => {
201 it("[[Call]] defaults to the constructor as the target", () => {
202 const constructor = class {};
204 Object
.getPrototypeOf(construct(
208 constructor.prototype,
212 it("[[Call]] constructs with the provided new target", () => {
213 const target = function () {};
226 it("[[Call]] constructs with the provided arguments", () => {
230 return [new.target
.value
, ...args
];
232 ["shrdlu", "cmfwyp"],
233 Object
.assign(function () {}, { value
: "etaoin" }),
235 ["etaoin", "shrdlu", "cmfwyp"],
239 it("[[Call]] works with any arraylike third argument", () => {
243 return [new.target
.value
, ...args
];
251 Object
.assign(function () {}, { value
: "etaoin" }),
253 ["etaoin", undefined, "shrdlu", undefined, "cmfwyp"],
257 it("[[Construct]] throws an error", () => {
258 assertThrows(() => new construct(function () {}, []));
261 describe(".length", () => {
262 it("[[Get]] returns the correct length", () => {
263 assertStrictEquals(construct
.length
, 2);
267 describe(".name", () => {
268 it("[[Get]] returns the correct name", () => {
269 assertStrictEquals(construct
.name
, "construct");
274 describe("createArrowFunction", () => {
275 it("[[Call]] sets this to undefined", () => {
286 it("[[Call]] transfers the provided arguments", () => {
290 return [this, ...args
];
292 ).call("failure", "etaoin", "shrdlu", "cmfwyp"),
293 [undefined, "etaoin", "shrdlu", "cmfwyp"],
297 it("[[Call]] correctly sets the length", () => {
300 function (_a
, _b
, _c
) {},
306 it("[[Call]] correctly sets the name", () => {
309 function etaoin() {},
315 it("[[Call]] allows the length to be overridden", () => {
318 function etaoin() {},
325 it("[[Call]] allows the name to be overridden", () => {
328 function etaoin() {},
335 it("[[Call]] returns an arrow function", () => {
336 assertThrows(() => new (createArrowFunction(function () {}))());
339 it("[[Call]] returns a function with no prototype property", () => {
342 createArrowFunction(function () {}, { prototype: {} })),
346 it("[[Construct]] throws an error", () => {
347 assertThrows(() => new createArrowFunction(function () {}));
350 describe(".length", () => {
351 it("[[Get]] returns the correct length", () => {
352 assertStrictEquals(createArrowFunction
.length
, 1);
356 describe(".name", () => {
357 it("[[Get]] returns the correct name", () => {
359 createArrowFunction
.name
,
360 "createArrowFunction",
366 describe("createCallableFunction", () => {
367 it("[[Call]] transfers the first argument to this", () => {
369 createCallableFunction(
373 ).call("fail", "pass"),
378 it("[[Call]] transfers the remaining arguments", () => {
380 createCallableFunction(
382 return [this, ...args
];
384 ).call("failure", "etaoin", "shrdlu", "cmfwyp"),
385 ["etaoin", "shrdlu", "cmfwyp"],
389 it("[[Call]] correctly sets the length", () => {
391 createCallableFunction(
392 function (_a
, _b
, _c
) {},
398 it("[[Call]] correctly sets the name", () => {
400 createCallableFunction(
401 function etaoin() {},
407 it("[[Call]] allows the length to be overridden", () => {
409 createCallableFunction(
410 function etaoin() {},
417 it("[[Call]] allows the name to be overridden", () => {
419 createCallableFunction(
420 function etaoin() {},
427 it("[[Call]] returns an arrow function", () => {
428 assertThrows(() => new (createCallableFunction(function () {}))());
431 it("[[Call]] returns a function with no prototype property", () => {
434 createCallableFunction(function () {}, { prototype: {} })),
438 it("[[Construct]] throws an error", () => {
439 assertThrows(() => new createCallableFunction(function () {}));
442 describe(".length", () => {
443 it("[[Get]] returns the correct length", () => {
444 assertStrictEquals(createCallableFunction
.length
, 1);
448 describe(".name", () => {
449 it("[[Get]] returns the correct name", () => {
451 createCallableFunction
.name
,
452 "createCallableFunction",
458 describe("createIllegalConstructor", () => {
459 it("[[Call]] returns a constructor", () => {
460 assert(isConstructor(createIllegalConstructor()));
463 it("[[Call]] works as expected when provided with no arguments", () => {
464 const constructor = createIllegalConstructor();
466 Object
.getPrototypeOf(constructor),
470 Object
.getPrototypeOf(constructor.prototype),
474 constructor.prototype,
475 Object
.create(Object
.prototype, {
485 !Object
.getOwnPropertyDescriptor(constructor, "prototype")
488 assertStrictEquals(constructor.name
, "");
491 it("[[Call]] returns a correctly‐formed constructor when provided one argument", () => {
492 const constructorPrototype
= Object
.create(null, {
493 name
: { value
: "etaoin" },
494 length
: { value
: "3" },
495 prototype: { value
: {} },
497 const constructor = createIllegalConstructor(
498 Object
.create(constructorPrototype
),
500 assert(isConstructor(constructor));
502 Object
.getPrototypeOf(constructor),
503 constructorPrototype
,
505 assert(Object
.hasOwn(constructor, "prototype"));
507 constructor.prototype,
508 constructorPrototype
.prototype,
511 !Object
.getOwnPropertyDescriptor(constructor, "prototype")
514 assertStrictEquals(constructor.name
, "etaoin");
515 assertStrictEquals(constructor.length
, 3);
518 it("[[Call]] allows the length to be overridden", () => {
520 createIllegalConstructor(
521 function etaoin() {},
528 it("[[Call]] allows the name to be overridden", () => {
530 createIllegalConstructor(
531 function etaoin() {},
538 it("[[Call]] allows the prototype to be overridden", () => {
541 createIllegalConstructor(
542 function etaoin() {},
549 it("[[Construct]] throws an error", () => {
550 assertThrows(() => new createIllegalConstructor(function () {}));
553 describe(".length", () => {
554 it("[[Get]] returns the correct length", () => {
555 assertStrictEquals(createIllegalConstructor
.length
, 1);
559 describe(".name", () => {
560 it("[[Get]] returns the correct name", () => {
562 createIllegalConstructor
.name
,
563 "createIllegalConstructor",
568 describe("~", () => {
569 it("[[Call]] throws an error", () => {
571 createIllegalConstructor(function () {})();
575 it("[[Construct]] throws an error", () => {
577 createIllegalConstructor(function () {})();
583 describe("createProxyConstructor", () => {
584 it("[[Call]] returns a constructor", () => {
585 assert(isConstructor(createProxyConstructor({})));
588 it("[[Call]] throws with no arguments", () => {
589 assertThrows(() => createProxyConstructor());
592 it("[[Call]] throws if the second argument is not a constructor or undefined", () => {
593 assertThrows(() => createProxyConstructor({}, () => {}));
596 it("[[Call]] throws if the third argument is not a constructor or undefined", () => {
598 createProxyConstructor({}, undefined, () => {})
602 it("[[Call]] creates a proper proxy constructor", () => {
603 const constructorPrototype
= function etaoin(_
) {};
604 const constructor = class Constructor
605 extends constructorPrototype
{
606 constructor(_1
, _2
, _3
) {}
608 const proxyConstructor
= createProxyConstructor(
612 assert(isConstructor(proxyConstructor
));
614 Object
.getPrototypeOf(proxyConstructor
),
617 assertStrictEquals(proxyConstructor
.prototype, undefined);
618 assertStrictEquals(proxyConstructor
.name
, "ConstructorProxy");
619 assertStrictEquals(proxyConstructor
.length
, 3);
622 it("[[Call]] allows the length to be overridden", () => {
624 createProxyConstructor({}, undefined, undefined, {
631 it("[[Call]] allows the name to be overridden", () => {
633 createProxyConstructor({}, function etaoin() {}, undefined, {
640 it("[[Call]] does not allow the prototype to be overridden", () => {
642 createProxyConstructor({}, undefined, undefined, {
649 it("[[Construct]] throws an error", () => {
650 assertThrows(() => new createProxyConstructor({}));
653 describe(".length", () => {
654 it("[[Get]] returns the correct length", () => {
655 assertStrictEquals(createProxyConstructor
.length
, 2);
659 describe(".name", () => {
660 it("[[Get]] returns the correct name", () => {
662 createProxyConstructor
.name
,
663 "createProxyConstructor",
668 describe("~", () => {
669 it("[[Call]] throws an error", () => {
671 createProxyConstructor({})();
675 it("[[Construct]] produces a proxy", () => {
677 const proxyConstructor
= createProxyConstructor({
678 get(O
, P
, Receiver
) {
679 if (P
=== "etaoin") {
680 return Reflect
.get(O
, P
, Receiver
) ?? "success";
682 return Reflect
.get(O
, P
, Receiver
);
688 const proxy
= new proxyConstructor();
689 assertStrictEquals(proxy
.etaoin
, "success");
690 obj
.etaoin
= "shrdlu";
691 assertStrictEquals(proxy
.etaoin
, "shrdlu");
694 it("[[Construct]] receives the expected new.target", () => {
695 const constructor = function Constructor() {
696 return { name
: new.target
.name
};
699 new (createProxyConstructor({}, constructor))().name
,
703 new (createProxyConstructor(
706 function NewTarget() {},
713 describe("~is[[.name]]", () => {
714 it("[[GetOwnProperty]] defines the appropriate method", () => {
715 assertNotStrictEquals(
716 Object
.getOwnPropertyDescriptor(
717 createProxyConstructor({}),
722 assertNotStrictEquals(
723 Object
.getOwnPropertyDescriptor(
724 createProxyConstructor({}, function Base() {}),
729 assertNotStrictEquals(
730 Object
.getOwnPropertyDescriptor(
731 createProxyConstructor({}, function Bad() {}, undefined, {
740 it("[[GetOwnProperty]] has the correct descriptor", () => {
741 const proxyConstructor
= createProxyConstructor({});
743 Object
.getOwnPropertyDescriptor(
750 value
: proxyConstructor
.isProxy
,
756 it("[[Call]] returns true for created proxies", () => {
757 const proxyConstructor
= createProxyConstructor({});
758 const proxy
= new proxyConstructor();
760 proxyConstructor
.isProxy(proxy
),
765 it("[[Call]] returns false for nonproxies", () => {
766 const constructor = function Base() {};
767 const proxyConstructor
= createProxyConstructor({}, constructor);
769 proxyConstructor
.isBaseProxy(new constructor()),
774 it("[[Construct]] throws an error", () => {
775 const proxyConstructor
= createProxyConstructor({});
776 assertThrows(() => new proxyConstructor
.isProxy({}));
779 describe(".length", () => {
780 it("[[Get]] returns the correct length", () => {
781 const proxyConstructor
= createProxyConstructor({});
782 assertStrictEquals(proxyConstructor
.isProxy
.length
, 1);
786 describe(".name", () => {
787 it("[[Get]] returns the correct name", () => {
788 const proxyConstructor
= createProxyConstructor({});
789 assertStrictEquals(proxyConstructor
.isProxy
.name
, "isProxy");
790 const otherProxyConstructor
= createProxyConstructor(
795 otherProxyConstructor
.isBaseProxy
.name
,
802 describe("~length", () => {
803 it("[[GetOwnProperty]] has the correct descriptor", () => {
805 Object
.getOwnPropertyDescriptor(
806 createProxyConstructor({}),
819 describe("~name", () => {
820 it("[[GetOwnProperty]] has the correct descriptor", () => {
822 Object
.getOwnPropertyDescriptor(
823 createProxyConstructor({}),
836 describe("~prototype", () => {
837 it("[[GetOwnProperty]] has the correct descriptor", () => {
839 Object
.getOwnPropertyDescriptor(
840 createProxyConstructor({}),
853 describe("~revocable", () => {
854 it("[[Call]] produces a revocable proxy", () => {
856 const proxyConstructor
= createProxyConstructor({
857 get(O
, P
, Receiver
) {
858 if (P
=== "etaoin") {
859 return Reflect
.get(O
, P
, Receiver
) ?? "success";
861 return Reflect
.get(O
, P
, Receiver
);
867 const { proxy
, revoke
} = proxyConstructor
.revocable();
868 assertStrictEquals(proxy
.etaoin
, "success");
869 obj
.etaoin
= "shrdlu";
870 assertStrictEquals(proxy
.etaoin
, "shrdlu");
872 assertThrows(() => proxy
.etaoin
);
875 it("[[Call]] receives the expected new.target", () => {
876 const constructor = function Constructor() {
877 return { name
: new.target
.name
};
880 createProxyConstructor({}, constructor).revocable().proxy
.name
,
884 createProxyConstructor(
887 function NewTarget() {},
888 ).revocable().proxy
.name
,
893 it("[[Construct]] throws an error", () => {
894 assertThrows(() => new (createProxyConstructor({})).revocable());
897 it("[[GetOwnProperty]] has the correct descriptor", () => {
898 const proxyConstructor
= createProxyConstructor({});
900 Object
.getOwnPropertyDescriptor(proxyConstructor
, "revocable"),
904 value
: proxyConstructor
.revocable
,
912 describe("identity", () => {
913 it("[[Call]] returns what it is given", () => {
915 assertStrictEquals(identity(value
), value
);
918 it("[[Construct]] is constructable", () => {
920 assertStrictEquals(new identity(value
), value
);
923 it("[[Construct]] is subclassable", () => {
925 assertStrictEquals(new class extends identity
{}(value
), value
);
928 describe(".length", () => {
929 it("[[Get]] returns the correct length", () => {
930 assertStrictEquals(identity
.length
, 1);
934 describe(".name", () => {
935 it("[[Get]] returns the correct name", () => {
936 assertStrictEquals(identity
.name
, "identity");
941 describe("isCallable", () => {
942 it("[[Call]] returns true for ordinary functions", () => {
943 assertStrictEquals(isCallable(function () {}), true);
946 it("[[Call]] returns true for arrow functions", () => {
947 assertStrictEquals(isCallable(() => {}), true);
950 it("[[Call]] returns true for generator functions", () => {
951 assertStrictEquals(isCallable(function* () {}), true);
954 it("[[Call]] returns true for classes", () => {
955 assertStrictEquals(isCallable(class {}), true);
958 it("[[Call]] returns true for builtin functions", () => {
959 assertStrictEquals(isCallable(Math
.ceil
), true);
962 it("[[Call]] returns true for getters", () => {
965 Object
.getOwnPropertyDescriptor({
975 it("[[Call]] returns true for setters", () => {
978 Object
.getOwnPropertyDescriptor({
988 it("[[Call]] returns false for null", () => {
989 assertStrictEquals(isCallable(null), false);
992 it("[[Call]] returns false for objects", () => {
993 assertStrictEquals(isCallable({}), false);
996 it("[[Construct]] throws an error", () => {
997 assertThrows(() => new isCallable(function () {}));
1000 describe(".length", () => {
1001 it("[[Get]] returns the correct length", () => {
1002 assertStrictEquals(isCallable
.length
, 1);
1006 describe(".name", () => {
1007 it("[[Get]] returns the correct name", () => {
1008 assertStrictEquals(isCallable
.name
, "isCallable");
1013 describe("isConstructor", () => {
1014 it("[[Call]] returns true for ordinary functions", () => {
1015 assertStrictEquals(isConstructor(function () {}), true);
1018 it("[[Call]] returns false for arrow functions", () => {
1019 assertStrictEquals(isConstructor(() => {}), false);
1022 it("[[Call]] returns false for generator functions", () => {
1023 assertStrictEquals(isConstructor(function* () {}), false);
1026 it("[[Call]] returns true for classes", () => {
1027 assertStrictEquals(isConstructor(class {}), true);
1030 it("[[Call]] returns false for builtin functions", () => {
1031 assertStrictEquals(isConstructor(Math
.ceil
), false);
1034 it("[[Call]] returns false for getters", () => {
1037 Object
.getOwnPropertyDescriptor({
1047 it("[[Call]] returns false for setters", () => {
1050 Object
.getOwnPropertyDescriptor({
1060 it("[[Call]] returns false for null", () => {
1061 assertStrictEquals(isConstructor(null), false);
1064 it("[[Call]] returns false for objects", () => {
1065 assertStrictEquals(isConstructor({}), false);
1068 it("[[Construct]] throws an error", () => {
1069 assertThrows(() => new isConstructor(function () {}));
1072 describe(".length", () => {
1073 it("[[Get]] returns the correct length", () => {
1074 assertStrictEquals(isConstructor
.length
, 1);
1078 describe(".name", () => {
1079 it("[[Get]] returns the correct name", () => {
1080 assertStrictEquals(isConstructor
.name
, "isConstructor");
1085 describe("maybe", () => {
1086 it("[[Call]] calls if not nullish", () => {
1087 const wrapper
= spy(() => "success");
1088 assertStrictEquals(maybe(0, wrapper
), "success");
1089 assertSpyCalls(wrapper
, 1);
1090 assertSpyCall(wrapper
, 0, {
1093 returned
: "success",
1097 it("[[Call]] does not call if nullish", () => {
1098 const wrapper
= spy(() => "success");
1099 assertStrictEquals(maybe(null, wrapper
), null);
1100 assertStrictEquals(maybe(undefined, wrapper
), undefined);
1101 assertSpyCalls(wrapper
, 0);
1104 it("[[Construct]] throws an error", () => {
1105 assertThrows(() => new maybe(true, ($) => $));
1108 describe(".length", () => {
1109 it("[[Get]] returns the correct length", () => {
1110 assertStrictEquals(maybe
.length
, 2);
1114 describe(".name", () => {
1115 it("[[Get]] returns the correct name", () => {
1116 assertStrictEquals(maybe
.name
, "maybe");
1121 describe("ordinaryHasInstance", () => {
1122 it("[[Call]] walks the prototype chain", () => {
1123 const constructor = class {
1124 [Symbol
.hasInstance
]() {
1129 ordinaryHasInstance(
1131 new class extends constructor {}(),
1137 it("[[Construct]] throws an error", () => {
1138 assertThrows(() => new ordinaryHasInstance(function () {}, {}));
1141 describe(".length", () => {
1142 it("[[Get]] returns the correct length", () => {
1143 assertStrictEquals(ordinaryHasInstance
.length
, 2);
1147 describe(".name", () => {
1148 it("[[Get]] returns the correct name", () => {
1150 ordinaryHasInstance
.name
,
1151 "ordinaryHasInstance",
This page took 0.126886 seconds and 5 git commands to generate.