1import { describe, it } from "@effect/vitest"
2import { assertFalse, assertNone, assertSome, assertTrue, deepStrictEqual, strictEqual } from "@effect/vitest/utils"
3import { Equivalence, Iterable as Iter, Option, Result } from "effect"
4import { pipe } from "effect/Function"
5import type { Predicate } from "effect/Predicate"
6
7const symA = Symbol.for("a")
8const symB = Symbol.for("b")
9const symC = Symbol.for("c")
10
11const toArray = <A>(i: Iterable<A>) => {
12 if (Array.isArray(i)) {
13 throw new Error("not an iterable")
14 }
15 return Array.from(i)
16}
17
18describe("Iterable", () => {
19 it("of", () => {
20 deepStrictEqual(Array.from(Iter.of(1)), [1])
21 })
22
23 describe("iterable inputs", () => {
24 it("prepend", () => {
25 deepStrictEqual(pipe([1, 2, 3], Iter.prepend(0), toArray), [0, 1, 2, 3])
26 deepStrictEqual(pipe([[2]], Iter.prepend([1]), toArray), [[1], [2]])
27
28 deepStrictEqual(pipe(new Set([1, 2, 3]), Iter.prepend(0), toArray), [0, 1, 2, 3])
29 deepStrictEqual(pipe(new Set([[2]]), Iter.prepend([1]), toArray), [[1], [2]])
30 })
31
32 it("prependAll", () => {
33 deepStrictEqual(pipe([3, 4], Iter.prependAll([1, 2]), toArray), [1, 2, 3, 4])
34
35 deepStrictEqual(pipe([3, 4], Iter.prependAll(new Set([1, 2])), toArray), [1, 2, 3, 4])
36 deepStrictEqual(pipe(new Set([3, 4]), Iter.prependAll([1, 2]), toArray), [1, 2, 3, 4])
37 })
38
39 it("append", () => {
40 deepStrictEqual(pipe([1, 2, 3], Iter.append(4), toArray), [1, 2, 3, 4])
41 deepStrictEqual(pipe([[1]], Iter.append([2]), toArray), [[1], [2]])
42
43 deepStrictEqual(pipe(new Set([1, 2, 3]), Iter.append(4), toArray), [1, 2, 3, 4])
44 deepStrictEqual(pipe(new Set([[1]]), Iter.append([2]), toArray), [[1], [2]])
45 })
46
47 it("appendAll", () => {
48 deepStrictEqual(pipe([1, 2], Iter.appendAll([3, 4]), toArray), [1, 2, 3, 4])
49
50 deepStrictEqual(pipe([1, 2], Iter.appendAll(new Set([3, 4])), toArray), [1, 2, 3, 4])
51 deepStrictEqual(pipe(new Set([1, 2]), Iter.appendAll([3, 4]), toArray), [1, 2, 3, 4])
52 })
53
54 it("scan", () => {
55 const f = (b: number, a: number) => b - a
56 deepStrictEqual(pipe([1, 2, 3], Iter.scan(10, f), toArray), [10, 9, 7, 4])
57 deepStrictEqual(pipe([0], Iter.scan(10, f), toArray), [10, 10])
58 deepStrictEqual(pipe([], Iter.scan(10, f), toArray), [10])
59
60 deepStrictEqual(pipe(new Set([1, 2, 3]), Iter.scan(10, f), toArray), [10, 9, 7, 4])
61 deepStrictEqual(pipe(new Set([0]), Iter.scan(10, f), toArray), [10, 10])
62 deepStrictEqual(pipe(new Set([]), Iter.scan(10, f), toArray), [10])
63 })
64
65 it("take", () => {
66 deepStrictEqual(pipe([1, 2, 3, 4], Iter.take(2), toArray), [1, 2])
67 deepStrictEqual(pipe([1, 2, 3, 4], Iter.take(0), toArray), [])
68 deepStrictEqual(pipe([1, 2, 3, 4], Iter.take(1.5), toArray), [1])
69 deepStrictEqual(pipe([1, 2, 3, 4], Iter.take(Number.NaN), toArray), [])
70 // out of bounds
71 deepStrictEqual(pipe([1, 2, 3, 4], Iter.take(-10), toArray), [])
72 deepStrictEqual(pipe([1, 2, 3, 4], Iter.take(10), toArray), [1, 2, 3, 4])
73
74 deepStrictEqual(pipe(new Set([1, 2, 3, 4]), Iter.take(2), toArray), [1, 2])
75 deepStrictEqual(pipe(new Set([1, 2, 3, 4]), Iter.take(0), toArray), [])
76 // out of bounds
77 deepStrictEqual(pipe(new Set([1, 2, 3, 4]), Iter.take(-10), toArray), [])
78 deepStrictEqual(pipe(new Set([1, 2, 3, 4]), Iter.take(10), toArray), [1, 2, 3, 4])
79 })
80
81 it("takeWhile", () => {
82 const f = (n: number) => n % 2 === 0
83 deepStrictEqual(pipe([2, 4, 3, 6], Iter.takeWhile(f), toArray), [2, 4])
84 deepStrictEqual(pipe(Iter.empty(), Iter.takeWhile(f), toArray), [])
85 deepStrictEqual(pipe([1, 2, 4], Iter.takeWhile(f), toArray), [])
86 deepStrictEqual(pipe([2, 4], Iter.takeWhile(f), toArray), [2, 4])
87
88 deepStrictEqual(pipe(new Set([2, 4, 3, 6]), Iter.takeWhile(f), toArray), [2, 4])
89 deepStrictEqual(pipe(new Set<number>(), Iter.takeWhile(f), toArray), [])
90 deepStrictEqual(pipe(new Set([1, 2, 4]), Iter.takeWhile(f), toArray), [])
91 deepStrictEqual(pipe(new Set([2, 4]), Iter.takeWhile(f), toArray), [2, 4])
92 })
93
94 it("drop", () => {
95 deepStrictEqual(pipe(Iter.empty(), Iter.drop(0), toArray), [])
96 deepStrictEqual(pipe([1, 2], Iter.drop(0), toArray), [1, 2])
97 deepStrictEqual(pipe([1, 2, 3], Iter.drop(1.5), toArray), [2, 3])
98 deepStrictEqual(pipe([1, 2], Iter.drop(Number.NaN), toArray), [1, 2])
99 deepStrictEqual(pipe([1, 2], Iter.drop(1), toArray), [2])
100 deepStrictEqual(pipe([1, 2], Iter.drop(2), toArray), [])
101 // out of bound
102 deepStrictEqual(pipe(Iter.empty(), Iter.drop(1), toArray), [])
103 deepStrictEqual(pipe(Iter.empty(), Iter.drop(-1), toArray), [])
104 deepStrictEqual(pipe([1, 2], Iter.drop(3), toArray), [])
105 deepStrictEqual(pipe([1, 2], Iter.drop(-1), toArray), [1, 2])
106
107 deepStrictEqual(pipe(new Set(), Iter.drop(0), toArray), [])
108 deepStrictEqual(pipe(new Set([1, 2]), Iter.drop(0), toArray), [1, 2])
109 deepStrictEqual(pipe(new Set([1, 2]), Iter.drop(1), toArray), [2])
110 deepStrictEqual(pipe(new Set([1, 2]), Iter.drop(2), toArray), [])
111 // out of bound
112 deepStrictEqual(pipe(new Set(), Iter.drop(1), toArray), [])
113 deepStrictEqual(pipe(new Set(), Iter.drop(-1), toArray), [])
114 deepStrictEqual(pipe(new Set([1, 2]), Iter.drop(3), toArray), [])
115 deepStrictEqual(pipe(new Set([1, 2]), Iter.drop(-1), toArray), [1, 2])
116 })
117
118 describe("findFirst", () => {
119 it("boolean-returning overloads", () => {
120 assertNone(pipe([], Iter.findFirst((n) => n % 2 === 0)))
121 assertSome(pipe([1, 2, 3], Iter.findFirst((n) => n % 2 === 0)), 2)
122 assertSome(pipe([1, 2, 3, 4], Iter.findFirst((n) => n % 2 === 0)), 2)
123
124 assertNone(pipe(new Set<number>(), Iter.findFirst((n) => n % 2 === 0)))
125 assertSome(pipe(new Set([1, 2, 3]), Iter.findFirst((n) => n % 2 === 0)), 2)
126 assertSome(pipe(new Set([1, 2, 3, 4]), Iter.findFirst((n) => n % 2 === 0)), 2)
127 })
128
129 it("Option-returning overloads", () => {
130 assertNone(pipe([], Iter.findFirst((n, i) => n % 2 === 0 ? Option.some([n, i]) : Option.none())))
131 assertSome(
132 pipe([1, 2, 3], Iter.findFirst((n, i) => n % 2 === 0 ? Option.some([n, i]) : Option.none())),
133 [2, 1]
134 )
135 assertSome(
136 pipe([1, 2, 3, 4], Iter.findFirst((n, i) => n % 2 === 0 ? Option.some([n, i]) : Option.none())),
137 [2, 1]
138 )
139
140 assertNone(
141 pipe(new Set<number>(), Iter.findFirst((n, i) => n % 2 === 0 ? Option.some([n, i]) : Option.none()))
142 )
143 assertSome(
144 pipe(new Set([1, 2, 3]), Iter.findFirst((n, i) => n % 2 === 0 ? Option.some([n, i]) : Option.none())),
145 [2, 1]
146 )
147 assertSome(
148 pipe(new Set([1, 2, 3, 4]), Iter.findFirst((n, i) => n % 2 === 0 ? Option.some([n, i]) : Option.none())),
149 [2, 1]
150 )
151 })
152 })
153
154 describe("findLast", () => {
155 it("boolean-returning overloads", () => {
156 assertNone(pipe([], Iter.findLast((n) => n % 2 === 0)))
157 assertSome(pipe([1, 2, 3], Iter.findLast((n) => n % 2 === 0)), 2)
158 assertSome(pipe([1, 2, 3, 4], Iter.findLast((n) => n % 2 === 0)), 4)
159
160 assertNone(pipe(new Set<number>(), Iter.findLast((n) => n % 2 === 0)))
161 assertSome(pipe(new Set([1, 2, 3]), Iter.findLast((n) => n % 2 === 0)), 2)
162 assertSome(pipe(new Set([1, 2, 3, 4]), Iter.findLast((n) => n % 2 === 0)), 4)
163 })
164
165 it("Option-returning overloads", () => {
166 assertNone(pipe([], Iter.findLast((n, i) => n % 2 === 0 ? Option.some([n, i]) : Option.none())))
167 assertSome(
168 pipe([1, 2, 3], Iter.findLast((n, i) => n % 2 === 0 ? Option.some([n, i]) : Option.none())),
169 [2, 1]
170 )
171 assertSome(
172 pipe([1, 2, 3, 4], Iter.findLast((n, i) => n % 2 === 0 ? Option.some([n, i]) : Option.none())),
173 [4, 3]
174 )
175
176 assertNone(
177 pipe(new Set<number>(), Iter.findLast((n, i) => n % 2 === 0 ? Option.some([n, i]) : Option.none()))
178 )
179 assertSome(
180 pipe(new Set([1, 2, 3]), Iter.findLast((n, i) => n % 2 === 0 ? Option.some([n, i]) : Option.none())),
181 [2, 1]
182 )
183 assertSome(
184 pipe(new Set([1, 2, 3, 4]), Iter.findLast((n, i) => n % 2 === 0 ? Option.some([n, i]) : Option.none())),
185 [4, 3]
186 )
187 })
188 })
189
190 it("zip", () => {
191 deepStrictEqual(pipe(new Set([]), Iter.zip(new Set(["a", "b", "c", "d"])), toArray), [])
192 deepStrictEqual(pipe(new Set([1, 2, 3]), Iter.zip(new Set([])), toArray), [])
193 deepStrictEqual(pipe(new Set([1, 2, 3]), Iter.zip(new Set(["a", "b", "c", "d"])), toArray), [
194 [1, "a"],
195 [2, "b"],
196 [3, "c"]
197 ])
198 deepStrictEqual(pipe(new Set([1, 2, 3]), Iter.zip(new Set(["a", "b", "c", "d"])), toArray), [
199 [1, "a"],
200 [2, "b"],
201 [3, "c"]
202 ])
203 })
204
205 it("zipWith", () => {
206 deepStrictEqual(
207 pipe(new Set([1, 2, 3]), Iter.zipWith(new Set([]), (n, s) => s + n), toArray),
208 []
209 )
210 deepStrictEqual(
211 pipe(new Set([]), Iter.zipWith(new Set(["a", "b", "c", "d"]), (n, s) => s + n), toArray),
212 []
213 )
214 deepStrictEqual(
215 pipe(new Set([]), Iter.zipWith(new Set([]), (n, s) => s + n), toArray),
216 []
217 )
218 deepStrictEqual(
219 pipe(new Set([1, 2, 3]), Iter.zipWith(new Set(["a", "b", "c", "d"]), (n, s) => s + n), toArray),
220 ["a1", "b2", "c3"]
221 )
222 })
223
224 it("intersperse", () => {
225 deepStrictEqual(pipe([], Iter.intersperse(0), toArray), [])
226 deepStrictEqual(pipe([1], Iter.intersperse(0), toArray), [1])
227 deepStrictEqual(pipe([1, 2, 3], Iter.intersperse(0), toArray), [1, 0, 2, 0, 3])
228 deepStrictEqual(pipe([1, 2], Iter.intersperse(0), toArray), [1, 0, 2])
229 deepStrictEqual(pipe([1, 2, 3, 4], Iter.intersperse(0), toArray), [1, 0, 2, 0, 3, 0, 4])
230
231 deepStrictEqual(pipe(new Set([]), Iter.intersperse(0), toArray), [])
232 deepStrictEqual(pipe(new Set([1]), Iter.intersperse(0), toArray), [1])
233 deepStrictEqual(pipe(new Set([1, 2, 3]), Iter.intersperse(0), toArray), [1, 0, 2, 0, 3])
234 deepStrictEqual(pipe(new Set([1, 2]), Iter.intersperse(0), toArray), [1, 0, 2])
235 deepStrictEqual(pipe(new Set([1, 2, 3, 4]), Iter.intersperse(0), toArray), [1, 0, 2, 0, 3, 0, 4])
236 })
237
238 it("containsWith", () => {
239 const contains = Iter.containsWith(Equivalence.strictEqual<number>())
240 assertTrue(pipe([1, 2, 3], contains(2)))
241 assertFalse(pipe([1, 2, 3], contains(0)))
242
243 assertTrue(pipe(new Set([1, 2, 3]), contains(2)))
244 assertFalse(pipe(new Set([1, 2, 3]), contains(0)))
245 })
246
247 it("contains", () => {
248 const contains = Iter.contains
249 assertTrue(pipe([1, 2, 3], contains(2)))
250 assertFalse(pipe([1, 2, 3], contains(0)))
251
252 assertTrue(pipe(new Set([1, 2, 3]), contains(2)))
253 assertFalse(pipe(new Set([1, 2, 3]), contains(0)))
254 })
255
256 it("dedupeAdjacentWith", () => {
257 const dedupeAdjacent = Iter.dedupeAdjacentWith(Equivalence.strictEqual<number>())
258 deepStrictEqual(toArray(dedupeAdjacent([])), [])
259 deepStrictEqual(toArray(dedupeAdjacent([1, 2, 3])), [1, 2, 3])
260 deepStrictEqual(toArray(dedupeAdjacent([1, 2, 2, 3, 3])), [1, 2, 3])
261 })
262 })
263
264 it("flatMapNullishOr", () => {
265 const f = Iter.flatMapNullishOr((n: number) => (n > 0 ? n : null))
266 deepStrictEqual(pipe([], f, toArray), [])
267 deepStrictEqual(pipe([1], f, toArray), [1])
268 deepStrictEqual(pipe([-1], f, toArray), [])
269 })
270
271 it("unfold", () => {
272 const as = Iter.unfold(5, (n) => (n > 0 ? Option.some([n, n - 1]) : Option.none()))
273 deepStrictEqual(toArray(as), [5, 4, 3, 2, 1])
274 })
275
276 it("map", () => {
277 deepStrictEqual(
278 pipe([1, 2, 3], Iter.map((n) => n * 2), toArray),
279 [2, 4, 6]
280 )
281 deepStrictEqual(
282 pipe(["a", "b"], Iter.map((s, i) => s + i), toArray),
283 ["a0", "b1"]
284 )
285 })
286
287 it("flatMap", () => {
288 deepStrictEqual(
289 pipe([1, 2, 3], Iter.flatMap((n) => [n, n + 1]), toArray),
290 [1, 2, 2, 3, 3, 4]
291 )
292 const f = (n: number, i: number) => [n + i]
293 deepStrictEqual(pipe([], Iter.flatMap(f), toArray), [])
294 deepStrictEqual(pipe([1, 2, 3], Iter.flatMap(f), toArray), [1, 3, 5])
295 })
296
297 it("getSomes", () => {
298 deepStrictEqual(toArray(Iter.getSomes([])), [])
299 deepStrictEqual(toArray(Iter.getSomes([Option.some(1), Option.some(2), Option.some(3)])), [
300 1,
301 2,
302 3
303 ])
304 deepStrictEqual(toArray(Iter.getSomes([Option.some(1), Option.none(), Option.some(3)])), [
305 1,
306 3
307 ])
308 })
309
310 it("filter", () => {
311 deepStrictEqual(toArray(Iter.filter([1, 2, 3], (n) => n % 2 === 1)), [1, 3])
312 deepStrictEqual(toArray(Iter.filter([Option.some(3), Option.some(2), Option.some(1)], Option.isSome)), [
313 Option.some(3),
314 Option.some(2),
315 Option.some(1)
316 ])
317 deepStrictEqual(toArray(Iter.filter([Option.some(3), Option.none(), Option.some(1)], Option.isSome)), [
318 Option.some(3),
319 Option.some(1)
320 ])
321 deepStrictEqual(toArray(Iter.filter(["a", "b", "c"], (_, i) => i % 2 === 0)), ["a", "c"])
322 })
323
324 it("filterMap", () => {
325 const f = (n: number) => (n % 2 === 0 ? Result.failVoid : Result.succeed(n))
326 deepStrictEqual(pipe([1, 2, 3], Iter.filterMap(f), toArray), [1, 3])
327 deepStrictEqual(pipe([], Iter.filterMap(f), toArray), [])
328 const g = (n: number, i: number) => ((i + n) % 2 === 0 ? Result.failVoid : Result.succeed(n))
329 deepStrictEqual(pipe([1, 2, 4], Iter.filterMap(g), toArray), [1, 2])
330 deepStrictEqual(pipe([], Iter.filterMap(g), toArray), [])
331 })
332
333 it("filterMapWhile", () => {
334 deepStrictEqual(
335 pipe([1, 3, 4, 5], Iter.filterMapWhile((n) => n % 2 === 1 ? Result.succeed(n) : Result.failVoid), toArray),
336 [1, 3]
337 )
338 deepStrictEqual(
339 pipe([1, 2, 4], Iter.filterMapWhile((n, i) => n === i + 1 ? Result.succeed(n + i) : Result.failVoid), toArray),
340 [1, 3]
341 )
342 })
343
344 it("getFailures", () => {
345 deepStrictEqual(toArray(Iter.getFailures([])), [])
346 deepStrictEqual(toArray(Iter.getFailures([Result.succeed(1), Result.fail("err"), Result.fail("nope")])), [
347 "err",
348 "nope"
349 ])
350 })
351
352 it("getSuccesses", () => {
353 deepStrictEqual(toArray(Iter.getSuccesses([])), [])
354 deepStrictEqual(toArray(Iter.getSuccesses([Result.fail("err"), Result.succeed(1), Result.succeed(2)])), [1, 2])
355 })
356
357 it("isEmpty", () => {
358 assertFalse(Iter.isEmpty([1, 2, 3]))
359 assertTrue(Iter.isEmpty([]))
360 })
361
362 it("head", () => {
363 const as: ReadonlyArray<number> = [1, 2, 3]
364 assertSome(Iter.head(as), 1)
365 assertNone(Iter.head([]))
366 })
367
368 it("chunksOf", () => {
369 deepStrictEqual(toArray(Iter.chunksOf(2)([1, 2, 3, 4, 5])), [
370 [1, 2],
371 [3, 4],
372 [5]
373 ])
374 deepStrictEqual(toArray(Iter.chunksOf(2)([1, 2, 3, 4, 5, 6])), [
375 [1, 2],
376 [3, 4],
377 [5, 6]
378 ])
379 deepStrictEqual(toArray(Iter.chunksOf(1)([1, 2, 3, 4, 5])), [[1], [2], [3], [4], [5]])
380 deepStrictEqual(toArray(Iter.chunksOf(5)([1, 2, 3, 4, 5])), [[1, 2, 3, 4, 5]])
381 // out of bounds
382 deepStrictEqual(toArray(Iter.chunksOf(0)([1, 2, 3, 4, 5])), [[1], [2], [3], [4], [5]])
383 deepStrictEqual(toArray(Iter.chunksOf(-1)([1, 2, 3, 4, 5])), [[1], [2], [3], [4], [5]])
384 deepStrictEqual(toArray(Iter.chunksOf(Number.NaN)([1, 2, 3])), [[1], [2], [3]])
385
386 const assertSingleChunk = (
387 input: Iterable<number>,
388 n: number
389 ) => {
390 const chunks = toArray(Iter.chunksOf(n)(input))
391 strictEqual(chunks.length, 1)
392 deepStrictEqual(chunks[0], input)
393 }
394 // n = length
395 assertSingleChunk([1, 2], 2)
396 // n out of bounds
397 assertSingleChunk([1, 2], 3)
398 })
399
400 it("flatten", () => {
401 deepStrictEqual(toArray(Iter.flatten([[1], [2], [3]])), [1, 2, 3])
402 })
403
404 it("flatten is stack safe across empty iterables", () => {
405 const input: Array<Iterable<number>> = Array.from({ length: 20_000 }, () => [])
406 input.push([1])
407
408 deepStrictEqual(toArray(Iter.flatten(input)), [1])
409 })
410
411 it("cartesianWith", () => {
412 const right = (function*() {
413 yield* [1, 2, 3]
414 })()
415 deepStrictEqual(toArray(Iter.cartesianWith(["a", "b"], right, (a, b) => `${a}${b}`)), [
416 "a1",
417 "a2",
418 "a3",
419 "b1",
420 "b2",
421 "b3"
422 ])
423 })
424
425 it("cartesian", () => {
426 const right = (function*() {
427 yield* [1, 2, 3]
428 })()
429 deepStrictEqual(toArray(Iter.cartesian(["a", "b"], right)), [
430 ["a", 1],
431 ["a", 2],
432 ["a", 3],
433 ["b", 1],
434 ["b", 2],
435 ["b", 3]
436 ])
437 })
438
439 it("cartesian keeps the right input lazy", () => {
440 const right: Iterable<number> = {
441 *[Symbol.iterator]() {
442 yield* [1, 2, 3]
443 throw new Error("right input was consumed eagerly")
444 }
445 }
446 deepStrictEqual(toArray(Iter.take(Iter.cartesian(["a", "b"], right), 3)), [
447 ["a", 1],
448 ["a", 2],
449 ["a", 3]
450 ])
451 })
452
453 it("groupWith", () => {
454 const groupWith = Iter.groupWith(Equivalence.strictEqual<number>())
455 deepStrictEqual(toArray(groupWith([1, 2, 1, 1])), [[1], [2], [1, 1]])
456 deepStrictEqual(toArray(groupWith([1, 2, 1, 1, 3])), [[1], [2], [1, 1], [3]])
457 })
458
459 it("groupBy", () => {
460 deepStrictEqual(Iter.groupBy((_) => "")([]), {})
461 deepStrictEqual(Iter.groupBy((a) => `${a}`)([1]), { "1": [1] })
462 deepStrictEqual(
463 Iter.groupBy((s: string) => `${s.length}`)(["foo", "bar", "foobar"]),
464 {
465 "3": ["foo", "bar"],
466 "6": ["foobar"]
467 }
468 )
469 deepStrictEqual(Iter.groupBy(["a", "b"], (s) => s === "a" ? symA : s === "b" ? symB : symC), {
470 [symA]: ["a"],
471 [symB]: ["b"]
472 })
473 deepStrictEqual(Iter.groupBy(["a", "b", "c", "d"], (s) => s === "a" ? symA : s === "b" ? symB : symC), {
474 [symA]: ["a"],
475 [symB]: ["b"],
476 [symC]: ["c", "d"]
477 })
478 })
479
480 it("makeBy", () => {
481 deepStrictEqual(
482 pipe(
483 Iter.makeBy((n) => n * 2),
484 Iter.take(5),
485 toArray
486 ),
487 [0, 2, 4, 6, 8]
488 )
489 deepStrictEqual(toArray(Iter.makeBy((n) => n * 2, { length: 5 })), [0, 2, 4, 6, 8])
490 deepStrictEqual(toArray(Iter.makeBy((n) => n * 2, { length: 2.2 })), [0, 2])
491 deepStrictEqual(toArray(Iter.makeBy((n) => n, { length: Number.NaN })), [0])
492 })
493
494 it("replicate", () => {
495 deepStrictEqual(toArray(Iter.replicate("a", 0)), ["a"])
496 deepStrictEqual(toArray(Iter.replicate("a", -1)), ["a"])
497 deepStrictEqual(toArray(Iter.replicate("a", 3)), ["a", "a", "a"])
498 deepStrictEqual(toArray(Iter.replicate("a", 2.2)), ["a", "a"])
499 deepStrictEqual(toArray(Iter.replicate("a", Number.NaN)), ["a"])
500 })
501
502 it("repeat", () => {
503 deepStrictEqual(toArray(Iter.repeat([1, 2], Number.NaN)), [1, 2])
504 })
505
506 it("range", () => {
507 deepStrictEqual(toArray(Iter.range(0, 0)), [0])
508 deepStrictEqual(toArray(Iter.range(0, 1)), [0, 1])
509 deepStrictEqual(toArray(Iter.range(1, 5)), [1, 2, 3, 4, 5])
510 deepStrictEqual(toArray(Iter.range(10, 15)), [10, 11, 12, 13, 14, 15])
511 deepStrictEqual(toArray(Iter.range(-1, 0)), [-1, 0])
512 deepStrictEqual(toArray(Iter.range(-5, -1)), [-5, -4, -3, -2, -1])
513 // out of bound
514 deepStrictEqual(Array.from(Iter.range(2, 1)), [2])
515 deepStrictEqual(Array.from(Iter.range(-1, -2)), [-1])
516 })
517
518 it("empty", () => {
519 deepStrictEqual(toArray(Iter.empty()).length, 0)
520 })
521
522 it("some", () => {
523 const isPositive: Predicate<number> = (n) => n > 0
524 assertTrue(Iter.some([-1, -2, 3], isPositive))
525 assertFalse(Iter.some([-1, -2, -3], isPositive))
526 })
527
528 it("size", () => {
529 strictEqual(Iter.size(Iter.empty()), 0)
530 strictEqual(Iter.size([]), 0)
531 strictEqual(Iter.size(["a"]), 1)
532 })
533
534 it("forEach", () => {
535 const log: Array<string> = []
536 Iter.forEach(["a", "b", "c"], (a, i) => log.push(`${a}-${i}`))
537 deepStrictEqual(log, ["a-0", "b-1", "c-2"])
538 })
539
540 it("countBy", () => {
541 deepStrictEqual(Iter.countBy([1, 2, 3, 4, 5], (n) => n % 2 === 0), 2)
542 deepStrictEqual(pipe([1, 2, 3, 4, 5], Iter.countBy((n) => n % 2 === 0)), 2)
543
544 deepStrictEqual(Iter.countBy(new Map([["a", 1], ["b", 2], ["c", 3]]), ([key, n]) => n % 2 === 1 && key !== "c"), 1)
545 })
546})