]>
Lady’s Gitweb - Pisces/blob - object.test.js
68e3264bb8b70d83353a7d56d2e3788c3833a2b1
1 // ♓🌟 Piscēs ∷ object.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";
36 describe("LazyLoader", () => {
37 const symbol
= Symbol("foo");
39 const etaoinMethod
= spy(() => "success");
40 const shrdluMethod
= spy(() => "success");
41 const cmfwypMethod
= spy(() => "success");
42 const vbgkqjMethod
= spy(() => "success");
43 const methodsObject
= Object
.create(
73 xz
fiflffffi: { configurable
: true, enumerable
: false, set(_
) {} },
83 it("[[Construct]] creates a new object which inherits from the correct prototype", () => {
85 Object
.getPrototypeOf(new LazyLoader(methodsObject
)),
90 it("[[Construct]] creates a new object with the desired properties", () => {
92 Reflect
.ownKeys(new LazyLoader(methodsObject
)),
93 ["etaoin", "shrdlu", "cmfwyp", "vbgkqj", "xzfiflffffi", symbol
],
97 it("[[Construct]] creates a new object with configurable properties", () => {
101 for (const key
of Reflect
.ownKeys(ll
)) {
104 Object
.getOwnPropertyDescriptor(ll
, key
).configurable
,
107 }(new LazyLoader(methodsObject
)),
120 it("[[Construct]] creates a new object with the correct enumerability", () => {
124 for (const key
of Reflect
.ownKeys(ll
)) {
127 Object
.getOwnPropertyDescriptor(ll
, key
).enumerable
,
130 }(new LazyLoader(methodsObject
)),
143 it("[[Construct]] creates a new object with defined getters", () => {
147 for (const key
of Reflect
.ownKeys(ll
)) {
150 Object
.getOwnPropertyDescriptor(ll
, key
).get?.name
,
153 }(new LazyLoader(methodsObject
)),
156 etaoin
: "get etaoin",
157 shrdlu
: "get shrdlu",
158 cmfwyp
: "get cmfwyp",
159 vbgkqj
: "get vbgkqj",
160 xz
fiflffffi: "get xzfiflffffi",
161 [symbol
]: `get [${symbol.description}]`,
166 it("[[Construct]] creates a new object with defined setters for writable properties only", () => {
170 for (const key
of Reflect
.ownKeys(ll
)) {
173 Object
.getOwnPropertyDescriptor(ll
, key
).set?.name
,
176 }(new LazyLoader(methodsObject
)),
184 [symbol
]: `set [${symbol.description}]`,
189 it("[[Construct]] creates a new object with correct getter behaviour", () => {
190 const ll
= new LazyLoader(methodsObject
);
193 Object
.getOwnPropertyDescriptor(ll
, "etaoin"),
201 assertSpyCalls(etaoinMethod
, 1);
202 assertSpyCall(etaoinMethod
, 0, {
209 Object
.getOwnPropertyDescriptor(ll
, "shrdlu"),
217 assertSpyCalls(shrdluMethod
, 1);
218 assertSpyCall(shrdluMethod
, 0, {
225 Object
.getOwnPropertyDescriptor(ll
, "cmfwyp"),
233 assertSpyCalls(cmfwypMethod
, 1);
234 assertSpyCall(cmfwypMethod
, 0, {
241 Object
.getOwnPropertyDescriptor(ll
, "vbgkqj"),
249 assertSpyCalls(vbgkqjMethod
, 1);
250 assertSpyCall(vbgkqjMethod
, 0, {
255 assertThrows(() => ll
.xz
fiflffffi);
256 assertThrows(() => ll
[symbol
]);
259 it("[[Construct]] creates a new object with correct setter behaviour", () => {
260 const ll
= new LazyLoader(methodsObject
);
261 ll
[symbol
] = "success";
263 Object
.getOwnPropertyDescriptor(ll
, symbol
),
274 describe("PropertyDescriptor", () => {
275 it("[[Construct]] creates a new PropertyDescriptor", () => {
277 Object
.getPrototypeOf(new PropertyDescriptor({})),
278 PropertyDescriptor
.prototype,
282 it("[[Construct]] throws for primitives", () => {
283 assertThrows(() => new PropertyDescriptor("failure"));
286 describe("::complete", () => {
287 it("[[Call]] completes a generic descriptor", () => {
289 PropertyDescriptor
.prototype.complete
.call(desc
);
298 it("[[Call]] completes a data descriptor", () => {
299 const desc
= { value
: undefined };
300 PropertyDescriptor
.prototype.complete
.call(desc
);
309 it("[[Call]] completes an accessor descriptor", () => {
310 const desc
= { get: undefined };
311 PropertyDescriptor
.prototype.complete
.call(desc
);
321 describe("::isAccessorDescriptor", () => {
322 it("[[Get]] returns false for a generic descriptor", () => {
325 PropertyDescriptor
.prototype,
326 "isAccessorDescriptor",
333 it("[[Get]] returns false for a data descriptor", () => {
336 PropertyDescriptor
.prototype,
337 "isAccessorDescriptor",
338 { value
: undefined },
344 it("[[Get]] returns true for an accessor descriptor", () => {
347 PropertyDescriptor
.prototype,
348 "isAccessorDescriptor",
356 describe("::isDataDescriptor", () => {
357 it("[[Get]] returns false for a generic descriptor", () => {
360 PropertyDescriptor
.prototype,
368 it("[[Get]] returns true for a data descriptor", () => {
371 PropertyDescriptor
.prototype,
373 { value
: undefined },
379 it("[[Get]] returns false for an accessor descriptor", () => {
382 PropertyDescriptor
.prototype,
391 describe("::isFullyPopulated", () => {
392 it("[[Get]] returns false for a generic descriptor", () => {
395 PropertyDescriptor
.prototype,
403 it("[[Get]] returns false for a non‐fully‐populated data descriptor", () => {
406 PropertyDescriptor
.prototype,
408 { value
: undefined },
414 it("[[Get]] returns true for a fully‐populated data descriptor", () => {
416 Reflect
.get(PropertyDescriptor
.prototype, "isFullyPopulated", {
426 it("[[Get]] returns false for a non‐fully‐populated accessor descriptor", () => {
429 PropertyDescriptor
.prototype,
437 it("[[Get]] returns true for a fully‐populated accessor descriptor", () => {
439 Reflect
.get(PropertyDescriptor
.prototype, "isFullyPopulated", {
450 describe("::isGenericDescriptor", () => {
451 it("[[Get]] returns true for a generic descriptor", () => {
454 PropertyDescriptor
.prototype,
455 "isGenericDescriptor",
462 it("[[Get]] returns true for a data descriptor", () => {
465 PropertyDescriptor
.prototype,
466 "isGenericDescriptor",
467 { value
: undefined },
473 it("[[Get]] returns false for an accessor descriptor", () => {
476 PropertyDescriptor
.prototype,
477 "isGenericDescriptor",
485 describe("~configurable", () => {
486 it("[[DefineOwnProperty]] coerces to a boolean", () => {
487 const desc
= new PropertyDescriptor({});
488 Object
.defineProperty(desc
, "configurable", {});
489 assertStrictEquals(desc
.configurable
, false);
492 it("[[DefineOwnProperty]] throws for accessor properties", () => {
493 const desc
= new PropertyDescriptor({});
495 Object
.defineProperty(desc
, "configurable", { get: undefined })
499 it("[[Set]] coerces to a boolean", () => {
500 const desc
= new PropertyDescriptor({});
501 desc
.configurable
= undefined;
502 assertStrictEquals(desc
.configurable
, false);
505 it("[[Delete]] works", () => {
506 const desc
= new PropertyDescriptor({ configurable
: false });
507 delete desc
.configurable
;
508 assert(!("configurable" in desc
));
512 describe("~enumerable", () => {
513 it("[[DefineOwnProperty]] coerces to a boolean", () => {
514 const desc
= new PropertyDescriptor({});
515 Object
.defineProperty(desc
, "enumerable", {});
516 assertStrictEquals(desc
.enumerable
, false);
519 it("[[DefineOwnProperty]] throws for accessor properties", () => {
520 const desc
= new PropertyDescriptor({});
522 Object
.defineProperty(desc
, "enumerable", { get: undefined })
526 it("[[Set]] coerces to a boolean", () => {
527 const desc
= new PropertyDescriptor({});
528 desc
.enumerable
= undefined;
529 assertStrictEquals(desc
.enumerable
, false);
532 it("[[Delete]] works", () => {
533 const desc
= new PropertyDescriptor({ enumerable
: false });
534 delete desc
.enumerable
;
535 assert(!("enumerable" in desc
));
539 describe("~get", () => {
540 it("[[DefineOwnProperty]] works", () => {
541 const desc
= new PropertyDescriptor({});
542 Object
.defineProperty(desc
, "get", {});
543 assertStrictEquals(desc
.get, undefined);
546 it("[[DefineOwnProperty]] throws for accessor properties", () => {
547 const desc
= new PropertyDescriptor({});
549 Object
.defineProperty(desc
, "get", { get: undefined })
553 it("[[DefineOwnProperty]] throws if not callable or undefined", () => {
554 const desc
= new PropertyDescriptor({});
556 () => Object
.defineProperty(desc
, "get", { value
: null }),
560 it("[[DefineOwnProperty]] throws if a data property is defined", () => {
561 const desc
= new PropertyDescriptor({ value
: undefined });
562 assertThrows(() => Object
.defineProperty(desc
, "get", {}));
565 it("[[Set]] works", () => {
566 const desc
= new PropertyDescriptor({});
569 assertStrictEquals(desc
.get, fn
);
572 it("[[Set]] throws if not callable or undefined", () => {
573 const desc
= new PropertyDescriptor({});
574 assertThrows(() => desc
.get = null);
577 it("[[Set]] throws if a data property is defined", () => {
578 const desc
= new PropertyDescriptor({ value
: undefined });
579 assertThrows(() => desc
.get = undefined);
582 it("[[Delete]] works", () => {
583 const desc
= new PropertyDescriptor({ get: undefined });
585 assert(!("get" in desc
));
589 describe("~set", () => {
590 it("[[DefineOwnProperty]] works", () => {
591 const desc
= new PropertyDescriptor({});
592 Object
.defineProperty(desc
, "set", {});
593 assertStrictEquals(desc
.set, undefined);
596 it("[[DefineOwnProperty]] throws for accessor properties", () => {
597 const desc
= new PropertyDescriptor({});
599 Object
.defineProperty(desc
, "set", { get: undefined })
603 it("[[DefineOwnProperty]] throws if not callable or undefined", () => {
604 const desc
= new PropertyDescriptor({});
606 () => Object
.defineProperty(desc
, "set", { value
: null }),
610 it("[[DefineOwnProperty]] throws if a data property is defined", () => {
611 const desc
= new PropertyDescriptor({ value
: undefined });
612 assertThrows(() => Object
.defineProperty(desc
, "set", {}));
615 it("[[Set]] works", () => {
616 const desc
= new PropertyDescriptor({});
617 const fn
= (_
) => {};
619 assertStrictEquals(desc
.set, fn
);
622 it("[[Set]] throws if not callable or undefined", () => {
623 const desc
= new PropertyDescriptor({});
624 assertThrows(() => desc
.set = null);
627 it("[[Set]] throws if a data property is defined", () => {
628 const desc
= new PropertyDescriptor({ value
: undefined });
629 assertThrows(() => desc
.set = undefined);
632 it("[[Delete]] works", () => {
633 const desc
= new PropertyDescriptor({ set: undefined });
635 assert(!("set" in desc
));
639 describe("~value", () => {
640 it("[[DefineOwnProperty]] works", () => {
641 const desc
= new PropertyDescriptor({});
642 Object
.defineProperty(desc
, "value", {});
643 assertStrictEquals(desc
.value
, undefined);
646 it("[[DefineOwnProperty]] throws for accessor properties", () => {
647 const desc
= new PropertyDescriptor({});
649 Object
.defineProperty(desc
, "value", { get: undefined })
653 it("[[DefineOwnProperty]] throws if an accessor property is defined", () => {
654 const desc
= new PropertyDescriptor({ get: undefined });
655 assertThrows(() => Object
.defineProperty(desc
, "value", {}));
658 it("[[Set]] works", () => {
659 const desc
= new PropertyDescriptor({});
660 desc
.value
= "success";
661 assertStrictEquals(desc
.value
, "success");
664 it("[[Set]] throws if an accessor property is defined", () => {
665 const desc
= new PropertyDescriptor({ get: undefined });
666 assertThrows(() => desc
.value
= null);
669 it("[[Delete]] works", () => {
670 const desc
= new PropertyDescriptor({ value
: undefined });
672 assert(!("value" in desc
));
676 describe("~writable", () => {
677 it("[[DefineOwnProperty]] coerces to a boolean", () => {
678 const desc
= new PropertyDescriptor({});
679 Object
.defineProperty(desc
, "writable", {});
680 assertStrictEquals(desc
.writable
, false);
683 it("[[DefineOwnProperty]] throws for accessor properties", () => {
684 const desc
= new PropertyDescriptor({});
686 Object
.defineProperty(desc
, "writable", { get: undefined })
690 it("[[DefineOwnProperty]] throws if an accessor property is defined", () => {
691 const desc
= new PropertyDescriptor({ get: undefined });
692 assertThrows(() => Object
.defineProperty(desc
, "writable", {}));
695 it("[[Set]] coerces to a boolean", () => {
696 const desc
= new PropertyDescriptor({});
697 desc
.writable
= undefined;
698 assertStrictEquals(desc
.writable
, false);
701 it("[[Set]] throws if an accessor property is defined", () => {
702 const desc
= new PropertyDescriptor({ get: undefined });
703 assertThrows(() => desc
.writable
= false);
706 it("[[Delete]] works", () => {
707 const desc
= new PropertyDescriptor({ writable
: false });
708 delete desc
.writable
;
709 assert(!("writable" in desc
));
714 describe("defineOwnProperties", () => {
715 it("[[Call]] defines properties from the provided objects", () => {
717 defineOwnProperties(obj
, {
721 assert("etaoin" in obj
);
722 assert("shrdlu" in obj
);
723 assert("cmfwyp" in obj
);
726 it("[[Call]] overrides earlier declarations with later ones", () => {
727 const obj
= { etaoin
: undefined };
728 defineOwnProperties(obj
, {
729 etaoin
: { value
: "failure" },
731 etaoin
: { value
: "success" },
733 assertStrictEquals(obj
.etaoin
, "success");
736 it("[[Call]] returns the provided object", () => {
738 assertStrictEquals(defineOwnProperties(obj
), obj
);
742 describe("deleteOwnProperty", () => {
743 it("[[Call]] deletes the provided property on the provided object", () => {
744 const obj
= { failure
: undefined };
745 deleteOwnProperty(obj
, "failure");
746 assert(!("failure" in obj
));
749 it("[[Call]] does nothing if the property doesn’t exist", () => {
750 const obj
= Object
.freeze({});
751 deleteOwnProperty(obj
, "failure");
752 assert(!("failure" in obj
));
755 it("[[Call]] throws if the property can’t be deleted", () => {
756 const obj
= Object
.seal({ failure
: undefined });
757 assertThrows(() => deleteOwnProperty(obj
, "failure"));
760 it("[[Call]] returns the provided object", () => {
762 assertStrictEquals(deleteOwnProperty(obj
, ""), obj
);
766 describe("frozenCopy", () => {
767 it("[[Call]] returns a frozen object", () => {
770 frozenCopy(Object
.create(null), {
787 it("[[Call]] ignores non·enumerable properties", () => {
790 Object
.create(null, {
791 data
: { value
: undefined },
792 accessor
: { get: undefined },
799 it("[[Call]] preserves accessor properties", () => {
827 Object
.getOwnPropertyDescriptors(
828 frozenCopy(Object
.create(null, properties
)),
834 it("[[Call]] does not copy properties on the prototype", () => {
837 frozenCopy(Object
.create({ failure
: undefined }), {
843 accessor
: { configurable
: true, get: undefined },
848 it("[[Call]] uses the species of the constructor", () => {
849 const species
= { prototype: {} };
851 Object
.getPrototypeOf(
852 frozenCopy({}, { [Symbol
.species
]: species
}),
858 it("[[Call]] uses constructor if no species is defined", () => {
859 const constructor = { [Symbol
.species
]: null, prototype: {} };
861 Object
.getPrototypeOf(frozenCopy({}, constructor)),
862 constructor.prototype,
866 it("[[Call]] uses the constructor on the object if none is provided", () => {
867 const constructor = { [Symbol
.species
]: null, prototype: {} };
869 Object
.getPrototypeOf(frozenCopy({ constructor })),
870 constructor.prototype,
874 it("[[Call]] allows a null constructor", () => {
876 Object
.getPrototypeOf(frozenCopy({}, null)),
882 describe("getMethod", () => {
883 it("[[Call]] gets a method", () => {
884 const method
= () => {};
885 assertStrictEquals(getMethod({ method
}, "method"), method
);
888 it("[[Call]] works for values coercible to objects", () => {
889 assertEquals(getMethod("", "toString"), String
.prototype.toString
);
892 it("[[Call]] throws for null and undefined", () => {
893 assertThrows(() => getMethod(null, "valueOf"));
894 assertThrows(() => getMethod(undefined, "valueOf"));
897 it("[[Call]] throws if the resulting value isn’t callable", () => {
898 assertThrows(() => getMethod({ "failure": true }, "failure"));
902 describe("getOwnPropertyKeys", () => {
903 it("[[Call]] gets own (but not inherited) property keys", () => {
904 assertEquals(getOwnPropertyKeys({ success
: true }), ["success"]);
907 it("[[Call]] works for values coercible to objects", () => {
908 assertEquals(getOwnPropertyKeys("foo"), ["0", "1", "2", "length"]);
911 it("[[Call]] throws for null and undefined", () => {
912 assertThrows(() => getOwnPropertyKeys(null));
913 assertThrows(() => getOwnPropertyKeys(undefined));
917 describe("getPropertyValue", () => {
918 it("[[Call]] gets property values on the provided object", () => {
920 getPropertyValue({ success
: true }, "success"),
925 it("[[Call]] works for values coercible to objects", () => {
927 getPropertyValue("", "toString"),
928 String
.prototype.toString
,
932 it("[[Call]] throws for null and undefined", () => {
933 assertThrows(() => getPropertyValue(null, "valueOf"));
934 assertThrows(() => getPropertyValue(undefined, "valueOf"));
938 describe("hasProperty", () => {
939 it("[[Call]] gets whether a property exists on the provided object", () => {
941 hasProperty({ success
: "etaoin" }, "success"),
946 it("[[Call]] works for values coercible to objects", () => {
947 assertStrictEquals(hasProperty("", "toString"), true);
950 it("[[Call]] throws for null and undefined", () => {
951 assertThrows(() => hasProperty(null, "valueOf"));
952 assertThrows(() => hasProperty(undefined, "valueOf"));
956 describe("setPropertyValue", () => {
957 it("[[Call]] sets the provided property on the provided object", () => {
959 setPropertyValue(obj
, "success", true);
960 assertStrictEquals(obj
.success
, true);
963 it("[[Call]] calls setters", () => {
964 const setter
= spy((_
) => {});
965 const obj
= Object
.create(null, { success
: { set: setter
} });
966 setPropertyValue(obj
, "success", true);
967 assertSpyCalls(setter
, 1);
968 assertSpyCall(setter
, 0, {
974 it("[[Call]] walks the prototype chain", () => {
975 const setter
= spy((_
) => {});
976 const obj
= Object
.create(
977 Object
.create(null, { success
: { set: setter
} }),
979 setPropertyValue(obj
, "success", true);
980 assertSpyCalls(setter
, 1);
981 assertSpyCall(setter
, 0, {
987 it("[[Call]] uses the provided receiver", () => {
988 const setter
= spy((_
) => {});
989 const obj
= Object
.create(null, { success
: { set: setter
} });
991 setPropertyValue(obj
, "success", true, receiver
);
992 assertSpyCalls(setter
, 1);
993 assertSpyCall(setter
, 0, {
999 it("[[Call]] throws if the property can’t be set", () => {
1000 const obj
= Object
.freeze({ failure
: undefined });
1001 assertThrows(() => setPropertyValue(obj
, "failure", true));
1004 it("[[Call]] returns the provided object", () => {
1006 assertStrictEquals(setPropertyValue(obj
, "", undefined), obj
);
1010 describe("toObject", () => {
1011 it("returns the input for objects", () => {
1013 assertStrictEquals(toObject(obj
), obj
);
1016 it("throws for nullish values", () => {
1017 assertThrows(() => toObject(null));
1018 assertThrows(() => toObject(void {}));
1021 it("returns a wrapper object for other primitives", () => {
1022 const sym
= Symbol();
1023 assertStrictEquals(typeof toObject(sym
), "object");
1024 assertStrictEquals(toObject(sym
).valueOf(), sym
);
1028 describe("toPropertyKey", () => {
1029 it("returns a string or symbol", () => {
1030 const sym
= Symbol();
1031 assertStrictEquals(toPropertyKey(sym
), sym
);
1033 toPropertyKey(new String("success")),
1038 it("favours the `toString` representation", () => {
This page took 0.129306 seconds and 3 git commands to generate.