]> Lady’s Gitweb - Pisces/blobdiff - iterable.test.js
Add iterator function builders; use in string.js
[Pisces] / iterable.test.js
diff --git a/iterable.test.js b/iterable.test.js
new file mode 100644 (file)
index 0000000..2e62d5c
--- /dev/null
@@ -0,0 +1,530 @@
+// ♓🌟 Piscēs ∷ iterable.test.js
+// ====================================================================
+//
+// Copyright © 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
+// file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+
+import {
+  assertEquals,
+  assertStrictEquals,
+  assertThrows,
+  describe,
+  it,
+} from "./dev-deps.js";
+import {
+  arrayIteratorFunction,
+  generatorIteratorFunction,
+  mapIteratorFunction,
+  setIteratorFunction,
+  stringIteratorFunction,
+} from "./iterable.js";
+
+describe("arrayIteratorFunction", () => {
+  it("[[Call]] returns a function", () => {
+    assertStrictEquals(typeof arrayIteratorFunction(), "function");
+  });
+
+  it("[[Call]] returns a value which has a prototype of %FunctionPrototype%", () => {
+    assertStrictEquals(
+      Object.getPrototypeOf(arrayIteratorFunction()),
+      Function.prototype,
+    );
+  });
+
+  describe("()", () => {
+    it("[[Call]] returns a value which inherits from %IteratorPrototype%", () => {
+      const iteratorProto = Object.getPrototypeOf(
+        Object.getPrototypeOf([][Symbol.iterator]),
+      );
+      const iterator = arrayIteratorFunction();
+      assertStrictEquals(
+        iterator([]) instanceof Object.assign(
+          function () {},
+          { prototype: iteratorProto },
+        ),
+        true,
+      );
+    });
+
+    it("[[Call]] returns a value with the provided string tag", () => {
+      const iterator = arrayIteratorFunction(null, "My Iterator");
+      assertStrictEquals(
+        iterator([])[Symbol.toStringTag],
+        "My Iterator",
+      );
+    });
+
+    it("[[Call]] yields the values", () => {
+      const iterator = arrayIteratorFunction();
+      assertEquals(
+        [...iterator(["etaoin", "shrdlu"])],
+        ["etaoin", "shrdlu"],
+      );
+    });
+
+    it("[[Call]] maps the values", () => {
+      const iterator = arrayIteratorFunction(function* ($) {
+        yield $.toUpperCase();
+      });
+      assertEquals(
+        [...iterator(["etaoin", "shrdlu"])],
+        ["ETAOIN", "SHRDLU"],
+      );
+    });
+
+    it("[[Call]] can map to nothing", () => {
+      const iterator = arrayIteratorFunction(function* () {});
+      assertEquals(
+        [...iterator(["etaoin", "shrdlu"])],
+        [],
+      );
+    });
+
+    it("[[Call]] can map to multiple values", () => {
+      const iterator = arrayIteratorFunction(function* ($) {
+        yield* $;
+      });
+      assertEquals(
+        [...iterator(["etaoin", "shrdlu"])],
+        [..."etaoinshrdlu"],
+      );
+    });
+
+    it("[[Call]] throws if not provided with any arguments", () => {
+      const iterator = arrayIteratorFunction();
+      assertThrows(() => {
+        iterator();
+      });
+    });
+
+    it("[[Call]] throws if not provided an arraylike", () => {
+      const iterator = arrayIteratorFunction();
+      assertThrows(() => {
+        iterator(null);
+      });
+    });
+
+    describe("::next", () => {
+      it("[[Call]] throws if there are values and the mapper is not a generator function", () => {
+        const iterator = arrayIteratorFunction(function () {});
+        assertThrows(() => {
+          iterator(["etaoin"]).next();
+        });
+      });
+    });
+  });
+});
+
+describe("generatorIteratorFunction", () => {
+  it("[[Call]] returns a function", () => {
+    assertStrictEquals(typeof generatorIteratorFunction(), "function");
+  });
+
+  it("[[Call]] returns a value which has a prototype of %FunctionPrototype%", () => {
+    assertStrictEquals(
+      Object.getPrototypeOf(generatorIteratorFunction()),
+      Function.prototype,
+    );
+  });
+
+  describe("()", () => {
+    it("[[Call]] returns a value which inherits from %IteratorPrototype%", () => {
+      const iteratorProto = Object.getPrototypeOf(
+        Object.getPrototypeOf([][Symbol.iterator]),
+      );
+      const iterator = generatorIteratorFunction();
+      assertStrictEquals(
+        iterator(function* () {}) instanceof Object.assign(
+          function () {},
+          { prototype: iteratorProto },
+        ),
+        true,
+      );
+    });
+
+    it("[[Call]] returns a value with the provided string tag", () => {
+      const iterator = generatorIteratorFunction(null, "My Iterator");
+      assertStrictEquals(
+        iterator(function* () {})[Symbol.toStringTag],
+        "My Iterator",
+      );
+    });
+
+    it("[[Call]] yields the values", () => {
+      const generator = function* () {
+        yield* ["etaoin", "shrdlu"];
+      };
+      const iterator = generatorIteratorFunction();
+      assertEquals(
+        [...iterator(generator)],
+        ["etaoin", "shrdlu"],
+      );
+    });
+
+    it("[[Call]] maps the values", () => {
+      const generator = function* () {
+        yield* ["etaoin", "shrdlu"];
+      };
+      const iterator = generatorIteratorFunction(function* ($) {
+        yield $.toUpperCase();
+      });
+      assertEquals(
+        [...iterator(generator)],
+        ["ETAOIN", "SHRDLU"],
+      );
+    });
+
+    it("[[Call]] can map to nothing", () => {
+      const generator = function* () {
+        yield* ["etaoin", "shrdlu"];
+      };
+      const iterator = generatorIteratorFunction(function* () {});
+      assertEquals(
+        [...iterator(generator)],
+        [],
+      );
+    });
+
+    it("[[Call]] can map to multiple values", () => {
+      const generator = function* () {
+        yield* ["etaoin", "shrdlu"];
+      };
+      const iterator = generatorIteratorFunction(function* ($) {
+        yield* $;
+      });
+      assertEquals(
+        [...iterator(generator)],
+        [..."etaoinshrdlu"],
+      );
+    });
+
+    it("[[Call]] throws if not provided with any arguments", () => {
+      const iterator = generatorIteratorFunction();
+      assertThrows(() => {
+        iterator();
+      });
+    });
+
+    it("[[Call]] throws if not provided a function", () => {
+      const iterator = generatorIteratorFunction();
+      assertThrows(() => {
+        iterator([]);
+      });
+    });
+
+    describe("::next", () => {
+      it("[[Call]] throws if there are values and the mapper is not a generator function", () => {
+        const generator = function* () {
+          yield "etaoin";
+        };
+        const iterator = generatorIteratorFunction(function () {});
+        assertThrows(() => {
+          iterator(generator).next();
+        });
+      });
+
+      it("[[Call]] throws if not constructed with a generator function", () => {
+        const iterator = generatorIteratorFunction();
+        assertThrows(() => {
+          iterator(Array.prototype[Symbol.iterator].bind([])).next();
+        });
+      });
+    });
+  });
+});
+
+describe("mapIteratorFunction", () => {
+  it("[[Call]] returns a function", () => {
+    assertStrictEquals(typeof mapIteratorFunction(), "function");
+  });
+
+  it("[[Call]] returns a value which has a prototype of %FunctionPrototype%", () => {
+    assertStrictEquals(
+      Object.getPrototypeOf(mapIteratorFunction()),
+      Function.prototype,
+    );
+  });
+
+  describe("()", () => {
+    it("[[Call]] returns a value which inherits from %IteratorPrototype%", () => {
+      const iteratorProto = Object.getPrototypeOf(
+        Object.getPrototypeOf([][Symbol.iterator]),
+      );
+      const iterator = mapIteratorFunction();
+      assertStrictEquals(
+        iterator(new Map()) instanceof Object.assign(
+          function () {},
+          { prototype: iteratorProto },
+        ),
+        true,
+      );
+    });
+
+    it("[[Call]] returns a value with the provided string tag", () => {
+      const iterator = mapIteratorFunction(null, "My Iterator");
+      assertStrictEquals(
+        iterator(new Map())[Symbol.toStringTag],
+        "My Iterator",
+      );
+    });
+
+    it("[[Call]] yields the values", () => {
+      const iterator = mapIteratorFunction();
+      assertEquals(
+        [...iterator(new Map([["etaoin", "shrdlu"]]))],
+        [["etaoin", "shrdlu"]],
+      );
+    });
+
+    it("[[Call]] maps the values", () => {
+      const iterator = mapIteratorFunction(function* ([k, v]) {
+        yield [k.toUpperCase(), v.toUpperCase()];
+      });
+      assertEquals(
+        [...iterator(new Map([["etaoin", "shrdlu"]]))],
+        [["ETAOIN", "SHRDLU"]],
+      );
+    });
+
+    it("[[Call]] can map to nothing", () => {
+      const iterator = mapIteratorFunction(function* () {});
+      assertEquals(
+        [...iterator(new Map([["etaoin", "shrdlu"]]))],
+        [],
+      );
+    });
+
+    it("[[Call]] can map to multiple values", () => {
+      const iterator = mapIteratorFunction(function* ($) {
+        yield* $;
+      });
+      assertEquals(
+        [...iterator(new Map([["etaoin", "shrdlu"]]))],
+        ["etaoin", "shrdlu"],
+      );
+    });
+
+    it("[[Call]] throws if not provided with any arguments", () => {
+      const iterator = mapIteratorFunction();
+      assertThrows(() => {
+        iterator();
+      });
+    });
+
+    it("[[Call]] throws if not provided a map", () => {
+      const iterator = mapIteratorFunction();
+      assertThrows(() => {
+        iterator([]);
+      });
+    });
+
+    describe("::next", () => {
+      it("[[Call]] throws if there are values and the mapper is not a generator function", () => {
+        const iterator = mapIteratorFunction(function () {});
+        assertThrows(() => {
+          iterator(new Map([["etaoin", "shrdlu"]])).next();
+        });
+      });
+    });
+  });
+});
+
+describe("setIteratorFunction", () => {
+  it("[[Call]] returns a function", () => {
+    assertStrictEquals(typeof setIteratorFunction(), "function");
+  });
+
+  it("[[Call]] returns a value which has a prototype of %FunctionPrototype%", () => {
+    assertStrictEquals(
+      Object.getPrototypeOf(setIteratorFunction()),
+      Function.prototype,
+    );
+  });
+
+  describe("()", () => {
+    it("[[Call]] returns a value which inherits from %IteratorPrototype%", () => {
+      const iteratorProto = Object.getPrototypeOf(
+        Object.getPrototypeOf([][Symbol.iterator]),
+      );
+      const iterator = setIteratorFunction();
+      assertStrictEquals(
+        iterator(new Set()) instanceof Object.assign(
+          function () {},
+          { prototype: iteratorProto },
+        ),
+        true,
+      );
+    });
+
+    it("[[Call]] returns a value with the provided string tag", () => {
+      const iterator = setIteratorFunction(null, "My Iterator");
+      assertStrictEquals(
+        iterator(new Set())[Symbol.toStringTag],
+        "My Iterator",
+      );
+    });
+
+    it("[[Call]] yields the values", () => {
+      const iterator = setIteratorFunction();
+      assertEquals(
+        [...iterator(new Set(["etaoin", "shrdlu"]))],
+        ["etaoin", "shrdlu"],
+      );
+    });
+
+    it("[[Call]] maps the values", () => {
+      const iterator = setIteratorFunction(function* ($) {
+        yield $.toUpperCase();
+      });
+      assertEquals(
+        [...iterator(new Set(["etaoin", "shrdlu"]))],
+        ["ETAOIN", "SHRDLU"],
+      );
+    });
+
+    it("[[Call]] can map to nothing", () => {
+      const iterator = setIteratorFunction(function* () {});
+      assertEquals(
+        [...iterator(new Set(["etaoin", "shrdlu"]))],
+        [],
+      );
+    });
+
+    it("[[Call]] can map to multiple values", () => {
+      const iterator = setIteratorFunction(function* ($) {
+        yield* $;
+      });
+      assertEquals(
+        [...iterator(new Set(["etaoin", "shrdlu"]))],
+        [..."etaoinshrdlu"],
+      );
+    });
+
+    it("[[Call]] throws if not provided with any arguments", () => {
+      const iterator = setIteratorFunction();
+      assertThrows(() => {
+        iterator();
+      });
+    });
+
+    it("[[Call]] throws if not provided a set", () => {
+      const iterator = setIteratorFunction();
+      assertThrows(() => {
+        iterator([]);
+      });
+    });
+
+    describe("::next", () => {
+      it("[[Call]] throws if there are values and the mapper is not a generator function", () => {
+        const iterator = setIteratorFunction(function () {});
+        assertThrows(() => {
+          iterator(new Set(["etaoin"])).next();
+        });
+      });
+    });
+  });
+});
+
+describe("stringIteratorFunction", () => {
+  it("[[Call]] returns a function", () => {
+    assertStrictEquals(typeof stringIteratorFunction(), "function");
+  });
+
+  it("[[Call]] returns a value which has a prototype of %FunctionPrototype%", () => {
+    assertStrictEquals(
+      Object.getPrototypeOf(stringIteratorFunction()),
+      Function.prototype,
+    );
+  });
+
+  describe("()", () => {
+    it("[[Call]] returns a value which inherits from %IteratorPrototype%", () => {
+      const iteratorProto = Object.getPrototypeOf(
+        Object.getPrototypeOf([][Symbol.iterator]),
+      );
+      const iterator = stringIteratorFunction();
+      assertStrictEquals(
+        iterator("") instanceof Object.assign(
+          function () {},
+          { prototype: iteratorProto },
+        ),
+        true,
+      );
+    });
+
+    it("[[Call]] returns a value with the provided string tag", () => {
+      const iterator = stringIteratorFunction(null, "My Iterator");
+      assertStrictEquals(
+        iterator("")[Symbol.toStringTag],
+        "My Iterator",
+      );
+    });
+
+    it("[[Call]] yields the values", () => {
+      const iterator = stringIteratorFunction();
+      assertEquals(
+        [...iterator("etaoin👀")],
+        [..."etaoin👀"],
+      );
+    });
+
+    it("[[Call]] maps the values", () => {
+      const iterator = stringIteratorFunction(function* ($) {
+        yield $.toUpperCase();
+      });
+      assertEquals(
+        [...iterator("etaoin👀")],
+        [..."ETAOIN👀"],
+      );
+    });
+
+    it("[[Call]] can map to nothing", () => {
+      const iterator = stringIteratorFunction(function* () {});
+      assertEquals(
+        [...iterator("etaoin👀")],
+        [],
+      );
+    });
+
+    it("[[Call]] can map to multiple values", () => {
+      const iterator = stringIteratorFunction(function* ($) {
+        yield $;
+        yield $;
+      });
+      assertEquals(
+        [...iterator("etaoin👀")],
+        [..."eettaaooiinn👀👀"],
+      );
+    });
+
+    it("[[Call]] throws if not provided with any arguments", () => {
+      const iterator = stringIteratorFunction();
+      assertThrows(() => {
+        iterator();
+      });
+    });
+
+    it("[[Call]] throws if not provided something convertible to a string", () => {
+      const iterator = stringIteratorFunction();
+      assertThrows(() => {
+        iterator({
+          toString() {
+            throw null;
+          },
+        });
+      });
+    });
+
+    describe("::next", () => {
+      it("[[Call]] throws if there are values and the mapper is not a generator function", () => {
+        const iterator = stringIteratorFunction(function () {});
+        assertThrows(() => {
+          iterator("etaoin").next();
+        });
+      });
+    });
+  });
+});
This page took 0.108236 seconds and 4 git commands to generate.