]>
Lady’s Gitweb - Pisces/blob - function.test.js
09b9f7e00160eb998a82f6714dbaece118aec180
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/>.
20 } from "./dev-deps.js";
27 createCallableFunction
,
28 createIllegalConstructor
,
29 createProxyConstructor
,
35 } from "./function.js";
37 describe("bind", () => {
38 it("[[Call]] binds this", () => {
51 it("[[Call]] binds arguments", () => {
55 return [this, ...args
];
59 ).call("failure", "cmfwyp"),
60 ["etaoin", "shrdlu", "cmfwyp"],
64 it("[[Call]] works with any arraylike third argument", () => {
68 return [this, ...args
];
76 ).call("failure", "cmfwyp"),
77 ["etaoin", undefined, "shrdlu", undefined, "cmfwyp"],
81 it("[[Construct]] throws an error", () => {
82 assertThrows(() => new bind(function () {}));
85 describe(".length", () => {
86 it("[[Get]] returns the correct length", () => {
87 assertStrictEquals(bind
.length
, 3);
91 describe(".name", () => {
92 it("[[Get]] returns the correct name", () => {
93 assertStrictEquals(bind
.name
, "bind");
98 describe("call", () => {
99 it("[[Call]] calls with the provided this value", () => {
112 it("[[Call]] calls with the provided arguments", () => {
116 return [this, ...args
];
119 ["shrdlu", "cmfwyp"],
121 ["etaoin", "shrdlu", "cmfwyp"],
125 it("[[Call]] works with any arraylike third argument", () => {
129 return [this, ...args
];
139 ["etaoin", undefined, "shrdlu", undefined, "cmfwyp"],
143 it("[[Construct]] throws an error", () => {
144 assertThrows(() => new call(function () {}, null, []));
147 describe(".length", () => {
148 it("[[Get]] returns the correct length", () => {
149 assertStrictEquals(call
.length
, 3);
153 describe(".name", () => {
154 it("[[Get]] returns the correct name", () => {
155 assertStrictEquals(call
.name
, "call");
160 describe("completesNormally", () => {
161 it("[[Call]] returns true for functions which complete normally", () => {
162 assertStrictEquals(completesNormally(() => {}), true);
165 it("[[Call]] returns false for functions which throw", () => {
167 completesNormally(() => {
174 it("[[Call]] throws when the argument is not callable", () => {
175 assertThrows(() => completesNormally(null));
178 it("[[Call]] throws when the argument is not provided", () => {
179 assertThrows(() => completesNormally());
182 it("[[Construct]] throws an error", () => {
183 assertThrows(() => new completesNormally(function () {}));
186 describe(".length", () => {
187 it("[[Get]] returns the correct length", () => {
188 assertStrictEquals(completesNormally
.length
, 1);
192 describe(".name", () => {
193 it("[[Get]] returns the correct name", () => {
194 assertStrictEquals(completesNormally
.name
, "completesNormally");
199 describe("construct", () => {
200 it("[[Call]] defaults to the constructor as the target", () => {
201 const constructor = class {};
203 Object
.getPrototypeOf(construct(
207 constructor.prototype,
211 it("[[Call]] constructs with the provided new target", () => {
212 const target = function () {};
225 it("[[Call]] constructs with the provided arguments", () => {
229 return [new.target
.value
, ...args
];
231 ["shrdlu", "cmfwyp"],
232 Object
.assign(function () {}, { value
: "etaoin" }),
234 ["etaoin", "shrdlu", "cmfwyp"],
238 it("[[Call]] works with any arraylike third argument", () => {
242 return [new.target
.value
, ...args
];
250 Object
.assign(function () {}, { value
: "etaoin" }),
252 ["etaoin", undefined, "shrdlu", undefined, "cmfwyp"],
256 it("[[Construct]] throws an error", () => {
257 assertThrows(() => new construct(function () {}, []));
260 describe(".length", () => {
261 it("[[Get]] returns the correct length", () => {
262 assertStrictEquals(construct
.length
, 2);
266 describe(".name", () => {
267 it("[[Get]] returns the correct name", () => {
268 assertStrictEquals(construct
.name
, "construct");
273 describe("createArrowFunction", () => {
274 it("[[Call]] sets this to undefined", () => {
285 it("[[Call]] transfers the provided arguments", () => {
289 return [this, ...args
];
291 ).call("failure", "etaoin", "shrdlu", "cmfwyp"),
292 [undefined, "etaoin", "shrdlu", "cmfwyp"],
296 it("[[Call]] correctly sets the length", () => {
299 function (_a
, _b
, _c
) {},
305 it("[[Call]] correctly sets the name", () => {
308 function etaoin() {},
314 it("[[Call]] allows the length to be overridden", () => {
317 function etaoin() {},
324 it("[[Call]] allows the name to be overridden", () => {
327 function etaoin() {},
334 it("[[Call]] returns an arrow function", () => {
335 assertThrows(() => new (createArrowFunction(function () {}))());
338 it("[[Call]] returns a function with no prototype property", () => {
341 createArrowFunction(function () {}, { prototype: {} })),
345 it("[[Construct]] throws an error", () => {
346 assertThrows(() => new createArrowFunction(function () {}));
349 describe(".length", () => {
350 it("[[Get]] returns the correct length", () => {
351 assertStrictEquals(createArrowFunction
.length
, 1);
355 describe(".name", () => {
356 it("[[Get]] returns the correct name", () => {
358 createArrowFunction
.name
,
359 "createArrowFunction",
365 describe("createCallableFunction", () => {
366 it("[[Call]] transfers the first argument to this", () => {
368 createCallableFunction(
372 ).call("fail", "pass"),
377 it("[[Call]] transfers the remaining arguments", () => {
379 createCallableFunction(
381 return [this, ...args
];
383 ).call("failure", "etaoin", "shrdlu", "cmfwyp"),
384 ["etaoin", "shrdlu", "cmfwyp"],
388 it("[[Call]] correctly sets the length", () => {
390 createCallableFunction(
391 function (_a
, _b
, _c
) {},
397 it("[[Call]] correctly sets the name", () => {
399 createCallableFunction(
400 function etaoin() {},
406 it("[[Call]] allows the length to be overridden", () => {
408 createCallableFunction(
409 function etaoin() {},
416 it("[[Call]] allows the name to be overridden", () => {
418 createCallableFunction(
419 function etaoin() {},
426 it("[[Call]] returns an arrow function", () => {
427 assertThrows(() => new (createCallableFunction(function () {}))());
430 it("[[Call]] returns a function with no prototype property", () => {
433 createCallableFunction(function () {}, { prototype: {} })),
437 it("[[Construct]] throws an error", () => {
438 assertThrows(() => new createCallableFunction(function () {}));
441 describe(".length", () => {
442 it("[[Get]] returns the correct length", () => {
443 assertStrictEquals(createCallableFunction
.length
, 1);
447 describe(".name", () => {
448 it("[[Get]] returns the correct name", () => {
450 createCallableFunction
.name
,
451 "createCallableFunction",
457 describe("createIllegalConstructor", () => {
458 it("[[Call]] returns a constructor", () => {
459 assert(isConstructor(createIllegalConstructor()));
462 it("[[Call]] works as expected when provided with no arguments", () => {
463 const constructor = createIllegalConstructor();
465 Object
.getPrototypeOf(constructor),
469 Object
.getPrototypeOf(constructor.prototype),
473 Object
.getOwnPropertyDescriptors(constructor.prototype),
476 constructor.prototype,
477 Object
.create(Object
.prototype, {
487 !Object
.getOwnPropertyDescriptor(constructor, "prototype")
490 assertStrictEquals(constructor.name
, "");
493 it("[[Call]] returns a correctly‐formed constructor when provided one argument", () => {
494 const constructorPrototype
= Object
.create(null, {
495 name
: { value
: "etaoin" },
496 length
: { value
: "3" },
497 prototype: { value
: {} },
499 const constructor = createIllegalConstructor(
500 Object
.create(constructorPrototype
),
502 assert(isConstructor(constructor));
504 Object
.getPrototypeOf(constructor),
505 constructorPrototype
,
507 assert(Object
.hasOwn(constructor, "prototype"));
509 constructor.prototype,
510 constructorPrototype
.prototype,
513 !Object
.getOwnPropertyDescriptor(constructor, "prototype")
516 assertStrictEquals(constructor.name
, "etaoin");
517 assertStrictEquals(constructor.length
, 3);
520 it("[[Call]] allows the length to be overridden", () => {
522 createIllegalConstructor(
523 function etaoin() {},
530 it("[[Call]] allows the name to be overridden", () => {
532 createIllegalConstructor(
533 function etaoin() {},
540 it("[[Call]] allows the prototype to be overridden", () => {
543 createIllegalConstructor(
544 function etaoin() {},
551 it("[[Construct]] throws an error", () => {
552 assertThrows(() => new createIllegalConstructor(function () {}));
555 describe(".length", () => {
556 it("[[Get]] returns the correct length", () => {
557 assertStrictEquals(createIllegalConstructor
.length
, 1);
561 describe(".name", () => {
562 it("[[Get]] returns the correct name", () => {
564 createIllegalConstructor
.name
,
565 "createIllegalConstructor",
570 describe("~", () => {
571 it("[[Call]] throws an error", () => {
573 createIllegalConstructor(function () {})();
577 it("[[Construct]] throws an error", () => {
579 createIllegalConstructor(function () {})();
585 describe("createProxyConstructor", () => {
586 it("[[Call]] returns a constructor", () => {
587 assert(isConstructor(createProxyConstructor({})));
590 it("[[Call]] throws with no arguments", () => {
591 assertThrows(() => createProxyConstructor());
594 it("[[Call]] throws if the second argument is not a constructor or undefined", () => {
595 assertThrows(() => createProxyConstructor({}, () => {}));
598 it("[[Call]] throws if the third argument is not a constructor or undefined", () => {
600 createProxyConstructor({}, undefined, () => {})
604 it("[[Call]] creates a proper proxy constructor", () => {
605 const constructorPrototype
= function etaoin(_
) {};
606 const constructor = class Constructor
607 extends constructorPrototype
{
608 constructor(_1
, _2
, _3
) {}
610 const proxyConstructor
= createProxyConstructor(
614 assert(isConstructor(proxyConstructor
));
616 Object
.getPrototypeOf(proxyConstructor
),
619 assertStrictEquals(proxyConstructor
.prototype, undefined);
620 assertStrictEquals(proxyConstructor
.name
, "ConstructorProxy");
621 assertStrictEquals(proxyConstructor
.length
, 3);
624 it("[[Call]] allows the length to be overridden", () => {
626 createProxyConstructor({}, undefined, undefined, {
633 it("[[Call]] allows the name to be overridden", () => {
635 createProxyConstructor({}, function etaoin() {}, undefined, {
642 it("[[Call]] does not allow the prototype to be overridden", () => {
644 createProxyConstructor({}, undefined, undefined, {
651 it("[[Construct]] throws an error", () => {
652 assertThrows(() => new createProxyConstructor({}));
655 describe(".length", () => {
656 it("[[Get]] returns the correct length", () => {
657 assertStrictEquals(createProxyConstructor
.length
, 2);
661 describe(".name", () => {
662 it("[[Get]] returns the correct name", () => {
664 createProxyConstructor
.name
,
665 "createProxyConstructor",
670 describe("~", () => {
671 it("[[Call]] throws an error", () => {
673 createProxyConstructor({})();
677 it("[[Construct]] produces a proxy", () => {
679 const proxyConstructor
= createProxyConstructor({
680 get(O
, P
, Receiver
) {
681 if (P
=== "etaoin") {
682 return Reflect
.get(O
, P
, Receiver
) ?? "success";
684 return Reflect
.get(O
, P
, Receiver
);
690 const proxy
= new proxyConstructor();
691 assertStrictEquals(proxy
.etaoin
, "success");
692 obj
.etaoin
= "shrdlu";
693 assertStrictEquals(proxy
.etaoin
, "shrdlu");
696 it("[[Construct]] receives the expected new.target", () => {
697 const constructor = function Constructor() {
698 return { name
: new.target
.name
};
701 new (createProxyConstructor({}, constructor))().name
,
705 new (createProxyConstructor(
708 function NewTarget() {},
715 describe("~length", () => {
716 it("[[GetOwnProperty]] has the correct descriptor", () => {
718 Object
.getOwnPropertyDescriptor(
719 createProxyConstructor({}),
732 describe("~name", () => {
733 it("[[GetOwnProperty]] has the correct descriptor", () => {
735 Object
.getOwnPropertyDescriptor(
736 createProxyConstructor({}),
742 value
: "ObjectProxy",
749 describe("~prototype", () => {
750 it("[[GetOwnProperty]] has the correct descriptor", () => {
752 Object
.getOwnPropertyDescriptor(
753 createProxyConstructor({}),
766 describe("~revocable", () => {
767 it("[[Call]] produces a revocable proxy", () => {
769 const proxyConstructor
= createProxyConstructor({
770 get(O
, P
, Receiver
) {
771 if (P
=== "etaoin") {
772 return Reflect
.get(O
, P
, Receiver
) ?? "success";
774 return Reflect
.get(O
, P
, Receiver
);
780 const { proxy
, revoke
} = proxyConstructor
.revocable();
781 assertStrictEquals(proxy
.etaoin
, "success");
782 obj
.etaoin
= "shrdlu";
783 assertStrictEquals(proxy
.etaoin
, "shrdlu");
785 assertThrows(() => proxy
.etaoin
);
788 it("[[Call]] receives the expected new.target", () => {
789 const constructor = function Constructor() {
790 return { name
: new.target
.name
};
793 createProxyConstructor({}, constructor).revocable().proxy
.name
,
797 createProxyConstructor(
800 function NewTarget() {},
801 ).revocable().proxy
.name
,
806 it("[[Construct]] throws an error", () => {
807 assertThrows(() => new (createProxyConstructor({})).revocable());
810 it("[[GetOwnProperty]] has the correct descriptor", () => {
811 const proxyConstructor
= createProxyConstructor({});
813 Object
.getOwnPropertyDescriptor(proxyConstructor
, "revocable"),
817 value
: proxyConstructor
.revocable
,
825 describe("identity", () => {
826 it("[[Call]] returns what it is given", () => {
828 assertStrictEquals(identity(value
), value
);
831 it("[[Construct]] is constructable", () => {
833 assertStrictEquals(new identity(value
), value
);
836 it("[[Construct]] is subclassable", () => {
838 assertStrictEquals(new class extends identity
{}(value
), value
);
841 describe(".length", () => {
842 it("[[Get]] returns the correct length", () => {
843 assertStrictEquals(identity
.length
, 1);
847 describe(".name", () => {
848 it("[[Get]] returns the correct name", () => {
849 assertStrictEquals(identity
.name
, "identity");
854 describe("isCallable", () => {
855 it("[[Call]] returns true for ordinary functions", () => {
856 assertStrictEquals(isCallable(function () {}), true);
859 it("[[Call]] returns true for arrow functions", () => {
860 assertStrictEquals(isCallable(() => {}), true);
863 it("[[Call]] returns true for generator functions", () => {
864 assertStrictEquals(isCallable(function* () {}), true);
867 it("[[Call]] returns true for classes", () => {
868 assertStrictEquals(isCallable(class {}), true);
871 it("[[Call]] returns true for builtin functions", () => {
872 assertStrictEquals(isCallable(Math
.ceil
), true);
875 it("[[Call]] returns true for getters", () => {
878 Object
.getOwnPropertyDescriptor({
888 it("[[Call]] returns true for setters", () => {
891 Object
.getOwnPropertyDescriptor({
901 it("[[Call]] returns false for null", () => {
902 assertStrictEquals(isCallable(null), false);
905 it("[[Call]] returns false for objects", () => {
906 assertStrictEquals(isCallable({}), false);
909 it("[[Construct]] throws an error", () => {
910 assertThrows(() => new isCallable(function () {}));
913 describe(".length", () => {
914 it("[[Get]] returns the correct length", () => {
915 assertStrictEquals(isCallable
.length
, 1);
919 describe(".name", () => {
920 it("[[Get]] returns the correct name", () => {
921 assertStrictEquals(isCallable
.name
, "isCallable");
926 describe("isConstructor", () => {
927 it("[[Call]] returns true for ordinary functions", () => {
928 assertStrictEquals(isConstructor(function () {}), true);
931 it("[[Call]] returns false for arrow functions", () => {
932 assertStrictEquals(isConstructor(() => {}), false);
935 it("[[Call]] returns false for generator functions", () => {
936 assertStrictEquals(isConstructor(function* () {}), false);
939 it("[[Call]] returns true for classes", () => {
940 assertStrictEquals(isConstructor(class {}), true);
943 it("[[Call]] returns false for builtin functions", () => {
944 assertStrictEquals(isConstructor(Math
.ceil
), false);
947 it("[[Call]] returns false for getters", () => {
950 Object
.getOwnPropertyDescriptor({
960 it("[[Call]] returns false for setters", () => {
963 Object
.getOwnPropertyDescriptor({
973 it("[[Call]] returns false for null", () => {
974 assertStrictEquals(isConstructor(null), false);
977 it("[[Call]] returns false for objects", () => {
978 assertStrictEquals(isConstructor({}), false);
981 it("[[Construct]] throws an error", () => {
982 assertThrows(() => new isConstructor(function () {}));
985 describe(".length", () => {
986 it("[[Get]] returns the correct length", () => {
987 assertStrictEquals(isConstructor
.length
, 1);
991 describe(".name", () => {
992 it("[[Get]] returns the correct name", () => {
993 assertStrictEquals(isConstructor
.name
, "isConstructor");
998 describe("maybe", () => {
999 it("[[Call]] calls if not nullish", () => {
1000 const wrapper
= spy(() => "success");
1001 assertStrictEquals(maybe(0, wrapper
), "success");
1002 assertSpyCalls(wrapper
, 1);
1003 assertSpyCall(wrapper
, 0, {
1006 returned
: "success",
1010 it("[[Call]] does not call if nullish", () => {
1011 const wrapper
= spy(() => "success");
1012 assertStrictEquals(maybe(null, wrapper
), null);
1013 assertStrictEquals(maybe(undefined, wrapper
), undefined);
1014 assertSpyCalls(wrapper
, 0);
1017 it("[[Construct]] throws an error", () => {
1018 assertThrows(() => new maybe(true, ($) => $));
1021 describe(".length", () => {
1022 it("[[Get]] returns the correct length", () => {
1023 assertStrictEquals(maybe
.length
, 2);
1027 describe(".name", () => {
1028 it("[[Get]] returns the correct name", () => {
1029 assertStrictEquals(maybe
.name
, "maybe");
1034 describe("ordinaryHasInstance", () => {
1035 it("[[Call]] walks the prototype chain", () => {
1036 const constructor = class {
1037 [Symbol
.hasInstance
]() {
1042 ordinaryHasInstance(
1044 new class extends constructor {}(),
1050 it("[[Construct]] throws an error", () => {
1051 assertThrows(() => new ordinaryHasInstance(function () {}, {}));
1054 describe(".length", () => {
1055 it("[[Get]] returns the correct length", () => {
1056 assertStrictEquals(ordinaryHasInstance
.length
, 2);
1060 describe(".name", () => {
1061 it("[[Get]] returns the correct name", () => {
1063 ordinaryHasInstance
.name
,
1064 "ordinaryHasInstance",
This page took 0.118095 seconds and 3 git commands to generate.