]> Lady’s Gitweb - Pisces/blobdiff - object.test.js
Add methods for own entries and values to object.js
[Pisces] / object.test.js
index da890d38f3aa5cd1f7152706d5b02bd7085a4650..cba44b948824ba411ecb966ae3e80a1265a3f5c4 100644 (file)
@@ -1,7 +1,7 @@
 // ♓🌟 Piscēs ∷ object.test.js
 // ====================================================================
 //
-// Copyright © 2022 Lady [@ Lady’s Computer].
+// Copyright © 2022–2023 Lady [@ Lady’s Computer].
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -10,6 +10,7 @@
 import {
   assert,
   assertEquals,
+  assertNotStrictEquals,
   assertSpyCall,
   assertSpyCalls,
   assertStrictEquals,
@@ -19,248 +20,2146 @@ import {
   spy,
 } from "./dev-deps.js";
 import {
+  defineOwnDataProperty,
+  defineOwnNonenumerableDataProperty,
   defineOwnProperties,
+  defineOwnProperty,
   deleteOwnProperty,
+  freeze,
   frozenCopy,
-  PropertyDescriptor,
+  getMethod,
+  getOwnPropertyDescriptor,
+  getOwnPropertyDescriptors,
+  getOwnPropertyEntries,
+  getOwnPropertyKeys,
+  getOwnPropertyStrings,
+  getOwnPropertySymbols,
+  getOwnPropertyValue,
+  getOwnPropertyValues,
+  getPropertyValue,
+  getPrototype,
+  hasOwnProperty,
+  hasProperty,
+  isArraylikeObject,
+  isConcatSpreadableObject,
+  isExtensibleObject,
+  isPropertyDescriptorRecord,
+  isUnfrozenObject,
+  isUnsealedObject,
+  LazyLoader,
+  lengthOfArraylike,
+  namedEntries,
+  namedKeys,
+  namedValues,
+  objectCreate,
+  objectFromEntries,
+  preventExtensions,
+  seal,
   setPropertyValue,
+  setPropertyValues,
+  setPrototype,
   toObject,
-  toPropertyKey,
+  toPropertyDescriptorRecord,
 } from "./object.js";
 
-describe("PropertyDescriptor", () => {
-  it("[[Construct]] creates a new PropertyDescriptor", () => {
+describe("LazyLoader", () => {
+  const symbol = Symbol("foo");
+  const prototype = {};
+  const etaoinMethod = spy(() => "success");
+  const shrdluMethod = spy(() => "success");
+  const cmfwypMethod = spy(() => "success");
+  const vbgkqjMethod = spy(() => "success");
+  const methodsObject = Object.create(
+    prototype,
+    {
+      etaoin: {
+        configurable: false,
+        enumerable: true,
+        value: etaoinMethod,
+        writable: false,
+      },
+      shrdlu: {
+        configurable: true,
+        enumerable: false,
+        value: shrdluMethod,
+        writable: false,
+      },
+      cmfwyp: {
+        configurable: true,
+        enumerable: false,
+        get() {
+          return cmfwypMethod;
+        },
+      },
+      vbgkqj: {
+        configurable: false,
+        enumerable: true,
+        get() {
+          return vbgkqjMethod;
+        },
+        set(_) {},
+      },
+      xzfiflffffi: { configurable: true, enumerable: false, set(_) {} },
+      [symbol]: {
+        configurable: true,
+        enumerable: false,
+        value: "failure",
+        writable: true,
+      },
+    },
+  );
+
+  it("[[Call]] throws an error", () => {
+    assertThrows(() => LazyLoader({}));
+  });
+
+  it("[[Construct]] creates a new object which inherits from the correct prototype", () => {
     assertStrictEquals(
-      Object.getPrototypeOf(new PropertyDescriptor({})),
-      PropertyDescriptor.prototype,
+      Object.getPrototypeOf(new LazyLoader(methodsObject)),
+      prototype,
     );
   });
 
-  it("[[Construct]] throws for primitives", () => {
-    assertThrows(() => new PropertyDescriptor("failure"));
+  it("[[Construct]] creates a new object with the desired properties", () => {
+    assertEquals(
+      Reflect.ownKeys(new LazyLoader(methodsObject)),
+      ["etaoin", "shrdlu", "cmfwyp", "vbgkqj", "xzfiflffffi", symbol],
+    );
+  });
+
+  it("[[Construct]] creates a new object with configurable properties", () => {
+    assertEquals(
+      Object.fromEntries(
+        function* (ll) {
+          for (const key of Reflect.ownKeys(ll)) {
+            yield [
+              key,
+              Object.getOwnPropertyDescriptor(ll, key).configurable,
+            ];
+          }
+        }(new LazyLoader(methodsObject)),
+      ),
+      {
+        etaoin: true,
+        shrdlu: true,
+        cmfwyp: true,
+        vbgkqj: true,
+        xzfiflffffi: true,
+        [symbol]: true,
+      },
+    );
+  });
+
+  it("[[Construct]] creates a new object with the correct enumerability", () => {
+    assertEquals(
+      Object.fromEntries(
+        function* (ll) {
+          for (const key of Reflect.ownKeys(ll)) {
+            yield [
+              key,
+              Object.getOwnPropertyDescriptor(ll, key).enumerable,
+            ];
+          }
+        }(new LazyLoader(methodsObject)),
+      ),
+      {
+        etaoin: true,
+        shrdlu: false,
+        cmfwyp: false,
+        vbgkqj: true,
+        xzfiflffffi: false,
+        [symbol]: false,
+      },
+    );
+  });
+
+  it("[[Construct]] creates a new object with defined getters", () => {
+    assertEquals(
+      Object.fromEntries(
+        function* (ll) {
+          for (const key of Reflect.ownKeys(ll)) {
+            yield [
+              key,
+              Object.getOwnPropertyDescriptor(ll, key).get?.name,
+            ];
+          }
+        }(new LazyLoader(methodsObject)),
+      ),
+      {
+        etaoin: "get etaoin",
+        shrdlu: "get shrdlu",
+        cmfwyp: "get cmfwyp",
+        vbgkqj: "get vbgkqj",
+        xzfiflffffi: "get xzfiflffffi",
+        [symbol]: `get [${symbol.description}]`,
+      },
+    );
   });
 
-  describe("::complete", () => {
-    it("[[Call]] completes a generic descriptor", () => {
-      const desc = {};
-      PropertyDescriptor.prototype.complete.call(desc);
-      assertEquals(desc, {
+  it("[[Construct]] creates a new object with defined setters for writable properties only", () => {
+    assertEquals(
+      Object.fromEntries(
+        function* (ll) {
+          for (const key of Reflect.ownKeys(ll)) {
+            yield [
+              key,
+              Object.getOwnPropertyDescriptor(ll, key).set?.name,
+            ];
+          }
+        }(new LazyLoader(methodsObject)),
+      ),
+      {
+        etaoin: undefined,
+        shrdlu: undefined,
+        cmfwyp: undefined,
+        vbgkqj: undefined,
+        xzfiflffffi: undefined,
+        [symbol]: `set [${symbol.description}]`,
+      },
+    );
+  });
+
+  it("[[Construct]] creates a new object with correct getter behaviour", () => {
+    const ll = new LazyLoader(methodsObject);
+    ll.etaoin;
+    assertEquals(
+      Object.getOwnPropertyDescriptor(ll, "etaoin"),
+      {
         configurable: false,
+        enumerable: true,
+        value: "success",
+        writable: false,
+      },
+    );
+    assertSpyCalls(etaoinMethod, 1);
+    assertSpyCall(etaoinMethod, 0, {
+      args: [],
+      self: ll,
+      returned: "success",
+    });
+    ll.shrdlu;
+    assertEquals(
+      Object.getOwnPropertyDescriptor(ll, "shrdlu"),
+      {
+        configurable: true,
         enumerable: false,
-        value: undefined,
+        value: "success",
         writable: false,
-      });
+      },
+    );
+    assertSpyCalls(shrdluMethod, 1);
+    assertSpyCall(shrdluMethod, 0, {
+      args: [],
+      self: ll,
+      returned: "success",
     });
-
-    it("[[Call]] completes a data descriptor", () => {
-      const desc = { value: undefined };
-      PropertyDescriptor.prototype.complete.call(desc);
-      assertEquals(desc, {
-        configurable: false,
+    ll.cmfwyp;
+    assertEquals(
+      Object.getOwnPropertyDescriptor(ll, "cmfwyp"),
+      {
+        configurable: true,
         enumerable: false,
-        value: undefined,
+        value: "success",
         writable: false,
-      });
+      },
+    );
+    assertSpyCalls(cmfwypMethod, 1);
+    assertSpyCall(cmfwypMethod, 0, {
+      args: [],
+      self: ll,
+      returned: "success",
     });
-
-    it("[[Call]] completes an accessor descriptor", () => {
-      const desc = { get: undefined };
-      PropertyDescriptor.prototype.complete.call(desc);
-      assertEquals(desc, {
+    ll.vbgkqj;
+    assertEquals(
+      Object.getOwnPropertyDescriptor(ll, "vbgkqj"),
+      {
         configurable: false,
+        enumerable: true,
+        value: "success",
+        writable: false,
+      },
+    );
+    assertSpyCalls(vbgkqjMethod, 1);
+    assertSpyCall(vbgkqjMethod, 0, {
+      args: [],
+      self: ll,
+      returned: "success",
+    });
+    assertThrows(() => ll.xzfiflffffi);
+    assertThrows(() => ll[symbol]);
+  });
+
+  it("[[Construct]] creates a new object with correct setter behaviour", () => {
+    const ll = new LazyLoader(methodsObject);
+    ll[symbol] = "success";
+    assertEquals(
+      Object.getOwnPropertyDescriptor(ll, symbol),
+      {
+        configurable: true,
         enumerable: false,
-        get: undefined,
-        set: undefined,
-      });
+        value: "success",
+        writable: true,
+      },
+    );
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(LazyLoader.length, 1);
     });
   });
 
-  describe("::isAccessorDescriptor", () => {
-    it("[[Get]] returns false for a generic descriptor", () => {
-      assertStrictEquals(
-        Reflect.get(
-          PropertyDescriptor.prototype,
-          "isAccessorDescriptor",
-          {},
-        ),
-        false,
-      );
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(LazyLoader.name, "LazyLoader");
     });
+  });
+});
 
-    it("[[Get]] returns false for a data descriptor", () => {
-      assertStrictEquals(
-        Reflect.get(
-          PropertyDescriptor.prototype,
-          "isAccessorDescriptor",
-          { value: undefined },
-        ),
-        false,
-      );
+describe("defineOwnDataProperty", () => {
+  it("[[Call]] defines the property", () => {
+    const obj = {};
+    defineOwnDataProperty(obj, "etaoin", "success");
+    assert(Object.hasOwn(obj, "etaoin"));
+    assertStrictEquals(obj.etaoin, "success");
+  });
+
+  it("[[Call]] defines a configurable, enumerable, writable property", () => {
+    const obj = {};
+    defineOwnDataProperty(obj, "etaoin", "success");
+    assertEquals(
+      Object.getOwnPropertyDescriptor(obj, "etaoin"),
+      {
+        configurable: true,
+        enumerable: true,
+        value: "success",
+        writable: true,
+      },
+    );
+  });
+
+  it("[[Call]] returns the provided object", () => {
+    const obj = {};
+    assertStrictEquals(
+      defineOwnDataProperty(obj, "etaoin", null),
+      obj,
+    );
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new defineOwnDataProperty(obj, "etaoin", null));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(defineOwnDataProperty.length, 3);
     });
+  });
 
-    it("[[Get]] returns true for an accessor descriptor", () => {
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
       assertStrictEquals(
-        Reflect.get(
-          PropertyDescriptor.prototype,
-          "isAccessorDescriptor",
-          { get: undefined },
-        ),
-        true,
+        defineOwnDataProperty.name,
+        "defineOwnDataProperty",
       );
     });
   });
+});
 
-  describe("::isDataDescriptor", () => {
-    it("[[Get]] returns false for a generic descriptor", () => {
-      assertStrictEquals(
-        Reflect.get(
-          PropertyDescriptor.prototype,
-          "isDataDescriptor",
-          {},
-        ),
-        false,
-      );
+describe("defineOwnNonenumerableDataProperty", () => {
+  it("[[Call]] defines the property", () => {
+    const obj = {};
+    defineOwnNonenumerableDataProperty(obj, "etaoin", "success");
+    assert(Object.hasOwn(obj, "etaoin"));
+    assertStrictEquals(obj.etaoin, "success");
+  });
+
+  it("[[Call]] defines a configurable, non·enumerable, writable property", () => {
+    const obj = {};
+    defineOwnNonenumerableDataProperty(obj, "etaoin", "success");
+    assertEquals(
+      Object.getOwnPropertyDescriptor(obj, "etaoin"),
+      {
+        configurable: true,
+        enumerable: false,
+        value: "success",
+        writable: true,
+      },
+    );
+  });
+
+  it("[[Call]] returns the provided object", () => {
+    const obj = {};
+    assertStrictEquals(
+      defineOwnNonenumerableDataProperty(obj, "etaoin", null),
+      obj,
+    );
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() =>
+      new defineOwnNonenumerableDataProperty(obj, "etaoin", null)
+    );
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(defineOwnNonenumerableDataProperty.length, 3);
     });
+  });
 
-    it("[[Get]] returns true for a data descriptor", () => {
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
       assertStrictEquals(
-        Reflect.get(
-          PropertyDescriptor.prototype,
-          "isDataDescriptor",
-          { value: undefined },
-        ),
-        true,
+        defineOwnNonenumerableDataProperty.name,
+        "defineOwnNonenumerableDataProperty",
       );
     });
+  });
+});
+
+describe("defineOwnProperty", () => {
+  it("[[Call]] defines the property", () => {
+    const obj = {};
+    defineOwnProperty(obj, "etaoin", {});
+    assert(Object.hasOwn(obj, "etaoin"));
+  });
+
+  it("[[Call]] returns the provided object", () => {
+    const obj = {};
+    assertStrictEquals(defineOwnProperty(obj, "etaoin", {}), obj);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new defineOwnProperty(obj, "etaoin", {}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(defineOwnProperty.length, 3);
+    });
+  });
 
-    it("[[Get]] returns false for an accessor descriptor", () => {
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
       assertStrictEquals(
-        Reflect.get(
-          PropertyDescriptor.prototype,
-          "isDataDescriptor",
-          { get: undefined },
-        ),
-        false,
+        defineOwnProperty.name,
+        "defineOwnProperty",
       );
     });
   });
+});
 
-  describe("::isFullyPopulated", () => {
-    it("[[Get]] returns false for a generic descriptor", () => {
-      assertStrictEquals(
-        Reflect.get(
-          PropertyDescriptor.prototype,
-          "isFullyPopulated",
-          {},
-        ),
-        false,
-      );
+describe("defineOwnProperties", () => {
+  it("[[Call]] defines properties from the provided objects", () => {
+    const obj = {};
+    defineOwnProperties(obj, {
+      etaoin: {},
+      shrdlu: {},
+    }, { cmfwyp: {} });
+    assert("etaoin" in obj);
+    assert("shrdlu" in obj);
+    assert("cmfwyp" in obj);
+  });
+
+  it("[[Call]] overrides earlier declarations with later ones", () => {
+    const obj = { etaoin: undefined };
+    defineOwnProperties(obj, {
+      etaoin: { value: "failure" },
+    }, {
+      etaoin: { value: "success" },
     });
+    assertStrictEquals(obj.etaoin, "success");
+  });
 
-    it("[[Get]] returns false for a non‐fully‐populated data descriptor", () => {
-      assertStrictEquals(
-        Reflect.get(
-          PropertyDescriptor.prototype,
-          "isFullyPopulated",
-          { value: undefined },
-        ),
-        false,
-      );
+  it("[[Call]] returns the provided object", () => {
+    const obj = {};
+    assertStrictEquals(defineOwnProperties(obj), obj);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new defineOwnProperties({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(defineOwnProperties.length, 1);
     });
+  });
 
-    it("[[Get]] returns true for a fully‐populated data descriptor", () => {
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
       assertStrictEquals(
-        Reflect.get(PropertyDescriptor.prototype, "isFullyPopulated", {
-          configurable: true,
-          enumerable: true,
-          value: undefined,
-          writable: true,
-        }),
-        true,
+        defineOwnProperties.name,
+        "defineOwnProperties",
       );
     });
+  });
+});
 
-    it("[[Get]] returns false for a non‐fully‐populated accessor descriptor", () => {
-      assertStrictEquals(
-        Reflect.get(
-          PropertyDescriptor.prototype,
-          "isFullyPopulated",
-          { get: undefined },
-        ),
-        false,
-      );
+describe("deleteOwnProperty", () => {
+  it("[[Call]] deletes the provided property on the provided object", () => {
+    const obj = { failure: undefined };
+    deleteOwnProperty(obj, "failure");
+    assert(!("failure" in obj));
+  });
+
+  it("[[Call]] does nothing if the property doesn’t exist", () => {
+    const obj = Object.freeze({});
+    deleteOwnProperty(obj, "failure");
+    assert(!("failure" in obj));
+  });
+
+  it("[[Call]] throws if the property can’t be deleted", () => {
+    const obj = Object.seal({ failure: undefined });
+    assertThrows(() => deleteOwnProperty(obj, "failure"));
+  });
+
+  it("[[Call]] returns the provided object", () => {
+    const obj = {};
+    assertStrictEquals(deleteOwnProperty(obj, ""), obj);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new deleteOwnProperty({}, ""));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(deleteOwnProperty.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(deleteOwnProperty.name, "deleteOwnProperty");
     });
+  });
+});
 
-    it("[[Get]] returns true for a fully‐populated accessor descriptor", () => {
-      assertStrictEquals(
-        Reflect.get(PropertyDescriptor.prototype, "isFullyPopulated", {
-          configurable: true,
-          enumerable: true,
-          get: undefined,
-          set: undefined,
-        }),
-        true,
-      );
+describe("freeze", () => {
+  it("[[Call]] freezes the object", () => {
+    const obj = {};
+    freeze(obj);
+    assert(Object.isFrozen(obj));
+  });
+
+  it("[[Call]] returns the provided object", () => {
+    const obj = {};
+    assertStrictEquals(freeze(obj), obj);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new freeze({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(freeze.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(freeze.name, "freeze");
     });
   });
+});
+
+describe("frozenCopy", () => {
+  it("[[Call]] returns a frozen object", () => {
+    assert(
+      Object.isFrozen(
+        frozenCopy(Object.create(null), {
+          data: {
+            configurable: true,
+            enumerable: true,
+            value: undefined,
+            writable: true,
+          },
+          accessor: {
+            configurable: true,
+            enumerable: true,
+            get: undefined,
+          },
+        }),
+      ),
+    );
+  });
+
+  it("[[Call]] ignores non·enumerable properties", () => {
+    assertEquals(
+      frozenCopy(
+        Object.create(null, {
+          data: { value: undefined },
+          accessor: { get: undefined },
+        }),
+      ),
+      {},
+    );
+  });
+
+  it("[[Call]] preserves accessor properties", () => {
+    const properties = {
+      both: {
+        configurable: false,
+        enumerable: true,
+        get: () => {},
+        set: (_) => {},
+      },
+      empty: {
+        configurable: false,
+        enumerable: true,
+        get: undefined,
+        set: undefined,
+      },
+      getter: {
+        configurable: false,
+        enumerable: true,
+        get: () => {},
+        set: undefined,
+      },
+      setter: {
+        configurable: false,
+        enumerable: true,
+        get: undefined,
+        set: (_) => {},
+      },
+    };
+    assertEquals(
+      Object.getOwnPropertyDescriptors(
+        frozenCopy(Object.create(null, properties)),
+      ),
+      properties,
+    );
+  });
+
+  it("[[Call]] preserves data properties", () => {
+    const properties = {
+      implied: {
+        configurable: false,
+        enumerable: true,
+      },
+      writable: {
+        configurable: false,
+        enumerable: true,
+        value: "etaoin",
+        writable: true,
+      },
+      nonwritable: {
+        configurable: false,
+        enumerable: true,
+        value: "shrdlu",
+        writable: false,
+      },
+    };
+    assertEquals(
+      Object.getOwnPropertyDescriptors(
+        frozenCopy(Object.create(null, properties)),
+      ),
+      {
+        implied: {
+          ...properties.implied,
+          value: undefined,
+          writable: false,
+        },
+        writable: { ...properties.writable, writable: false },
+        nonwritable: properties.nonwritable,
+      },
+    );
+  });
+
+  it("[[Call]] does not copy properties on the prototype", () => {
+    assert(
+      !("failure" in
+        frozenCopy(Object.create({ failure: undefined }))),
+    );
+  });
+
+  it("[[Call]] uses the species of the constructor", () => {
+    const species = { prototype: {} };
+    assertStrictEquals(
+      Object.getPrototypeOf(
+        frozenCopy({}, { [Symbol.species]: species }),
+      ),
+      species.prototype,
+    );
+  });
+
+  it("[[Call]] uses constructor if no species is defined", () => {
+    const constructor = { [Symbol.species]: null, prototype: {} };
+    assertStrictEquals(
+      Object.getPrototypeOf(frozenCopy({}, constructor)),
+      constructor.prototype,
+    );
+  });
+
+  it("[[Call]] uses the constructor on the object if none is provided", () => {
+    const constructor = { [Symbol.species]: null, prototype: {} };
+    assertStrictEquals(
+      Object.getPrototypeOf(frozenCopy({ constructor })),
+      constructor.prototype,
+    );
+  });
+
+  it("[[Call]] allows a null constructor", () => {
+    assertStrictEquals(
+      Object.getPrototypeOf(frozenCopy({}, null)),
+      null,
+    );
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new frozenCopy({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(frozenCopy.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(frozenCopy.name, "frozenCopy");
+    });
+  });
+});
+
+describe("getMethod", () => {
+  it("[[Call]] gets a method", () => {
+    const method = () => {};
+    assertStrictEquals(getMethod({ method }, "method"), method);
+  });
+
+  it("[[Call]] works for values coercible to objects", () => {
+    assertEquals(getMethod("", "toString"), String.prototype.toString);
+  });
+
+  it("[[Call]] throws for null and undefined", () => {
+    assertThrows(() => getMethod(null, "valueOf"));
+    assertThrows(() => getMethod(undefined, "valueOf"));
+  });
+
+  it("[[Call]] throws if the resulting value isn’t callable", () => {
+    assertThrows(() => getMethod({ "failure": true }, "failure"));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new getMethod({ method() {} }, "method"));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(getMethod.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(getMethod.name, "getMethod");
+    });
+  });
+});
+
+describe("getOwnPropertyDescriptor", () => {
+  it("[[Call]] gets the descriptor", () => {
+    assertEquals(
+      getOwnPropertyDescriptor({ success: true }, "success"),
+      {
+        configurable: true,
+        enumerable: true,
+        value: true,
+        writable: true,
+      },
+    );
+  });
+
+  it("[[Call]] returns undefined for non‐own properties", () => {
+    assertStrictEquals(
+      getOwnPropertyDescriptor({}, "valueOf"),
+      undefined,
+    );
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new getOwnPropertyDescriptor({}, ""));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(getOwnPropertyDescriptor.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(
+        getOwnPropertyDescriptor.name,
+        "getOwnPropertyDescriptor",
+      );
+    });
+  });
+});
+
+describe("getOwnPropertyDescriptors", () => {
+  it("[[Call]] gets the descriptors", () => {
+    assertEquals(
+      getOwnPropertyDescriptors({ success: true, etaoin: "shrdlu" }),
+      {
+        success: {
+          configurable: true,
+          enumerable: true,
+          value: true,
+          writable: true,
+        },
+        etaoin: {
+          configurable: true,
+          enumerable: true,
+          value: "shrdlu",
+          writable: true,
+        },
+      },
+    );
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new getOwnPropertyDescriptors({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(getOwnPropertyDescriptors.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(
+        getOwnPropertyDescriptors.name,
+        "getOwnPropertyDescriptors",
+      );
+    });
+  });
+});
+
+describe("getOwnPropertyEntries", () => {
+  it("[[Call]] gets own (but not inherited) property entries", () => {
+    assertEquals(
+      getOwnPropertyEntries({ success: true }),
+      [["success", true]],
+    );
+  });
+
+  it("[[Call]] works for values coercible to objects", () => {
+    assertEquals(
+      getOwnPropertyEntries("foo"),
+      [["0", "f"], ["1", "o"], ["2", "o"], ["length", 3]],
+    );
+  });
+
+  it("[[Call]] uses the provided receiver", () => {
+    const target = {};
+    assertEquals(
+      getOwnPropertyEntries({
+        get success() {
+          return this;
+        },
+      }, target),
+      [["success", target]],
+    );
+  });
+
+  it("[[Call]] throws for null and undefined", () => {
+    assertThrows(() => getOwnPropertyEntries(null));
+    assertThrows(() => getOwnPropertyEntries(undefined));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new getOwnPropertyEntries({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(getOwnPropertyEntries.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(
+        getOwnPropertyEntries.name,
+        "getOwnPropertyEntries",
+      );
+    });
+  });
+});
+
+describe("getOwnPropertyKeys", () => {
+  it("[[Call]] gets own (but not inherited) property keys", () => {
+    assertEquals(getOwnPropertyKeys({ success: true }), ["success"]);
+  });
+
+  it("[[Call]] works for values coercible to objects", () => {
+    assertEquals(getOwnPropertyKeys("foo"), ["0", "1", "2", "length"]);
+  });
+
+  it("[[Call]] throws for null and undefined", () => {
+    assertThrows(() => getOwnPropertyKeys(null));
+    assertThrows(() => getOwnPropertyKeys(undefined));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new getOwnPropertyKeys({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(getOwnPropertyKeys.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(
+        getOwnPropertyKeys.name,
+        "getOwnPropertyKeys",
+      );
+    });
+  });
+});
+
+describe("getOwnPropertyStrings", () => {
+  it("[[Call]] gets own string keys", () => {
+    assertEquals(getOwnPropertyStrings({ success: true }), [
+      "success",
+    ]);
+  });
+
+  it("[[Call]] works for values coercible to objects", () => {
+    assertEquals(getOwnPropertyStrings("foo"), [
+      "0",
+      "1",
+      "2",
+      "length",
+    ]);
+  });
+
+  it("[[Call]] throws for null and undefined", () => {
+    assertThrows(() => getOwnPropertyStrings(null));
+    assertThrows(() => getOwnPropertyStrings(undefined));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new getOwnPropertyStrings({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(getOwnPropertyStrings.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(
+        getOwnPropertyStrings.name,
+        "getOwnPropertyStrings",
+      );
+    });
+  });
+});
+
+describe("getOwnPropertySymbols", () => {
+  it("[[Call]] gets own symbol keys", () => {
+    const sym = Symbol();
+    assertEquals(getOwnPropertySymbols({ [sym]: true }), [sym]);
+  });
+
+  it("[[Call]] works for values coercible to objects", () => {
+    assertEquals(getOwnPropertySymbols("foo"), []);
+  });
+
+  it("[[Call]] throws for null and undefined", () => {
+    assertThrows(() => getOwnPropertySymbols(null));
+    assertThrows(() => getOwnPropertySymbols(undefined));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new getOwnPropertySymbols({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(getOwnPropertySymbols.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(
+        getOwnPropertySymbols.name,
+        "getOwnPropertySymbols",
+      );
+    });
+  });
+});
+
+describe("getOwnPropertyValue", () => {
+  it("[[Call]] gets the own property value", () => {
+    assertStrictEquals(
+      getOwnPropertyValue({ success: true }, "success"),
+      true,
+    );
+  });
+
+  it("[[Call]] returns undefined for non‐own properties", () => {
+    assertStrictEquals(
+      getOwnPropertyValue(Object.create({ success: true }), "success"),
+      undefined,
+    );
+  });
+
+  it("[[Call]] works for values coercible to objects", () => {
+    assertStrictEquals(getOwnPropertyValue("foo", "length"), 3);
+  });
+
+  it("[[Call]] uses the provided receiver", () => {
+    const target = {};
+    assertStrictEquals(
+      getOwnPropertyValue(
+        {
+          get success() {
+            return this;
+          },
+        },
+        "success",
+        target,
+      ),
+      target,
+    );
+  });
+
+  it("[[Call]] throws for null and undefined", () => {
+    assertThrows(() => getOwnPropertyValue(null));
+    assertThrows(() => getOwnPropertyValue(undefined));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new getOwnPropertyValue({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(getOwnPropertyValue.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(
+        getOwnPropertyValue.name,
+        "getOwnPropertyValue",
+      );
+    });
+  });
+});
+
+describe("getOwnPropertyValues", () => {
+  it("[[Call]] gets own (but not inherited) property values", () => {
+    assertEquals(getOwnPropertyValues({ success: true }), [true]);
+  });
+
+  it("[[Call]] works for values coercible to objects", () => {
+    assertEquals(
+      getOwnPropertyValues("foo"),
+      ["f", "o", "o", 3],
+    );
+  });
+
+  it("[[Call]] uses the provided receiver", () => {
+    const target = {};
+    assertEquals(
+      getOwnPropertyValues({
+        get success() {
+          return this;
+        },
+      }, target),
+      [target],
+    );
+  });
+
+  it("[[Call]] throws for null and undefined", () => {
+    assertThrows(() => getOwnPropertyValues(null));
+    assertThrows(() => getOwnPropertyValues(undefined));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new getOwnPropertyValues({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(getOwnPropertyValues.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(
+        getOwnPropertyValues.name,
+        "getOwnPropertyValues",
+      );
+    });
+  });
+});
+
+describe("getPropertyValue", () => {
+  it("[[Call]] gets property values on the provided object", () => {
+    assertStrictEquals(
+      getPropertyValue({ success: true }, "success"),
+      true,
+    );
+  });
+
+  it("[[Call]] works for values coercible to objects", () => {
+    assertStrictEquals(
+      getPropertyValue("", "toString"),
+      String.prototype.toString,
+    );
+  });
+
+  it("[[Call]] throws for null and undefined", () => {
+    assertThrows(() => getPropertyValue(null, "valueOf"));
+    assertThrows(() => getPropertyValue(undefined, "valueOf"));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new getPropertyValue({}, "valueOf"));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(getPropertyValue.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(getPropertyValue.name, "getPropertyValue");
+    });
+  });
+});
+
+describe("getPrototype", () => {
+  it("[[Call]] gets object prototypes", () => {
+    assertStrictEquals(getPrototype({}), Object.prototype);
+    const proto = {};
+    assertStrictEquals(getPrototype(Object.create(proto)), proto);
+  });
+
+  it("[[Call]] gets null prototypes", () => {
+    assertStrictEquals(getPrototype(Object.create(null)), null);
+  });
+
+  it("[[Call]] gets prototypes for coercible primitives", () => {
+    assertStrictEquals(getPrototype(1), Number.prototype);
+    assertStrictEquals(getPrototype(Symbol()), Symbol.prototype);
+  });
+
+  it("[[Call]] throws for null and undefined", () => {
+    assertThrows(() => getPrototype(null));
+    assertThrows(() => getPrototype(undefined));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new getPrototype({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(getPrototype.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(getPrototype.name, "getPrototype");
+    });
+  });
+});
+
+describe("hasProperty", () => {
+  it("[[Call]] gets whether a property exists on the provided object", () => {
+    assertStrictEquals(
+      hasProperty({ success: "etaoin" }, "success"),
+      true,
+    );
+    assertStrictEquals(hasProperty({}, "hasOwnProperty"), true);
+  });
+
+  it("[[Call]] works for values coercible to objects", () => {
+    assertStrictEquals(hasProperty("", "length"), true);
+    assertStrictEquals(hasProperty("", "toString"), true);
+  });
+
+  it("[[Call]] throws for null and undefined", () => {
+    assertThrows(() => hasProperty(null, "valueOf"));
+    assertThrows(() => hasProperty(undefined, "valueOf"));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new hasProperty({}, "valueOf"));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(hasProperty.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(hasProperty.name, "hasProperty");
+    });
+  });
+});
+
+describe("hasOwnProperty", () => {
+  it("[[Call]] gets whether an own property exists on the provided object", () => {
+    assertStrictEquals(
+      hasOwnProperty({ success: "etaoin" }, "success"),
+      true,
+    );
+    assertStrictEquals(hasOwnProperty({}, "hasOwnProperty"), false);
+  });
+
+  it("[[Call]] works for values coercible to objects", () => {
+    assertStrictEquals(hasOwnProperty("", "length"), true);
+    assertStrictEquals(hasOwnProperty("", "toString"), false);
+  });
+
+  it("[[Call]] throws for null and undefined", () => {
+    assertThrows(() => hasOwnProperty(null, "valueOf"));
+    assertThrows(() => hasOwnProperty(undefined, "valueOf"));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new hasOwnProperty({}, "valueOf"));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(hasOwnProperty.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(hasOwnProperty.name, "hasOwnProperty");
+    });
+  });
+});
+
+describe("isArraylikeObject", () => {
+  it("[[Call]] returns false for primitives", () => {
+    assertStrictEquals(isArraylikeObject("failure"), false);
+  });
+
+  it("[[Call]] returns false if length throws", () => {
+    assertStrictEquals(
+      isArraylikeObject({
+        get length() {
+          throw void {};
+        },
+      }),
+      false,
+    );
+  });
+
+  it("[[Call]] returns false if length is not a number and cannot be converted to one", () => {
+    assertStrictEquals(isArraylikeObject({ length: 1n }), false);
+  });
+
+  it("[[Call]] returns true if length is convertable to a number", () => {
+    assertStrictEquals(isArraylikeObject({ length: -0 }), true);
+    assertStrictEquals(isArraylikeObject({ length: 1 }), true);
+    assertStrictEquals(isArraylikeObject({ length: -1.25 }), true);
+    assertStrictEquals(
+      isArraylikeObject({ length: 9007199254740992 }),
+      true,
+    );
+    assertStrictEquals(isArraylikeObject({ length: Infinity }), true);
+    assertStrictEquals(isArraylikeObject({ length: "success" }), true);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new isArraylikeObject({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(isArraylikeObject.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(
+        isArraylikeObject.name,
+        "isArraylikeObject",
+      );
+    });
+  });
+});
+
+describe("isConcatSpreadableObject", () => {
+  it("[[Call]] returns false for primitives", () => {
+    assertStrictEquals(isConcatSpreadableObject("failure"), false);
+  });
+
+  it("[[Call]] returns false if [Symbol.isConcatSpreadable] is null or false", () => {
+    assertStrictEquals(
+      isConcatSpreadableObject(
+        Object.assign([], { [Symbol.isConcatSpreadable]: null }),
+      ),
+      false,
+    );
+    assertStrictEquals(
+      isConcatSpreadableObject(
+        Object.assign([], { [Symbol.isConcatSpreadable]: false }),
+      ),
+      false,
+    );
+  });
+
+  it("[[Call]] returns true if [Symbol.isConcatSpreadable] is undefined and the object is an array", () => {
+    assertStrictEquals(
+      isConcatSpreadableObject(
+        Object.assign([], { [Symbol.isConcatSpreadable]: undefined }),
+      ),
+      true,
+    );
+  });
+
+  it("[[Call]] returns true if [Symbol.isConcatSpreadable] is true", () => {
+    assertStrictEquals(
+      isConcatSpreadableObject({ [Symbol.isConcatSpreadable]: true }),
+      true,
+    );
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new isConcatSpreadableObject({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(isConcatSpreadableObject.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(
+        isConcatSpreadableObject.name,
+        "isConcatSpreadableObject",
+      );
+    });
+  });
+});
+
+describe("isExtensibleObject", () => {
+  it("[[Call]] returns true for extensible objects", () => {
+    assertStrictEquals(isExtensibleObject({}), true);
+  });
+
+  it("[[Call]] returns false for coercible primitives", () => {
+    assertStrictEquals(isExtensibleObject(1), false);
+    assertStrictEquals(isExtensibleObject(Symbol()), false);
+  });
+
+  it("[[Call]] returns false for non·extensible objects", () => {
+    assertStrictEquals(
+      isExtensibleObject(Object.preventExtensions({})),
+      false,
+    );
+  });
+
+  it("[[Call]] returns false for null and undefined", () => {
+    assertStrictEquals(isExtensibleObject(null), false);
+    assertStrictEquals(isExtensibleObject(undefined), false);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new isExtensibleObject({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(isExtensibleObject.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(
+        isExtensibleObject.name,
+        "isExtensibleObject",
+      );
+    });
+  });
+});
+
+describe("isPropertyDescriptorRecord", () => {
+  it("[[Call]] returns true for objects created by toPropertyDescriptorRecord", () => {
+    assertStrictEquals(
+      isPropertyDescriptorRecord(toPropertyDescriptorRecord({})),
+      true,
+    );
+  });
+
+  it("[[Get]] returns false for other objects", () => {
+    assertStrictEquals(
+      isPropertyDescriptorRecord(Object.create(null)),
+      false,
+    );
+  });
+
+  it("[[Get]] returns false for undefined", () => {
+    assertStrictEquals(isPropertyDescriptorRecord(undefined), false);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new isPropertyDescriptorRecord({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(isPropertyDescriptorRecord.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(
+        isPropertyDescriptorRecord.name,
+        "isPropertyDescriptorRecord",
+      );
+    });
+  });
+});
+
+describe("isUnfrozenObject", () => {
+  it("[[Call]] returns true for unfrozen objects", () => {
+    assertStrictEquals(isUnfrozenObject({}), true);
+  });
+
+  it("[[Call]] returns false for coercible primitives", () => {
+    assertStrictEquals(isUnfrozenObject(1), false);
+    assertStrictEquals(isUnfrozenObject(Symbol()), false);
+  });
+
+  it("[[Call]] returns false for frozen objects", () => {
+    assertStrictEquals(isUnfrozenObject(Object.freeze({})), false);
+  });
+
+  it("[[Call]] returns false for null and undefined", () => {
+    assertStrictEquals(isUnfrozenObject(null), false);
+    assertStrictEquals(isUnfrozenObject(undefined), false);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new isUnfrozenObject({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(isUnfrozenObject.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(isUnfrozenObject.name, "isUnfrozenObject");
+    });
+  });
+});
+
+describe("isUnsealedObject", () => {
+  it("[[Call]] returns true for unsealed objects", () => {
+    assertStrictEquals(isUnsealedObject({}), true);
+  });
+
+  it("[[Call]] returns false for coercible primitives", () => {
+    assertStrictEquals(isUnsealedObject(1), false);
+    assertStrictEquals(isUnsealedObject(Symbol()), false);
+  });
+
+  it("[[Call]] returns false for sealed objects", () => {
+    assertStrictEquals(isUnsealedObject(Object.seal({})), false);
+  });
+
+  it("[[Call]] returns false for null and undefined", () => {
+    assertStrictEquals(isUnsealedObject(null), false);
+    assertStrictEquals(isUnsealedObject(undefined), false);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new isUnsealedObject({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(isUnsealedObject.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(isUnsealedObject.name, "isUnsealedObject");
+    });
+  });
+});
+
+describe("lengthOfArraylike", () => {
+  it("[[Call]] returns the length", () => {
+    assertStrictEquals(
+      lengthOfArraylike({ length: 9007199254740991 }),
+      9007199254740991,
+    );
+  });
+
+  it("[[Call]] returns a non·nan result", () => {
+    assertStrictEquals(lengthOfArraylike({ length: NaN }), 0);
+    assertStrictEquals(lengthOfArraylike({ length: "failure" }), 0);
+  });
+
+  it("[[Call]] returns an integral result", () => {
+    assertStrictEquals(lengthOfArraylike({ length: 0.25 }), 0);
+    assertStrictEquals(lengthOfArraylike({ length: 1.1 }), 1);
+  });
+
+  it("[[Call]] returns a result greater than or equal to zero", () => {
+    assertStrictEquals(lengthOfArraylike({ length: -0 }), 0);
+    assertStrictEquals(lengthOfArraylike({ length: -1 }), 0);
+    assertStrictEquals(lengthOfArraylike({ length: -Infinity }), 0);
+  });
+
+  it("[[Call]] returns a result less than 2 ** 53", () => {
+    assertStrictEquals(
+      lengthOfArraylike({ length: 9007199254740992 }),
+      9007199254740991,
+    );
+    assertStrictEquals(
+      lengthOfArraylike({ length: Infinity }),
+      9007199254740991,
+    );
+  });
+
+  it("[[Call]] does not require an object argument", () => {
+    assertStrictEquals(lengthOfArraylike("string"), 6);
+    assertStrictEquals(lengthOfArraylike(Symbol()), 0);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new lengthOfArraylike(""));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(lengthOfArraylike.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(lengthOfArraylike.name, "lengthOfArraylike");
+    });
+  });
+});
+
+describe("namedEntries", () => {
+  it("[[Call]] gets named entries", () => {
+    assertEquals(namedEntries({ success: true }), [["success", true]]);
+  });
+
+  it("[[Call]] works for values coercible to objects", () => {
+    assertEquals(namedEntries("foo"), [
+      ["0", "f"],
+      ["1", "o"],
+      ["2", "o"],
+    ]);
+  });
+
+  it("[[Call]] throws for null and undefined", () => {
+    assertThrows(() => namedEntries(null));
+    assertThrows(() => namedEntries(undefined));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new namedEntries({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(namedEntries.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(namedEntries.name, "namedEntries");
+    });
+  });
+});
+
+describe("namedKeys", () => {
+  it("[[Call]] gets named keys", () => {
+    assertEquals(namedKeys({ success: true }), ["success"]);
+  });
+
+  it("[[Call]] works for values coercible to objects", () => {
+    assertEquals(namedKeys("foo"), [
+      "0",
+      "1",
+      "2",
+    ]);
+  });
+
+  it("[[Call]] throws for null and undefined", () => {
+    assertThrows(() => namedKeys(null));
+    assertThrows(() => namedKeys(undefined));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new namedKeys({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(namedKeys.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(namedKeys.name, "namedKeys");
+    });
+  });
+});
+
+describe("namedValues", () => {
+  it("[[Call]] gets named values", () => {
+    assertEquals(namedValues({ success: true }), [true]);
+  });
+
+  it("[[Call]] works for values coercible to objects", () => {
+    assertEquals(namedValues("foo"), [
+      "f",
+      "o",
+      "o",
+    ]);
+  });
+
+  it("[[Call]] throws for null and undefined", () => {
+    assertThrows(() => namedValues(null));
+    assertThrows(() => namedValues(undefined));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new namedValues({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(namedValues.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(namedValues.name, "namedValues");
+    });
+  });
+});
+
+describe("objectCreate", () => {
+  it("[[Call]] creates an object", () => {
+    const obj = objectCreate(null);
+    assertStrictEquals(Object(obj), obj);
+  });
+
+  it("[[Call]] correctly sets the prototype", () => {
+    const proto = {};
+    assertStrictEquals(
+      Object.getPrototypeOf(objectCreate(proto)),
+      proto,
+    );
+    assertStrictEquals(
+      Object.getPrototypeOf(objectCreate(null)),
+      null,
+    );
+  });
+
+  it("[[Call]] correctly sets own properties", () => {
+    assertEquals(
+      Object.getOwnPropertyDescriptors(
+        objectCreate(null, { success: { value: true } }),
+      ),
+      {
+        success: {
+          configurable: false,
+          enumerable: false,
+          value: true,
+          writable: false,
+        },
+      },
+    );
+  });
+
+  it("[[Call]] throws for coercible primitives", () => {
+    assertThrows(() => objectCreate(1));
+    assertThrows(() => objectCreate(Symbol()));
+  });
+
+  it("[[Call]] throws for undefined", () => {
+    assertThrows(() => objectCreate(undefined));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new objectCreate({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(objectCreate.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(objectCreate.name, "objectCreate");
+    });
+  });
+});
+
+describe("objectFromEntries", () => {
+  it("[[Call]] creates an object", () => {
+    const obj = objectFromEntries([]);
+    assertStrictEquals(Object(obj), obj);
+  });
+
+  it("[[Call]] correctly sets the prototype", () => {
+    assertStrictEquals(
+      Object.getPrototypeOf(objectFromEntries([])),
+      Object.prototype,
+    );
+  });
+
+  it("[[Call]] correctly sets own properties", () => {
+    assertEquals(
+      Object.entries(objectFromEntries([["success", true]])),
+      [["success", true]],
+    );
+  });
+
+  it("[[Call]] throws if the argument is not a nested arraylike", () => {
+    assertThrows(() => objectFromEntries(1));
+    assertThrows(() => objectFromEntries(Symbol()));
+    assertThrows(() => objectFromEntries(null));
+    assertThrows(() => objectFromEntries(undefined));
+    assertThrows(() => objectFromEntries({}));
+    assertThrows(() => objectFromEntries([undefined]));
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new objectFromEntries([]));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(objectFromEntries.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(objectFromEntries.name, "objectFromEntries");
+    });
+  });
+});
+
+describe("preventExtensions", () => {
+  it("[[Call]] prevents extensions on the object", () => {
+    const obj = {};
+    preventExtensions(obj);
+    assert(!Object.isExtensible(obj));
+  });
+
+  it("[[Call]] returns the provided object", () => {
+    const obj = {};
+    assertStrictEquals(preventExtensions(obj), obj);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new preventExtensions({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(preventExtensions.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(preventExtensions.name, "preventExtensions");
+    });
+  });
+});
+
+describe("seal", () => {
+  it("[[Call]] seals the object", () => {
+    const obj = {};
+    seal(obj);
+    assert(Object.isSealed(obj));
+  });
+
+  it("[[Call]] returns the provided object", () => {
+    const obj = {};
+    assertStrictEquals(seal(obj), obj);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new seal({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(seal.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(seal.name, "seal");
+    });
+  });
+});
+
+describe("setPropertyValue", () => {
+  it("[[Call]] sets the provided property on the provided object", () => {
+    const obj = {};
+    setPropertyValue(obj, "success", true);
+    assertStrictEquals(obj.success, true);
+  });
+
+  it("[[Call]] calls setters", () => {
+    const setter = spy((_) => {});
+    const obj = Object.create(null, { success: { set: setter } });
+    setPropertyValue(obj, "success", true);
+    assertSpyCalls(setter, 1);
+    assertSpyCall(setter, 0, {
+      args: [true],
+      self: obj,
+    });
+  });
+
+  it("[[Call]] walks the prototype chain", () => {
+    const setter = spy((_) => {});
+    const obj = Object.create(
+      Object.create(null, { success: { set: setter } }),
+    );
+    setPropertyValue(obj, "success", true);
+    assertSpyCalls(setter, 1);
+    assertSpyCall(setter, 0, {
+      args: [true],
+      self: obj,
+    });
+  });
+
+  it("[[Call]] uses the provided receiver", () => {
+    const setter = spy((_) => {});
+    const obj = Object.create(null, { success: { set: setter } });
+    const receiver = {};
+    setPropertyValue(obj, "success", true, receiver);
+    assertSpyCalls(setter, 1);
+    assertSpyCall(setter, 0, {
+      args: [true],
+      self: receiver,
+    });
+  });
+
+  it("[[Call]] throws if the property can’t be set", () => {
+    const obj = Object.freeze({ failure: undefined });
+    assertThrows(() => setPropertyValue(obj, "failure", true));
+  });
+
+  it("[[Call]] returns the provided object", () => {
+    const obj = {};
+    assertStrictEquals(setPropertyValue(obj, "", undefined), obj);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new setPropertyValue({}, "", undefined));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(setPropertyValue.length, 3);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(setPropertyValue.name, "setPropertyValue");
+    });
+  });
+});
+
+describe("setPropertyValues", () => {
+  it("[[Call]] sets the provided properties on the provided object", () => {
+    const obj = {};
+    setPropertyValues(obj, { success: true, all: "good" });
+    assertStrictEquals(obj.success, true);
+    assertStrictEquals(obj.all, "good");
+  });
+
+  it("[[Call]] can take multiple objects", () => {
+    const obj = {};
+    setPropertyValues(
+      obj,
+      { success: false, all: "good" },
+      { success: true },
+    );
+    assertStrictEquals(obj.success, true);
+    assertStrictEquals(obj.all, "good");
+  });
+
+  it("[[Call]] ignores nullish arguments", () => {
+    const obj = {};
+    setPropertyValues(obj, null, undefined, { success: true });
+    assertStrictEquals(obj.success, true);
+  });
+
+  it("[[Call]] calls setters", () => {
+    const setter = spy((_) => {});
+    const obj = Object.create(null, { success: { set: setter } });
+    setPropertyValues(obj, { success: true });
+    assertSpyCalls(setter, 1);
+    assertSpyCall(setter, 0, {
+      args: [true],
+      self: obj,
+    });
+  });
+
+  it("[[Call]] calls setters multiple times if property appears more than once", () => {
+    const setter = spy((_) => {});
+    const obj = Object.create(null, { success: { set: setter } });
+    setPropertyValues(obj, { success: false }, { success: true });
+    assertSpyCalls(setter, 2);
+    assertSpyCall(setter, 0, {
+      args: [false],
+      self: obj,
+    });
+    assertSpyCall(setter, 1, {
+      args: [true],
+      self: obj,
+    });
+  });
+
+  it("[[Call]] walks the prototype chain", () => {
+    const setter = spy((_) => {});
+    const obj = Object.create(
+      Object.create(null, { success: { set: setter } }),
+    );
+    setPropertyValues(obj, { success: true });
+    assertSpyCalls(setter, 1);
+    assertSpyCall(setter, 0, {
+      args: [true],
+      self: obj,
+    });
+  });
+
+  it("[[Call]] throws if the property can’t be set", () => {
+    const obj = Object.freeze({ failure: undefined });
+    assertThrows(() => setPropertyValues(obj, { failure: true }));
+  });
+
+  it("[[Call]] returns the provided object", () => {
+    const obj = {};
+    assertStrictEquals(setPropertyValues(obj, { "": undefined }), obj);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new setPropertyValues(obj, { "": undefined }));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(setPropertyValues.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(setPropertyValues.name, "setPropertyValues");
+    });
+  });
+});
+
+describe("setPrototype", () => {
+  it("[[Call]] sets object prototypes", () => {
+    const obj = {};
+    const proto = {};
+    setPrototype(obj, proto);
+    assertStrictEquals(Object.getPrototypeOf(obj), proto);
+  });
+
+  it("[[Call]] sets null prototypes", () => {
+    const obj = {};
+    setPrototype(obj, null);
+    assertStrictEquals(Object.getPrototypeOf(obj), null);
+  });
+
+  it("[[Call]] can set coercible primitives to their same prototype", () => {
+    setPrototype(1, Number.prototype);
+    setPrototype(Symbol(), Symbol.prototype);
+  });
+
+  it("[[Call]] throws when setting coercible primitives to a different prototype", () => {
+    assertThrows(() => setPrototype(1, Object.prototype));
+    assertThrows(() => setPrototype(Symbol(), Object.prototype));
+  });
+
+  it("[[Call]] throws for null and undefined", () => {
+    assertThrows(() => setPrototype(null, Object.prototype));
+    assertThrows(() => setPrototype(undefined, Object.prototype));
+  });
+
+  it("[[Call]] returns the provided value", () => {
+    const obj = {};
+    assertStrictEquals(setPrototype(obj, null), obj);
+    assertStrictEquals(setPrototype(1, Number.prototype), 1);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new setPrototype({}, null));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(setPrototype.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(setPrototype.name, "setPrototype");
+    });
+  });
+});
+
+describe("toObject", () => {
+  it("returns the input for objects", () => {
+    const obj = {};
+    assertStrictEquals(toObject(obj), obj);
+  });
+
+  it("throws for nullish values", () => {
+    assertThrows(() => toObject(null));
+    assertThrows(() => toObject(void {}));
+  });
+
+  it("returns a wrapper object for other primitives", () => {
+    const sym = Symbol();
+    assertStrictEquals(typeof toObject(sym), "object");
+    assertStrictEquals(toObject(sym).valueOf(), sym);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new toObject({}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(toObject.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(toObject.name, "toObject");
+    });
+  });
+});
+
+describe("toPropertyDescriptorRecord", () => {
+  it("[[Call]] creates a new property descriptor record", () => {
+    const obj = {};
+    const desc = toPropertyDescriptorRecord(obj);
+    assertEquals(obj, desc);
+    assertNotStrictEquals(obj, desc);
+  });
+
+  it("[[Call]] coerces the values", () => {
+    assertEquals(
+      toPropertyDescriptorRecord({
+        configurable: undefined,
+        enumerable: undefined,
+        writable: undefined,
+      }),
+      { configurable: false, enumerable: false, writable: false },
+    );
+  });
+
+  it("[[Construct]] throws for primitives", () => {
+    assertThrows(() => toPropertyDescriptorRecord(undefined));
+    assertThrows(() => toPropertyDescriptorRecord("failure"));
+  });
 
-  describe("::isGenericDescriptor", () => {
-    it("[[Get]] returns true for a generic descriptor", () => {
-      assertStrictEquals(
-        Reflect.get(
-          PropertyDescriptor.prototype,
-          "isGenericDescriptor",
-          {},
-        ),
-        true,
-      );
-    });
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new toPropertyDescriptorRecord({}));
+  });
 
-    it("[[Get]] returns true for a data descriptor", () => {
-      assertStrictEquals(
-        Reflect.get(
-          PropertyDescriptor.prototype,
-          "isGenericDescriptor",
-          { value: undefined },
-        ),
-        false,
-      );
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(toPropertyDescriptorRecord.length, 1);
     });
+  });
 
-    it("[[Get]] returns false for an accessor descriptor", () => {
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
       assertStrictEquals(
-        Reflect.get(
-          PropertyDescriptor.prototype,
-          "isGenericDescriptor",
-          { get: undefined },
-        ),
-        false,
+        toPropertyDescriptorRecord.name,
+        "toPropertyDescriptorRecord",
       );
     });
   });
 
   describe("~configurable", () => {
     it("[[DefineOwnProperty]] coerces to a boolean", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       Object.defineProperty(desc, "configurable", {});
       assertStrictEquals(desc.configurable, false);
     });
 
     it("[[DefineOwnProperty]] throws for accessor properties", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       assertThrows(() =>
         Object.defineProperty(desc, "configurable", { get: undefined })
       );
     });
 
     it("[[Set]] coerces to a boolean", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       desc.configurable = undefined;
       assertStrictEquals(desc.configurable, false);
     });
 
     it("[[Delete]] works", () => {
-      const desc = new PropertyDescriptor({ configurable: false });
+      const desc = toPropertyDescriptorRecord({ configurable: false });
       delete desc.configurable;
       assert(!("configurable" in desc));
     });
@@ -268,26 +2167,26 @@ describe("PropertyDescriptor", () => {
 
   describe("~enumerable", () => {
     it("[[DefineOwnProperty]] coerces to a boolean", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       Object.defineProperty(desc, "enumerable", {});
       assertStrictEquals(desc.enumerable, false);
     });
 
     it("[[DefineOwnProperty]] throws for accessor properties", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       assertThrows(() =>
         Object.defineProperty(desc, "enumerable", { get: undefined })
       );
     });
 
     it("[[Set]] coerces to a boolean", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       desc.enumerable = undefined;
       assertStrictEquals(desc.enumerable, false);
     });
 
     it("[[Delete]] works", () => {
-      const desc = new PropertyDescriptor({ enumerable: false });
+      const desc = toPropertyDescriptorRecord({ enumerable: false });
       delete desc.enumerable;
       assert(!("enumerable" in desc));
     });
@@ -295,49 +2194,49 @@ describe("PropertyDescriptor", () => {
 
   describe("~get", () => {
     it("[[DefineOwnProperty]] works", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       Object.defineProperty(desc, "get", {});
       assertStrictEquals(desc.get, undefined);
     });
 
     it("[[DefineOwnProperty]] throws for accessor properties", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       assertThrows(() =>
         Object.defineProperty(desc, "get", { get: undefined })
       );
     });
 
     it("[[DefineOwnProperty]] throws if not callable or undefined", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       assertThrows(
         () => Object.defineProperty(desc, "get", { value: null }),
       );
     });
 
     it("[[DefineOwnProperty]] throws if a data property is defined", () => {
-      const desc = new PropertyDescriptor({ value: undefined });
+      const desc = toPropertyDescriptorRecord({ value: undefined });
       assertThrows(() => Object.defineProperty(desc, "get", {}));
     });
 
     it("[[Set]] works", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       const fn = () => {};
       desc.get = fn;
       assertStrictEquals(desc.get, fn);
     });
 
     it("[[Set]] throws if not callable or undefined", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       assertThrows(() => desc.get = null);
     });
 
     it("[[Set]] throws if a data property is defined", () => {
-      const desc = new PropertyDescriptor({ value: undefined });
+      const desc = toPropertyDescriptorRecord({ value: undefined });
       assertThrows(() => desc.get = undefined);
     });
 
     it("[[Delete]] works", () => {
-      const desc = new PropertyDescriptor({ get: undefined });
+      const desc = toPropertyDescriptorRecord({ get: undefined });
       delete desc.get;
       assert(!("get" in desc));
     });
@@ -345,49 +2244,49 @@ describe("PropertyDescriptor", () => {
 
   describe("~set", () => {
     it("[[DefineOwnProperty]] works", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       Object.defineProperty(desc, "set", {});
       assertStrictEquals(desc.set, undefined);
     });
 
     it("[[DefineOwnProperty]] throws for accessor properties", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       assertThrows(() =>
         Object.defineProperty(desc, "set", { get: undefined })
       );
     });
 
     it("[[DefineOwnProperty]] throws if not callable or undefined", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       assertThrows(
         () => Object.defineProperty(desc, "set", { value: null }),
       );
     });
 
     it("[[DefineOwnProperty]] throws if a data property is defined", () => {
-      const desc = new PropertyDescriptor({ value: undefined });
+      const desc = toPropertyDescriptorRecord({ value: undefined });
       assertThrows(() => Object.defineProperty(desc, "set", {}));
     });
 
     it("[[Set]] works", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       const fn = (_) => {};
       desc.set = fn;
       assertStrictEquals(desc.set, fn);
     });
 
     it("[[Set]] throws if not callable or undefined", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       assertThrows(() => desc.set = null);
     });
 
     it("[[Set]] throws if a data property is defined", () => {
-      const desc = new PropertyDescriptor({ value: undefined });
+      const desc = toPropertyDescriptorRecord({ value: undefined });
       assertThrows(() => desc.set = undefined);
     });
 
     it("[[Delete]] works", () => {
-      const desc = new PropertyDescriptor({ set: undefined });
+      const desc = toPropertyDescriptorRecord({ set: undefined });
       delete desc.set;
       assert(!("set" in desc));
     });
@@ -395,36 +2294,36 @@ describe("PropertyDescriptor", () => {
 
   describe("~value", () => {
     it("[[DefineOwnProperty]] works", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       Object.defineProperty(desc, "value", {});
       assertStrictEquals(desc.value, undefined);
     });
 
     it("[[DefineOwnProperty]] throws for accessor properties", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       assertThrows(() =>
         Object.defineProperty(desc, "value", { get: undefined })
       );
     });
 
     it("[[DefineOwnProperty]] throws if an accessor property is defined", () => {
-      const desc = new PropertyDescriptor({ get: undefined });
+      const desc = toPropertyDescriptorRecord({ get: undefined });
       assertThrows(() => Object.defineProperty(desc, "value", {}));
     });
 
     it("[[Set]] works", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       desc.value = "success";
       assertStrictEquals(desc.value, "success");
     });
 
     it("[[Set]] throws if an accessor property is defined", () => {
-      const desc = new PropertyDescriptor({ get: undefined });
+      const desc = toPropertyDescriptorRecord({ get: undefined });
       assertThrows(() => desc.value = null);
     });
 
     it("[[Delete]] works", () => {
-      const desc = new PropertyDescriptor({ value: undefined });
+      const desc = toPropertyDescriptorRecord({ value: undefined });
       delete desc.value;
       assert(!("value" in desc));
     });
@@ -432,303 +2331,38 @@ describe("PropertyDescriptor", () => {
 
   describe("~writable", () => {
     it("[[DefineOwnProperty]] coerces to a boolean", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       Object.defineProperty(desc, "writable", {});
       assertStrictEquals(desc.writable, false);
     });
 
     it("[[DefineOwnProperty]] throws for accessor properties", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       assertThrows(() =>
         Object.defineProperty(desc, "writable", { get: undefined })
       );
     });
 
     it("[[DefineOwnProperty]] throws if an accessor property is defined", () => {
-      const desc = new PropertyDescriptor({ get: undefined });
+      const desc = toPropertyDescriptorRecord({ get: undefined });
       assertThrows(() => Object.defineProperty(desc, "writable", {}));
     });
 
     it("[[Set]] coerces to a boolean", () => {
-      const desc = new PropertyDescriptor({});
+      const desc = toPropertyDescriptorRecord({});
       desc.writable = undefined;
       assertStrictEquals(desc.writable, false);
     });
 
     it("[[Set]] throws if an accessor property is defined", () => {
-      const desc = new PropertyDescriptor({ get: undefined });
+      const desc = toPropertyDescriptorRecord({ get: undefined });
       assertThrows(() => desc.writable = false);
     });
 
     it("[[Delete]] works", () => {
-      const desc = new PropertyDescriptor({ writable: false });
+      const desc = toPropertyDescriptorRecord({ writable: false });
       delete desc.writable;
       assert(!("writable" in desc));
     });
   });
 });
-
-describe("defineOwnProperties", () => {
-  it("[[Call]] defines properties from the provided objects", () => {
-    const obj = {};
-    defineOwnProperties(obj, {
-      etaoin: {},
-      shrdlu: {},
-    }, { cmfwyp: {} });
-    assert("etaoin" in obj);
-    assert("shrdlu" in obj);
-    assert("cmfwyp" in obj);
-  });
-
-  it("[[Call]] overrides earlier declarations with later ones", () => {
-    const obj = { etaoin: undefined };
-    defineOwnProperties(obj, {
-      etaoin: { value: "failure" },
-    }, {
-      etaoin: { value: "success" },
-    });
-    assertStrictEquals(obj.etaoin, "success");
-  });
-
-  it("[[Call]] returns the provided object", () => {
-    const obj = {};
-    assertStrictEquals(defineOwnProperties(obj), obj);
-  });
-});
-
-describe("deleteOwnProperty", () => {
-  it("[[Call]] deletes the provided property on the provided object", () => {
-    const obj = { failure: undefined };
-    deleteOwnProperty(obj, "failure");
-    assert(!("failure" in obj));
-  });
-
-  it("[[Call]] does nothing if the property doesn’t exist", () => {
-    const obj = Object.freeze({});
-    deleteOwnProperty(obj, "failure");
-    assert(!("failure" in obj));
-  });
-
-  it("[[Call]] throws if the property can’t be deleted", () => {
-    const obj = Object.seal({ failure: undefined });
-    assertThrows(() => deleteOwnProperty(obj, "failure"));
-  });
-
-  it("[[Call]] returns the provided object", () => {
-    const obj = {};
-    assertStrictEquals(deleteOwnProperty(obj, ""), obj);
-  });
-});
-
-describe("frozenCopy", () => {
-  it("[[Call]] returns a frozen object", () => {
-    assert(
-      Object.isFrozen(
-        frozenCopy(Object.create(null), {
-          data: {
-            configurable: true,
-            enumerable: true,
-            value: undefined,
-            writable: true,
-          },
-          accessor: {
-            configurable: true,
-            enumerable: true,
-            get: undefined,
-          },
-        }),
-      ),
-    );
-  });
-
-  it("[[Call]] ignores non·enumerable properties", () => {
-    assertEquals(
-      frozenCopy(
-        Object.create(null, {
-          data: { value: undefined },
-          accessor: { get: undefined },
-        }),
-      ),
-      {},
-    );
-  });
-
-  it("[[Call]] preserves accessor properties", () => {
-    const properties = {
-      both: {
-        configurable: false,
-        enumerable: true,
-        get: () => {},
-        set: (_) => {},
-      },
-      empty: {
-        configurable: false,
-        enumerable: true,
-        get: undefined,
-        set: undefined,
-      },
-      getter: {
-        configurable: false,
-        enumerable: true,
-        get: () => {},
-        set: undefined,
-      },
-      setter: {
-        configurable: false,
-        enumerable: true,
-        get: undefined,
-        set: (_) => {},
-      },
-    };
-    assertEquals(
-      Object.getOwnPropertyDescriptors(
-        frozenCopy(Object.create(null, properties)),
-      ),
-      properties,
-    );
-  });
-
-  it("[[Call]] does not copy properties on the prototype", () => {
-    assert(
-      !("failure" in
-        frozenCopy(Object.create({ failure: undefined }), {
-          data: {
-            configurable: true,
-            value: undefined,
-            writable: true,
-          },
-          accessor: { configurable: true, get: undefined },
-        })),
-    );
-  });
-
-  it("[[Call]] uses the species of the constructor", () => {
-    const species = { prototype: {} };
-    assertStrictEquals(
-      Object.getPrototypeOf(
-        frozenCopy({}, { [Symbol.species]: species }),
-      ),
-      species.prototype,
-    );
-  });
-
-  it("[[Call]] uses constructor if no species is defined", () => {
-    const constructor = { [Symbol.species]: null, prototype: {} };
-    assertStrictEquals(
-      Object.getPrototypeOf(frozenCopy({}, constructor)),
-      constructor.prototype,
-    );
-  });
-
-  it("[[Call]] uses the constructor on the object if none is provided", () => {
-    const constructor = { [Symbol.species]: null, prototype: {} };
-    assertStrictEquals(
-      Object.getPrototypeOf(frozenCopy({ constructor })),
-      constructor.prototype,
-    );
-  });
-
-  it("[[Call]] allows a null constructor", () => {
-    assertStrictEquals(
-      Object.getPrototypeOf(frozenCopy({}, null)),
-      null,
-    );
-  });
-});
-
-describe("setPropertyValue", () => {
-  it("[[Call]] sets the provided property on the provided object", () => {
-    const obj = {};
-    setPropertyValue(obj, "success", true);
-    assertStrictEquals(obj.success, true);
-  });
-
-  it("[[Call]] calls setters", () => {
-    const setter = spy((_) => {});
-    const obj = Object.create(null, { success: { set: setter } });
-    setPropertyValue(obj, "success", true);
-    assertSpyCalls(setter, 1);
-    assertSpyCall(setter, 0, {
-      args: [true],
-      self: obj,
-    });
-  });
-
-  it("[[Call]] walks the prototype chain", () => {
-    const setter = spy((_) => {});
-    const obj = Object.create(
-      Object.create(null, { success: { set: setter } }),
-    );
-    setPropertyValue(obj, "success", true);
-    assertSpyCalls(setter, 1);
-    assertSpyCall(setter, 0, {
-      args: [true],
-      self: obj,
-    });
-  });
-
-  it("[[Call]] uses the provided receiver", () => {
-    const setter = spy((_) => {});
-    const obj = Object.create(null, { success: { set: setter } });
-    const receiver = {};
-    setPropertyValue(obj, "success", true, receiver);
-    assertSpyCalls(setter, 1);
-    assertSpyCall(setter, 0, {
-      args: [true],
-      self: receiver,
-    });
-  });
-
-  it("[[Call]] throws if the property can’t be set", () => {
-    const obj = Object.freeze({ failure: undefined });
-    assertThrows(() => setPropertyValue(obj, "failure", true));
-  });
-
-  it("[[Call]] returns the provided object", () => {
-    const obj = {};
-    assertStrictEquals(setPropertyValue(obj, "", undefined), obj);
-  });
-});
-
-describe("toObject", () => {
-  it("returns the input for objects", () => {
-    const obj = {};
-    assertStrictEquals(toObject(obj), obj);
-  });
-
-  it("returns a new object for nullish values", () => {
-    assertEquals(toObject(null), {});
-    assertEquals(toObject(void {}), {});
-  });
-
-  it("returns a wrapper object for other primitives", () => {
-    const sym = Symbol();
-    assertStrictEquals(typeof toObject(sym), "object");
-    assertStrictEquals(toObject(sym).valueOf(), sym);
-  });
-});
-
-describe("toPropertyKey", () => {
-  it("returns a string or symbol", () => {
-    const sym = Symbol();
-    assertStrictEquals(toPropertyKey(sym), sym);
-    assertStrictEquals(
-      toPropertyKey(new String("success")),
-      "success",
-    );
-  });
-
-  it("favours the `toString` representation", () => {
-    assertStrictEquals(
-      toPropertyKey({
-        toString() {
-          return "success";
-        },
-        valueOf() {
-          return "failure";
-        },
-      }),
-      "success",
-    );
-  });
-});
This page took 0.187214 seconds and 4 git commands to generate.