]> Lady’s Gitweb - Pisces/blob - object.test.js
Add LazyLoader class
[Pisces] / object.test.js
1 // ♓🌟 Piscēs ∷ object.test.js
2 // ====================================================================
3 //
4 // Copyright © 2022 Lady [@ Lady’s Computer].
5 //
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/>.
9
10 import {
11 assert,
12 assertEquals,
13 assertSpyCall,
14 assertSpyCalls,
15 assertStrictEquals,
16 assertThrows,
17 describe,
18 it,
19 spy,
20 } from "./dev-deps.js";
21 import {
22 defineOwnProperties,
23 deleteOwnProperty,
24 frozenCopy,
25 LazyLoader,
26 PropertyDescriptor,
27 setPropertyValue,
28 toObject,
29 toPropertyKey,
30 } from "./object.js";
31
32 describe("LazyLoader", () => {
33 const symbol = Symbol();
34 const prototype = {};
35 const etaoinMethod = spy(() => "success");
36 const shrdluMethod = spy(() => "success");
37 const cmfwypMethod = spy(() => "success");
38 const vbgkqjMethod = spy(() => "success");
39 const methodsObject = Object.create(
40 prototype,
41 {
42 etaoin: {
43 configurable: false,
44 enumerable: true,
45 value: etaoinMethod,
46 writable: false,
47 },
48 shrdlu: {
49 configurable: true,
50 enumerable: false,
51 value: shrdluMethod,
52 writable: false,
53 },
54 cmfwyp: {
55 configurable: true,
56 enumerable: false,
57 get() {
58 return cmfwypMethod;
59 },
60 },
61 vbgkqj: {
62 configurable: false,
63 enumerable: true,
64 get() {
65 return vbgkqjMethod;
66 },
67 set(_) {},
68 },
69 xzfiflffffi: { configurable: true, enumerable: false, set(_) {} },
70 [symbol]: {
71 configurable: true,
72 enumerable: false,
73 value: "failure",
74 writable: true,
75 },
76 },
77 );
78
79 it("[[Construct]] creates a new object which inherits from the correct prototype", () => {
80 assertStrictEquals(
81 Object.getPrototypeOf(new LazyLoader(methodsObject)),
82 prototype,
83 );
84 });
85
86 it("[[Construct]] creates a new object with the desired properties", () => {
87 assertEquals(
88 Reflect.ownKeys(new LazyLoader(methodsObject)),
89 ["etaoin", "shrdlu", "cmfwyp", "vbgkqj", "xzfiflffffi", symbol],
90 );
91 });
92
93 it("[[Construct]] creates a new object with configurable properties", () => {
94 assertEquals(
95 Object.fromEntries(
96 function* (ll) {
97 for (const key of Reflect.ownKeys(ll)) {
98 yield [
99 key,
100 Object.getOwnPropertyDescriptor(ll, key).configurable,
101 ];
102 }
103 }(new LazyLoader(methodsObject)),
104 ),
105 {
106 etaoin: true,
107 shrdlu: true,
108 cmfwyp: true,
109 vbgkqj: true,
110 xzfiflffffi: true,
111 [symbol]: true,
112 },
113 );
114 });
115
116 it("[[Construct]] creates a new object with the correct enumerability", () => {
117 assertEquals(
118 Object.fromEntries(
119 function* (ll) {
120 for (const key of Reflect.ownKeys(ll)) {
121 yield [
122 key,
123 Object.getOwnPropertyDescriptor(ll, key).enumerable,
124 ];
125 }
126 }(new LazyLoader(methodsObject)),
127 ),
128 {
129 etaoin: true,
130 shrdlu: false,
131 cmfwyp: false,
132 vbgkqj: true,
133 xzfiflffffi: false,
134 [symbol]: false,
135 },
136 );
137 });
138
139 it("[[Construct]] creates a new object with defined getters", () => {
140 assertEquals(
141 Object.fromEntries(
142 function* (ll) {
143 for (const key of Reflect.ownKeys(ll)) {
144 yield [
145 key,
146 Object.getOwnPropertyDescriptor(ll, key).get !== void {},
147 ];
148 }
149 }(new LazyLoader(methodsObject)),
150 ),
151 {
152 etaoin: true,
153 shrdlu: true,
154 cmfwyp: true,
155 vbgkqj: true,
156 xzfiflffffi: true,
157 [symbol]: true,
158 },
159 );
160 });
161
162 it("[[Construct]] creates a new object with defined setters for writable properties only", () => {
163 assertEquals(
164 Object.fromEntries(
165 function* (ll) {
166 for (const key of Reflect.ownKeys(ll)) {
167 yield [
168 key,
169 Object.getOwnPropertyDescriptor(ll, key).set !== void {},
170 ];
171 }
172 }(new LazyLoader(methodsObject)),
173 ),
174 {
175 etaoin: false,
176 shrdlu: false,
177 cmfwyp: false,
178 vbgkqj: false,
179 xzfiflffffi: false,
180 [symbol]: true,
181 },
182 );
183 });
184
185 describe("[[Construct]] creates a new object with correct getter behaviour", () => {
186 const ll = new LazyLoader(methodsObject);
187 ll.etaoin;
188 assertEquals(
189 Object.getOwnPropertyDescriptor(ll, "etaoin"),
190 {
191 configurable: false,
192 enumerable: true,
193 value: "success",
194 writable: false,
195 },
196 );
197 assertSpyCalls(etaoinMethod, 1);
198 assertSpyCall(etaoinMethod, 0, {
199 args: [],
200 self: ll,
201 returned: "success",
202 });
203 ll.shrdlu;
204 assertEquals(
205 Object.getOwnPropertyDescriptor(ll, "shrdlu"),
206 {
207 configurable: true,
208 enumerable: false,
209 value: "success",
210 writable: false,
211 },
212 );
213 assertSpyCalls(shrdluMethod, 1);
214 assertSpyCall(shrdluMethod, 0, {
215 args: [],
216 self: ll,
217 returned: "success",
218 });
219 ll.cmfwyp;
220 assertEquals(
221 Object.getOwnPropertyDescriptor(ll, "cmfwyp"),
222 {
223 configurable: true,
224 enumerable: false,
225 value: "success",
226 writable: false,
227 },
228 );
229 assertSpyCalls(cmfwypMethod, 1);
230 assertSpyCall(cmfwypMethod, 0, {
231 args: [],
232 self: ll,
233 returned: "success",
234 });
235 ll.vbgkqj;
236 assertEquals(
237 Object.getOwnPropertyDescriptor(ll, "vbgkqj"),
238 {
239 configurable: false,
240 enumerable: true,
241 value: "success",
242 writable: false,
243 },
244 );
245 assertSpyCalls(vbgkqjMethod, 1);
246 assertSpyCall(vbgkqjMethod, 0, {
247 args: [],
248 self: ll,
249 returned: "success",
250 });
251 assertThrows(() => ll.xzfiflffffi);
252 assertThrows(() => ll[symbol]);
253 });
254
255 describe("[[Construct]] creates a new object with correct setter behaviour", () => {
256 const ll = new LazyLoader(methodsObject);
257 ll[symbol] = "success";
258 assertEquals(
259 Object.getOwnPropertyDescriptor(ll, symbol),
260 {
261 configurable: true,
262 enumerable: false,
263 value: "success",
264 writable: true,
265 },
266 );
267 });
268 });
269
270 describe("PropertyDescriptor", () => {
271 it("[[Construct]] creates a new PropertyDescriptor", () => {
272 assertStrictEquals(
273 Object.getPrototypeOf(new PropertyDescriptor({})),
274 PropertyDescriptor.prototype,
275 );
276 });
277
278 it("[[Construct]] throws for primitives", () => {
279 assertThrows(() => new PropertyDescriptor("failure"));
280 });
281
282 describe("::complete", () => {
283 it("[[Call]] completes a generic descriptor", () => {
284 const desc = {};
285 PropertyDescriptor.prototype.complete.call(desc);
286 assertEquals(desc, {
287 configurable: false,
288 enumerable: false,
289 value: undefined,
290 writable: false,
291 });
292 });
293
294 it("[[Call]] completes a data descriptor", () => {
295 const desc = { value: undefined };
296 PropertyDescriptor.prototype.complete.call(desc);
297 assertEquals(desc, {
298 configurable: false,
299 enumerable: false,
300 value: undefined,
301 writable: false,
302 });
303 });
304
305 it("[[Call]] completes an accessor descriptor", () => {
306 const desc = { get: undefined };
307 PropertyDescriptor.prototype.complete.call(desc);
308 assertEquals(desc, {
309 configurable: false,
310 enumerable: false,
311 get: undefined,
312 set: undefined,
313 });
314 });
315 });
316
317 describe("::isAccessorDescriptor", () => {
318 it("[[Get]] returns false for a generic descriptor", () => {
319 assertStrictEquals(
320 Reflect.get(
321 PropertyDescriptor.prototype,
322 "isAccessorDescriptor",
323 {},
324 ),
325 false,
326 );
327 });
328
329 it("[[Get]] returns false for a data descriptor", () => {
330 assertStrictEquals(
331 Reflect.get(
332 PropertyDescriptor.prototype,
333 "isAccessorDescriptor",
334 { value: undefined },
335 ),
336 false,
337 );
338 });
339
340 it("[[Get]] returns true for an accessor descriptor", () => {
341 assertStrictEquals(
342 Reflect.get(
343 PropertyDescriptor.prototype,
344 "isAccessorDescriptor",
345 { get: undefined },
346 ),
347 true,
348 );
349 });
350 });
351
352 describe("::isDataDescriptor", () => {
353 it("[[Get]] returns false for a generic descriptor", () => {
354 assertStrictEquals(
355 Reflect.get(
356 PropertyDescriptor.prototype,
357 "isDataDescriptor",
358 {},
359 ),
360 false,
361 );
362 });
363
364 it("[[Get]] returns true for a data descriptor", () => {
365 assertStrictEquals(
366 Reflect.get(
367 PropertyDescriptor.prototype,
368 "isDataDescriptor",
369 { value: undefined },
370 ),
371 true,
372 );
373 });
374
375 it("[[Get]] returns false for an accessor descriptor", () => {
376 assertStrictEquals(
377 Reflect.get(
378 PropertyDescriptor.prototype,
379 "isDataDescriptor",
380 { get: undefined },
381 ),
382 false,
383 );
384 });
385 });
386
387 describe("::isFullyPopulated", () => {
388 it("[[Get]] returns false for a generic descriptor", () => {
389 assertStrictEquals(
390 Reflect.get(
391 PropertyDescriptor.prototype,
392 "isFullyPopulated",
393 {},
394 ),
395 false,
396 );
397 });
398
399 it("[[Get]] returns false for a non‐fully‐populated data descriptor", () => {
400 assertStrictEquals(
401 Reflect.get(
402 PropertyDescriptor.prototype,
403 "isFullyPopulated",
404 { value: undefined },
405 ),
406 false,
407 );
408 });
409
410 it("[[Get]] returns true for a fully‐populated data descriptor", () => {
411 assertStrictEquals(
412 Reflect.get(PropertyDescriptor.prototype, "isFullyPopulated", {
413 configurable: true,
414 enumerable: true,
415 value: undefined,
416 writable: true,
417 }),
418 true,
419 );
420 });
421
422 it("[[Get]] returns false for a non‐fully‐populated accessor descriptor", () => {
423 assertStrictEquals(
424 Reflect.get(
425 PropertyDescriptor.prototype,
426 "isFullyPopulated",
427 { get: undefined },
428 ),
429 false,
430 );
431 });
432
433 it("[[Get]] returns true for a fully‐populated accessor descriptor", () => {
434 assertStrictEquals(
435 Reflect.get(PropertyDescriptor.prototype, "isFullyPopulated", {
436 configurable: true,
437 enumerable: true,
438 get: undefined,
439 set: undefined,
440 }),
441 true,
442 );
443 });
444 });
445
446 describe("::isGenericDescriptor", () => {
447 it("[[Get]] returns true for a generic descriptor", () => {
448 assertStrictEquals(
449 Reflect.get(
450 PropertyDescriptor.prototype,
451 "isGenericDescriptor",
452 {},
453 ),
454 true,
455 );
456 });
457
458 it("[[Get]] returns true for a data descriptor", () => {
459 assertStrictEquals(
460 Reflect.get(
461 PropertyDescriptor.prototype,
462 "isGenericDescriptor",
463 { value: undefined },
464 ),
465 false,
466 );
467 });
468
469 it("[[Get]] returns false for an accessor descriptor", () => {
470 assertStrictEquals(
471 Reflect.get(
472 PropertyDescriptor.prototype,
473 "isGenericDescriptor",
474 { get: undefined },
475 ),
476 false,
477 );
478 });
479 });
480
481 describe("~configurable", () => {
482 it("[[DefineOwnProperty]] coerces to a boolean", () => {
483 const desc = new PropertyDescriptor({});
484 Object.defineProperty(desc, "configurable", {});
485 assertStrictEquals(desc.configurable, false);
486 });
487
488 it("[[DefineOwnProperty]] throws for accessor properties", () => {
489 const desc = new PropertyDescriptor({});
490 assertThrows(() =>
491 Object.defineProperty(desc, "configurable", { get: undefined })
492 );
493 });
494
495 it("[[Set]] coerces to a boolean", () => {
496 const desc = new PropertyDescriptor({});
497 desc.configurable = undefined;
498 assertStrictEquals(desc.configurable, false);
499 });
500
501 it("[[Delete]] works", () => {
502 const desc = new PropertyDescriptor({ configurable: false });
503 delete desc.configurable;
504 assert(!("configurable" in desc));
505 });
506 });
507
508 describe("~enumerable", () => {
509 it("[[DefineOwnProperty]] coerces to a boolean", () => {
510 const desc = new PropertyDescriptor({});
511 Object.defineProperty(desc, "enumerable", {});
512 assertStrictEquals(desc.enumerable, false);
513 });
514
515 it("[[DefineOwnProperty]] throws for accessor properties", () => {
516 const desc = new PropertyDescriptor({});
517 assertThrows(() =>
518 Object.defineProperty(desc, "enumerable", { get: undefined })
519 );
520 });
521
522 it("[[Set]] coerces to a boolean", () => {
523 const desc = new PropertyDescriptor({});
524 desc.enumerable = undefined;
525 assertStrictEquals(desc.enumerable, false);
526 });
527
528 it("[[Delete]] works", () => {
529 const desc = new PropertyDescriptor({ enumerable: false });
530 delete desc.enumerable;
531 assert(!("enumerable" in desc));
532 });
533 });
534
535 describe("~get", () => {
536 it("[[DefineOwnProperty]] works", () => {
537 const desc = new PropertyDescriptor({});
538 Object.defineProperty(desc, "get", {});
539 assertStrictEquals(desc.get, undefined);
540 });
541
542 it("[[DefineOwnProperty]] throws for accessor properties", () => {
543 const desc = new PropertyDescriptor({});
544 assertThrows(() =>
545 Object.defineProperty(desc, "get", { get: undefined })
546 );
547 });
548
549 it("[[DefineOwnProperty]] throws if not callable or undefined", () => {
550 const desc = new PropertyDescriptor({});
551 assertThrows(
552 () => Object.defineProperty(desc, "get", { value: null }),
553 );
554 });
555
556 it("[[DefineOwnProperty]] throws if a data property is defined", () => {
557 const desc = new PropertyDescriptor({ value: undefined });
558 assertThrows(() => Object.defineProperty(desc, "get", {}));
559 });
560
561 it("[[Set]] works", () => {
562 const desc = new PropertyDescriptor({});
563 const fn = () => {};
564 desc.get = fn;
565 assertStrictEquals(desc.get, fn);
566 });
567
568 it("[[Set]] throws if not callable or undefined", () => {
569 const desc = new PropertyDescriptor({});
570 assertThrows(() => desc.get = null);
571 });
572
573 it("[[Set]] throws if a data property is defined", () => {
574 const desc = new PropertyDescriptor({ value: undefined });
575 assertThrows(() => desc.get = undefined);
576 });
577
578 it("[[Delete]] works", () => {
579 const desc = new PropertyDescriptor({ get: undefined });
580 delete desc.get;
581 assert(!("get" in desc));
582 });
583 });
584
585 describe("~set", () => {
586 it("[[DefineOwnProperty]] works", () => {
587 const desc = new PropertyDescriptor({});
588 Object.defineProperty(desc, "set", {});
589 assertStrictEquals(desc.set, undefined);
590 });
591
592 it("[[DefineOwnProperty]] throws for accessor properties", () => {
593 const desc = new PropertyDescriptor({});
594 assertThrows(() =>
595 Object.defineProperty(desc, "set", { get: undefined })
596 );
597 });
598
599 it("[[DefineOwnProperty]] throws if not callable or undefined", () => {
600 const desc = new PropertyDescriptor({});
601 assertThrows(
602 () => Object.defineProperty(desc, "set", { value: null }),
603 );
604 });
605
606 it("[[DefineOwnProperty]] throws if a data property is defined", () => {
607 const desc = new PropertyDescriptor({ value: undefined });
608 assertThrows(() => Object.defineProperty(desc, "set", {}));
609 });
610
611 it("[[Set]] works", () => {
612 const desc = new PropertyDescriptor({});
613 const fn = (_) => {};
614 desc.set = fn;
615 assertStrictEquals(desc.set, fn);
616 });
617
618 it("[[Set]] throws if not callable or undefined", () => {
619 const desc = new PropertyDescriptor({});
620 assertThrows(() => desc.set = null);
621 });
622
623 it("[[Set]] throws if a data property is defined", () => {
624 const desc = new PropertyDescriptor({ value: undefined });
625 assertThrows(() => desc.set = undefined);
626 });
627
628 it("[[Delete]] works", () => {
629 const desc = new PropertyDescriptor({ set: undefined });
630 delete desc.set;
631 assert(!("set" in desc));
632 });
633 });
634
635 describe("~value", () => {
636 it("[[DefineOwnProperty]] works", () => {
637 const desc = new PropertyDescriptor({});
638 Object.defineProperty(desc, "value", {});
639 assertStrictEquals(desc.value, undefined);
640 });
641
642 it("[[DefineOwnProperty]] throws for accessor properties", () => {
643 const desc = new PropertyDescriptor({});
644 assertThrows(() =>
645 Object.defineProperty(desc, "value", { get: undefined })
646 );
647 });
648
649 it("[[DefineOwnProperty]] throws if an accessor property is defined", () => {
650 const desc = new PropertyDescriptor({ get: undefined });
651 assertThrows(() => Object.defineProperty(desc, "value", {}));
652 });
653
654 it("[[Set]] works", () => {
655 const desc = new PropertyDescriptor({});
656 desc.value = "success";
657 assertStrictEquals(desc.value, "success");
658 });
659
660 it("[[Set]] throws if an accessor property is defined", () => {
661 const desc = new PropertyDescriptor({ get: undefined });
662 assertThrows(() => desc.value = null);
663 });
664
665 it("[[Delete]] works", () => {
666 const desc = new PropertyDescriptor({ value: undefined });
667 delete desc.value;
668 assert(!("value" in desc));
669 });
670 });
671
672 describe("~writable", () => {
673 it("[[DefineOwnProperty]] coerces to a boolean", () => {
674 const desc = new PropertyDescriptor({});
675 Object.defineProperty(desc, "writable", {});
676 assertStrictEquals(desc.writable, false);
677 });
678
679 it("[[DefineOwnProperty]] throws for accessor properties", () => {
680 const desc = new PropertyDescriptor({});
681 assertThrows(() =>
682 Object.defineProperty(desc, "writable", { get: undefined })
683 );
684 });
685
686 it("[[DefineOwnProperty]] throws if an accessor property is defined", () => {
687 const desc = new PropertyDescriptor({ get: undefined });
688 assertThrows(() => Object.defineProperty(desc, "writable", {}));
689 });
690
691 it("[[Set]] coerces to a boolean", () => {
692 const desc = new PropertyDescriptor({});
693 desc.writable = undefined;
694 assertStrictEquals(desc.writable, false);
695 });
696
697 it("[[Set]] throws if an accessor property is defined", () => {
698 const desc = new PropertyDescriptor({ get: undefined });
699 assertThrows(() => desc.writable = false);
700 });
701
702 it("[[Delete]] works", () => {
703 const desc = new PropertyDescriptor({ writable: false });
704 delete desc.writable;
705 assert(!("writable" in desc));
706 });
707 });
708 });
709
710 describe("defineOwnProperties", () => {
711 it("[[Call]] defines properties from the provided objects", () => {
712 const obj = {};
713 defineOwnProperties(obj, {
714 etaoin: {},
715 shrdlu: {},
716 }, { cmfwyp: {} });
717 assert("etaoin" in obj);
718 assert("shrdlu" in obj);
719 assert("cmfwyp" in obj);
720 });
721
722 it("[[Call]] overrides earlier declarations with later ones", () => {
723 const obj = { etaoin: undefined };
724 defineOwnProperties(obj, {
725 etaoin: { value: "failure" },
726 }, {
727 etaoin: { value: "success" },
728 });
729 assertStrictEquals(obj.etaoin, "success");
730 });
731
732 it("[[Call]] returns the provided object", () => {
733 const obj = {};
734 assertStrictEquals(defineOwnProperties(obj), obj);
735 });
736 });
737
738 describe("deleteOwnProperty", () => {
739 it("[[Call]] deletes the provided property on the provided object", () => {
740 const obj = { failure: undefined };
741 deleteOwnProperty(obj, "failure");
742 assert(!("failure" in obj));
743 });
744
745 it("[[Call]] does nothing if the property doesn’t exist", () => {
746 const obj = Object.freeze({});
747 deleteOwnProperty(obj, "failure");
748 assert(!("failure" in obj));
749 });
750
751 it("[[Call]] throws if the property can’t be deleted", () => {
752 const obj = Object.seal({ failure: undefined });
753 assertThrows(() => deleteOwnProperty(obj, "failure"));
754 });
755
756 it("[[Call]] returns the provided object", () => {
757 const obj = {};
758 assertStrictEquals(deleteOwnProperty(obj, ""), obj);
759 });
760 });
761
762 describe("frozenCopy", () => {
763 it("[[Call]] returns a frozen object", () => {
764 assert(
765 Object.isFrozen(
766 frozenCopy(Object.create(null), {
767 data: {
768 configurable: true,
769 enumerable: true,
770 value: undefined,
771 writable: true,
772 },
773 accessor: {
774 configurable: true,
775 enumerable: true,
776 get: undefined,
777 },
778 }),
779 ),
780 );
781 });
782
783 it("[[Call]] ignores non·enumerable properties", () => {
784 assertEquals(
785 frozenCopy(
786 Object.create(null, {
787 data: { value: undefined },
788 accessor: { get: undefined },
789 }),
790 ),
791 {},
792 );
793 });
794
795 it("[[Call]] preserves accessor properties", () => {
796 const properties = {
797 both: {
798 configurable: false,
799 enumerable: true,
800 get: () => {},
801 set: (_) => {},
802 },
803 empty: {
804 configurable: false,
805 enumerable: true,
806 get: undefined,
807 set: undefined,
808 },
809 getter: {
810 configurable: false,
811 enumerable: true,
812 get: () => {},
813 set: undefined,
814 },
815 setter: {
816 configurable: false,
817 enumerable: true,
818 get: undefined,
819 set: (_) => {},
820 },
821 };
822 assertEquals(
823 Object.getOwnPropertyDescriptors(
824 frozenCopy(Object.create(null, properties)),
825 ),
826 properties,
827 );
828 });
829
830 it("[[Call]] does not copy properties on the prototype", () => {
831 assert(
832 !("failure" in
833 frozenCopy(Object.create({ failure: undefined }), {
834 data: {
835 configurable: true,
836 value: undefined,
837 writable: true,
838 },
839 accessor: { configurable: true, get: undefined },
840 })),
841 );
842 });
843
844 it("[[Call]] uses the species of the constructor", () => {
845 const species = { prototype: {} };
846 assertStrictEquals(
847 Object.getPrototypeOf(
848 frozenCopy({}, { [Symbol.species]: species }),
849 ),
850 species.prototype,
851 );
852 });
853
854 it("[[Call]] uses constructor if no species is defined", () => {
855 const constructor = { [Symbol.species]: null, prototype: {} };
856 assertStrictEquals(
857 Object.getPrototypeOf(frozenCopy({}, constructor)),
858 constructor.prototype,
859 );
860 });
861
862 it("[[Call]] uses the constructor on the object if none is provided", () => {
863 const constructor = { [Symbol.species]: null, prototype: {} };
864 assertStrictEquals(
865 Object.getPrototypeOf(frozenCopy({ constructor })),
866 constructor.prototype,
867 );
868 });
869
870 it("[[Call]] allows a null constructor", () => {
871 assertStrictEquals(
872 Object.getPrototypeOf(frozenCopy({}, null)),
873 null,
874 );
875 });
876 });
877
878 describe("setPropertyValue", () => {
879 it("[[Call]] sets the provided property on the provided object", () => {
880 const obj = {};
881 setPropertyValue(obj, "success", true);
882 assertStrictEquals(obj.success, true);
883 });
884
885 it("[[Call]] calls setters", () => {
886 const setter = spy((_) => {});
887 const obj = Object.create(null, { success: { set: setter } });
888 setPropertyValue(obj, "success", true);
889 assertSpyCalls(setter, 1);
890 assertSpyCall(setter, 0, {
891 args: [true],
892 self: obj,
893 });
894 });
895
896 it("[[Call]] walks the prototype chain", () => {
897 const setter = spy((_) => {});
898 const obj = Object.create(
899 Object.create(null, { success: { set: setter } }),
900 );
901 setPropertyValue(obj, "success", true);
902 assertSpyCalls(setter, 1);
903 assertSpyCall(setter, 0, {
904 args: [true],
905 self: obj,
906 });
907 });
908
909 it("[[Call]] uses the provided receiver", () => {
910 const setter = spy((_) => {});
911 const obj = Object.create(null, { success: { set: setter } });
912 const receiver = {};
913 setPropertyValue(obj, "success", true, receiver);
914 assertSpyCalls(setter, 1);
915 assertSpyCall(setter, 0, {
916 args: [true],
917 self: receiver,
918 });
919 });
920
921 it("[[Call]] throws if the property can’t be set", () => {
922 const obj = Object.freeze({ failure: undefined });
923 assertThrows(() => setPropertyValue(obj, "failure", true));
924 });
925
926 it("[[Call]] returns the provided object", () => {
927 const obj = {};
928 assertStrictEquals(setPropertyValue(obj, "", undefined), obj);
929 });
930 });
931
932 describe("toObject", () => {
933 it("returns the input for objects", () => {
934 const obj = {};
935 assertStrictEquals(toObject(obj), obj);
936 });
937
938 it("returns a new object for nullish values", () => {
939 assertEquals(toObject(null), {});
940 assertEquals(toObject(void {}), {});
941 });
942
943 it("returns a wrapper object for other primitives", () => {
944 const sym = Symbol();
945 assertStrictEquals(typeof toObject(sym), "object");
946 assertStrictEquals(toObject(sym).valueOf(), sym);
947 });
948 });
949
950 describe("toPropertyKey", () => {
951 it("returns a string or symbol", () => {
952 const sym = Symbol();
953 assertStrictEquals(toPropertyKey(sym), sym);
954 assertStrictEquals(
955 toPropertyKey(new String("success")),
956 "success",
957 );
958 });
959
960 it("favours the `toString` representation", () => {
961 assertStrictEquals(
962 toPropertyKey({
963 toString() {
964 return "success";
965 },
966 valueOf() {
967 return "failure";
968 },
969 }),
970 "success",
971 );
972 });
973 });
This page took 0.173961 seconds and 5 git commands to generate.