summaryrefslogtreecommitdiff
path: root/src/utils/iterator.test.ts
blob: dda0e0a3f893e30416a7c7e11f66d1f1ad36c07e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import { describe, it } from "@std/testing/bdd";
import {
  createAsyncIterator,
  filterDuplicate,
  findMapAsync,
  surelyIterable,
} from "./iterator.ts";
import { assertEquals } from "@std/assert";

describe("surelyIterable", () => {
  it("returns the iterable as-is if input is already iterable", () => {
    const input = [1, 2, 3];
    const result = surelyIterable(input);
    assertEquals([...result], [1, 2, 3]);
  });

  it("wraps a non-iterable value in an array", () => {
    const input = 42;
    const result = surelyIterable(input);
    assertEquals([...result], [42]);
  });

  it("wraps null in an array", () => {
    const input = null;
    const result = surelyIterable(input);
    assertEquals([...result], [null]);
  });

  it("wraps undefined in an array", () => {
    const input = undefined;
    const result = surelyIterable(input);
    assertEquals([...result], [undefined]);
  });

  it("wraps an object that is not iterable", () => {
    const input = { a: 1 };
    const result = surelyIterable(input);
    assertEquals([...result], [{ a: 1 }]);
  });

  it("handles a Set correctly", () => {
    const input = new Set([1, 2, 3]);
    const result = surelyIterable(input);
    assertEquals([...result], [1, 2, 3]);
  });
});

describe("createAsyncIterator", () => {
  it("yields resolved values in order", async () => {
    const values = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)];
    const results: number[] = [];
    for await (const value of createAsyncIterator(values)) {
      results.push(value);
    }
    assertEquals(results, [1, 2, 3]);
  });

  it("handles empty array", async () => {
    const results: unknown[] = [];
    for await (const value of createAsyncIterator([])) {
      results.push(value);
    }
    assertEquals(results, []);
  });
});

describe("filterDuplicate", () => {
  it("filters duplicate objects by key", () => {
    const items = [
      { id: 1, name: "a" },
      { id: 2, name: "b" },
      { id: 1, name: "c" },
    ];
    const result = filterDuplicate(items, (i) => i.id);
    assertEquals(result.length, 2);
    assertEquals(result[0].name, "a");
    assertEquals(result[1].name, "b");
  });

  it("handles empty iterable", () => {
    const result = filterDuplicate([], (x) => x);
    assertEquals(result, []);
  });

  it("keeps first occurrence only", () => {
    const input = [1, 2, 3, 1, 2, 4];
    const result = filterDuplicate(input, (x) => x);
    assertEquals(result, [1, 2, 3, 4]);
  });
});

describe("findMapAsync", () => {
  it("returns first successful result", async () => {
    const arr = [1, 2, 3];
    const i = 2;
    const result = await findMapAsync(arr, (x) => {
      if (x === i) return Promise.resolve(x);
      throw new Error("not found");
    });
    assertEquals(result, i);
  });

  it("returns undefined if all reject", async () => {
    const arr = [1, 2];
    const result = await findMapAsync(arr, () => {
      throw new Error("fail");
    });
    assertEquals(result, undefined);
  });

  it("short-circuits after first success", async () => {
    const calls: number[] = [];
    const arr = [1, 2, 3];
    const i = arr.length - 1;
    await findMapAsync(arr, (x) => {
      calls.push(x);
      if (x === i) return Promise.resolve("ok");
      throw new Error("fail");
    });
    assertEquals(calls, arr.slice(0, i));
  });
});