+describe("createCallableFunction", () => {
+ it("[[Call]] transfers the first argument to this", () => {
+ assertStrictEquals(
+ createCallableFunction(
+ function () {
+ return this;
+ },
+ ).call("fail", "pass"),
+ "pass",
+ );
+ });
+
+ it("[[Call]] transfers the remaining arguments", () => {
+ assertEquals(
+ createCallableFunction(
+ function (...args) {
+ return [this, ...args];
+ },
+ ).call("failure", "etaoin", "shrdlu", "cmfwyp"),
+ ["etaoin", "shrdlu", "cmfwyp"],
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new createCallableFunction(function () {}));
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ createCallableFunction.name,
+ "createCallableFunction",
+ );
+ });
+ });
+});
+
+describe("createIllegalConstructor", () => {
+ it("[[Call]] returns a constructor", () => {
+ assert(isConstructor(createIllegalConstructor()));
+ });
+
+ it("[[Call]] works as expected when provided with no arguments", () => {
+ const constructor = createIllegalConstructor();
+ assertStrictEquals(
+ Object.getPrototypeOf(constructor),
+ Function.prototype,
+ );
+ assertStrictEquals(
+ Object.getPrototypeOf(constructor.prototype),
+ Object.prototype,
+ );
+ assertEquals(constructor.prototype, {});
+ assert(
+ !Object.getOwnPropertyDescriptor(constructor, "prototype")
+ .writable,
+ );
+ assertStrictEquals(constructor.name, "");
+ });
+
+ it("[[Call]] returns a correctly‐formed constructor when provided one argument", () => {
+ const constructorPrototype = Object.create(null, {
+ name: { value: "etaoin" },
+ prototype: { value: {} },
+ });
+ const constructor = createIllegalConstructor(
+ Object.create(constructorPrototype),
+ );
+ assert(isConstructor(constructor));
+ assertStrictEquals(
+ Object.getPrototypeOf(constructor),
+ constructorPrototype,
+ );
+ assert(Object.hasOwn(constructor, "prototype"));
+ assertEquals(
+ constructor.prototype,
+ constructorPrototype.prototype,
+ );
+ assert(
+ !Object.getOwnPropertyDescriptor(constructor, "prototype")
+ .writable,
+ );
+ assertStrictEquals(constructor.name, "etaoin");
+ });
+
+ it("[[Call]] allows the second argument to override the prototype of the constructor", () => {
+ const constructorPrototype = Object.create(null, {
+ name: { value: "etaoin" },
+ prototype: { value: {} },
+ });
+ const expectedPrototype = Object.create(null, {
+ name: { value: "shrdlu" },
+ prototype: { value: {} },
+ });
+ const constructor = createIllegalConstructor(
+ Object.create(constructorPrototype),
+ expectedPrototype,
+ );
+ assert(isConstructor(constructor));
+ assertStrictEquals(
+ Object.getPrototypeOf(constructor),
+ expectedPrototype,
+ );
+ assert(Object.hasOwn(constructor, "prototype"));
+ assertEquals(
+ constructor.prototype,
+ constructorPrototype.prototype,
+ );
+ assert(
+ !Object.getOwnPropertyDescriptor(constructor, "prototype")
+ .writable,
+ );
+ assertStrictEquals(constructor.name, "etaoin");
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new createIllegalConstructor(function () {}));
+ });
+
+ describe("~", () => {
+ it("[[Call]] throws an error", () => {
+ assertThrows(() => {
+ createIllegalConstructor(function () {})();
+ });
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => {
+ createIllegalConstructor(function () {})();
+ });
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ createIllegalConstructor.name,
+ "createIllegalConstructor",
+ );
+ });
+ });
+});
+