import { describe, it } from "@effect/vitest" import { assertEquals, assertFalse, assertNone, assertSome, assertTrue, deepStrictEqual, doesNotThrow, strictEqual, throws } from "@effect/vitest/utils" import type { Predicate } from "effect" import { Array as Arr, Chunk, Equal, Equivalence, Option, Order, Result } from "effect" import { identity, pipe } from "effect/Function" import { FastCheck as fc } from "effect/testing" const assertTuple = ( actual: [Chunk.Chunk, Chunk.Chunk], expected: [Chunk.Chunk, Chunk.Chunk] ) => { assertEquals(actual[0], expected[0]) assertEquals(actual[1], expected[1]) } describe("Chunk", () => { it("Equal.equals", () => { assertTrue(Equal.equals(Chunk.make(0), Chunk.make(0))) assertTrue(Equal.equals(Chunk.make(1, 2, 3), Chunk.make(1, 2, 3))) assertFalse(Equal.equals(Chunk.make(1, 2, 3), Chunk.make(1, 2))) assertFalse(Equal.equals(Chunk.make(1, 2), Chunk.make(1, 2, 3))) assertFalse(Equal.equals(Chunk.make(1, 2, 3), Chunk.make(1, "a", 3))) assertFalse(Equal.equals(Chunk.make(0), [0])) }) it("toString", () => { strictEqual( String(Chunk.make(0, 1, 2)), `Chunk([0,1,2])` ) strictEqual( String(Chunk.make(Chunk.make(1, 2, 3))), `Chunk([Chunk([1,2,3])])` ) }) it("toJSON", () => { deepStrictEqual(Chunk.make(0, 1, 2).toJSON(), { _id: "Chunk", values: [0, 1, 2] }) deepStrictEqual(Chunk.make(Chunk.make(1, 2, 3)).toJSON(), { _id: "Chunk", values: [{ _id: "Chunk", values: [1, 2, 3] }] }) }) it("inspect", () => { if (typeof window === "undefined") { // oxlint-disable-next-line @typescript-eslint/no-require-imports const { inspect } = require("node:util") assertEquals(inspect(Chunk.make(0, 1, 2)), inspect({ _id: "Chunk", values: [0, 1, 2] })) } }) it("modify", () => { assertNone(pipe(Chunk.empty(), Chunk.modify(0, (n: number) => n * 2))) assertSome( pipe(Chunk.make(1, 2, 3), Chunk.modify(0, (n: number) => n * 2)), Chunk.make(2, 2, 3) ) }) it("replace", () => { assertNone(pipe(Chunk.empty(), Chunk.replace(0, 2))) assertSome(pipe(Chunk.make(1, 2, 3), Chunk.replace(0, 2)), Chunk.make(2, 2, 3)) }) it("remove", () => { assertEquals(pipe(Chunk.empty(), Chunk.remove(0)), Chunk.empty()) assertEquals(pipe(Chunk.make(1, 2, 3), Chunk.remove(0)), Chunk.make(2, 3)) }) it("chunksOf", () => { assertEquals(pipe(Chunk.empty(), Chunk.chunksOf(2)), Chunk.empty()) assertEquals( pipe(Chunk.make(1, 2, 3, 4, 5), Chunk.chunksOf(2)), Chunk.make(Chunk.make(1, 2), Chunk.make(3, 4), Chunk.make(5)) ) assertEquals( pipe(Chunk.make(1, 2, 3, 4, 5, 6), Chunk.chunksOf(2)), Chunk.make(Chunk.make(1, 2), Chunk.make(3, 4), Chunk.make(5, 6)) ) assertEquals( pipe(Chunk.make(1, 2, 3, 4, 5), Chunk.chunksOf(1)), Chunk.make(Chunk.make(1), Chunk.make(2), Chunk.make(3), Chunk.make(4), Chunk.make(5)) ) assertEquals(pipe(Chunk.make(1, 2, 3, 4, 5), Chunk.chunksOf(5)), Chunk.make(Chunk.make(1, 2, 3, 4, 5))) // out of bounds assertEquals( pipe(Chunk.make(1, 2, 3, 4, 5), Chunk.chunksOf(0)), Chunk.make(Chunk.make(1), Chunk.make(2), Chunk.make(3), Chunk.make(4), Chunk.make(5)) ) assertEquals( pipe(Chunk.make(1, 2, 3, 4, 5), Chunk.chunksOf(-1)), Chunk.make(Chunk.make(1), Chunk.make(2), Chunk.make(3), Chunk.make(4), Chunk.make(5)) ) assertEquals(pipe(Chunk.make(1, 2, 3, 4, 5), Chunk.chunksOf(10)), Chunk.make(Chunk.make(1, 2, 3, 4, 5))) }) it(".pipe() method", () => { assertEquals(Chunk.empty().pipe(Chunk.append(1)), Chunk.make(1)) }) describe("toArray", () => { it("should return an empty array for an empty chunk", () => { deepStrictEqual(Chunk.toArray(Chunk.empty()), []) }) it("should return an array with the elements of the chunk", () => { deepStrictEqual(Chunk.toArray(Chunk.make(1, 2, 3)), [1, 2, 3]) }) it("should not affect the original chunk when the array is mutated", () => { const chunk = Chunk.make(1, 2, 3) const arr = Chunk.toArray(chunk) // mutate the array arr[1] = 4 // the chunk should not be affected deepStrictEqual(Chunk.toArray(chunk), [1, 2, 3]) }) }) describe("toReadonlyArray", () => { describe("Given an empty Chunk", () => { const chunk = Chunk.empty() it("should give back an empty readonly array", () => { deepStrictEqual(Chunk.toReadonlyArray(chunk), []) }) }) describe("Given a large Chunk", () => { const len = 100_000 let chunk = Chunk.empty() for (let i = 0; i < len; i++) chunk = Chunk.appendAll(Chunk.of(i), chunk) it("gives back a readonly array", () => { doesNotThrow(() => Chunk.toReadonlyArray(chunk)) deepStrictEqual(Chunk.toReadonlyArray(chunk), Arr.reverse(Arr.range(0, len - 1))) }) }) describe(`Given an imbalanced left and right chunk`, () => { const len = 1_000 let rchunk = Chunk.empty() let lchunk = Chunk.empty() for (let i = 0; i < len; i++) { rchunk = Chunk.appendAll(Chunk.of(i), rchunk) lchunk = Chunk.appendAll(lchunk, Chunk.of(i)) } it("should have depth of +/- 3", () => { assertTrue(rchunk.depth >= lchunk.depth - 3) assertTrue(rchunk.depth <= lchunk.depth + 3) }) }) }) describe("isChunk", () => { describe("Given a chunk", () => { const chunk = Chunk.make(0, 1) it("should be true", () => { assertTrue(Chunk.isChunk(chunk)) }) }) describe("Given an object", () => { const object = {} it("should be false", () => { assertFalse(Chunk.isChunk(object)) }) }) }) describe("fromIterable", () => { describe("Given an iterable", () => { const myIterable = { [Symbol.iterator]() { let i = 0 return { next() { i++ return { value: i, done: i > 5 } } } } } it("should process it", () => { assertEquals(Chunk.fromIterable(myIterable), Chunk.fromArrayUnsafe([1, 2, 3, 4, 5])) }) }) it("should return the same reference if the input is a Chunk", () => { const expected = Chunk.make(1, 2, 3) const actual = Chunk.fromIterable(expected) assertTrue(actual === expected) }) }) describe("get", () => { describe("Given a Chunk and an index within the bounds", () => { const chunk = Chunk.fromArrayUnsafe([1, 2, 3]) const index = 0 it("should a Some with the value", () => { deepStrictEqual(pipe(chunk, Chunk.get(index)), Option.some(1)) }) }) describe("Given a Chunk and an index out of bounds", () => { const chunk = Chunk.fromArrayUnsafe([1, 2, 3]) it("should return a None", () => { assertNone(pipe(chunk, Chunk.get(4))) }) }) }) describe("getUnsafe", () => { describe("Given an empty Chunk and an index", () => { const chunk = Chunk.empty() const index = 4 it("should throw", () => { throws(() => pipe(chunk, Chunk.getUnsafe(index))) }) }) describe("Given an appended Chunk and an index out of bounds", () => { const chunk = pipe(Chunk.empty(), Chunk.append(1)) const index = 4 it("should throw", () => { throws(() => pipe(chunk, Chunk.getUnsafe(index))) }) }) describe("Given an appended Chunk and an index in bounds", () => { it("should return the value", () => { const chunk = pipe(Chunk.make(0, 1, 2), Chunk.append(3)) strictEqual(Chunk.getUnsafe(1)(chunk), 1) }) }) describe("Given a prepended Chunk and an index out of bounds", () => { it("should throw", () => { fc.assert(fc.property(fc.array(fc.anything()), (array) => { let chunk: Chunk.Chunk = Chunk.empty() array.forEach((e) => { chunk = pipe(chunk, Chunk.prepend(e)) }) throws(() => pipe(chunk, Chunk.getUnsafe(array.length))) })) }) }) describe("Given a prepended Chunk and an index in bounds", () => { it("should return the value", () => { const chunk = pipe(Chunk.make(0, 1, 2), Chunk.prepend(3)) strictEqual(Chunk.getUnsafe(1)(chunk), 0) }) }) describe("Given a singleton Chunk and an index out of bounds", () => { const chunk = Chunk.make(1) const index = 4 it("should throw", () => { throws(() => pipe(chunk, Chunk.getUnsafe(index))) }) }) describe("Given an array Chunk and an index out of bounds", () => { const chunk = Chunk.fromArrayUnsafe([1, 2]) const index = 4 it("should throw", () => { throws(() => pipe(chunk, Chunk.getUnsafe(index))) }) }) describe("Given a concat Chunk and an index out of bounds", () => { it("should throw", () => { fc.assert(fc.property(fc.array(fc.anything()), fc.array(fc.anything()), (arr1, arr2) => { const chunk: Chunk.Chunk = Chunk.appendAll(Chunk.fromIterable(arr2))(Chunk.fromArrayUnsafe(arr1)) throws(() => pipe(chunk, Chunk.getUnsafe(arr1.length + arr2.length))) })) }) }) describe("Given an appended Chunk and an index in bounds", () => { const chunk = pipe(Chunk.empty(), Chunk.append(1), Chunk.append(2)) const index = 1 it("should return the value", () => { strictEqual(pipe(chunk, Chunk.getUnsafe(index)), 2) }) }) describe("Given a prepended Chunk and an index in bounds", () => { const chunk = pipe(Chunk.empty(), Chunk.prepend(2), Chunk.prepend(1)) const index = 1 it("should return the value", () => { strictEqual(pipe(chunk, Chunk.getUnsafe(index)), 2) }) }) describe("Given a singleton Chunk and an index in bounds", () => { const chunk = Chunk.make(1) const index = 0 it("should return the value", () => { strictEqual(pipe(chunk, Chunk.getUnsafe(index)), 1) }) }) describe("Given an array Chunk and an index in bounds", () => { const chunk = pipe(Chunk.fromArrayUnsafe([1, 2, 3])) const index = 1 it("should return the value", () => { strictEqual(pipe(chunk, Chunk.getUnsafe(index)), 2) }) }) describe("Given a concat Chunk and an index in bounds", () => { it("should return the value", () => { fc.assert(fc.property(fc.array(fc.anything()), fc.array(fc.anything()), (a, b) => { const c = [...a, ...b] const d = Chunk.appendAll(Chunk.fromArrayUnsafe(b))(Chunk.fromArrayUnsafe(a)) for (let i = 0; i < c.length; i++) { deepStrictEqual(Chunk.getUnsafe(i)(d), c[i]) } })) }) }) }) it("append", () => { fc.assert( fc.property( fc.array(fc.integer()), fc.array(fc.integer(), { minLength: 0, maxLength: 120, size: "xlarge" }), (a, b) => { let chunk = Chunk.fromArrayUnsafe(a) b.forEach((e) => { chunk = Chunk.append(e)(chunk) }) deepStrictEqual(Chunk.toReadonlyArray(chunk), [...a, ...b]) } ) ) }) it("prependAll", () => { assertEquals(pipe(Chunk.empty(), Chunk.prependAll(Chunk.make(1))), Chunk.make(1)) assertEquals(pipe(Chunk.make(1), Chunk.prependAll(Chunk.empty())), Chunk.make(1)) assertEquals(pipe(Chunk.empty(), Chunk.prependAll(Chunk.make(1, 2))), Chunk.make(1, 2)) assertEquals(pipe(Chunk.make(1, 2), Chunk.prependAll(Chunk.empty())), Chunk.make(1, 2)) assertEquals(pipe(Chunk.make(2, 3), Chunk.prependAll(Chunk.make(1))), Chunk.make(1, 2, 3)) assertEquals(pipe(Chunk.make(3), Chunk.prependAll(Chunk.make(1, 2))), Chunk.make(1, 2, 3)) }) it("prepend", () => { fc.assert( fc.property( fc.array(fc.integer()), fc.array(fc.integer(), { minLength: 0, maxLength: 120, size: "xlarge" }), (a, b) => { let chunk = Chunk.fromArrayUnsafe(a) for (let i = b.length - 1; i >= 0; i--) { chunk = Chunk.prepend(b[i])(chunk) } deepStrictEqual(Chunk.toReadonlyArray(chunk), [...b, ...a]) } ) ) }) describe("take", () => { describe("Given a Chunk with more elements than the amount taken", () => { it("should return the subset", () => { assertEquals(pipe(Chunk.fromArrayUnsafe([1, 2, 3]), Chunk.take(2)), Chunk.fromArrayUnsafe([1, 2])) }) }) describe("Given a Chunk with fewer elements than the amount taken", () => { const chunk = Chunk.fromArrayUnsafe([1, 2, 3]) const amount = 5 it("should return the available subset", () => { assertEquals(pipe(chunk, Chunk.take(amount)), Chunk.fromArrayUnsafe([1, 2, 3])) }) }) describe("Given a slice Chunk with and an amount", () => { const chunk = pipe(Chunk.fromArrayUnsafe([1, 2, 3, 4, 5]), Chunk.take(4)) const amount = 3 it("should return the available subset", () => { assertEquals(pipe(chunk, Chunk.take(amount)), Chunk.fromArrayUnsafe([1, 2, 3])) }) }) describe("Given a singleton Chunk with and an amount > 1", () => { const chunk = Chunk.make(1) const amount = 2 it("should return the available subset", () => { assertEquals(pipe(chunk, Chunk.take(amount)), Chunk.fromArrayUnsafe([1])) }) }) describe("Given a concatenated Chunk and an amount > 1", () => { const chunk = pipe(Chunk.of(1), Chunk.appendAll(Chunk.make(2, 3, 4))) const amount = 2 it("should return the available subset", () => { deepStrictEqual(pipe(chunk, Chunk.take(amount), Chunk.toReadonlyArray), [1, 2]) }) }) describe("Given a concatenated Chunk and an amount <= self.left", () => { it("should return the available subset", () => { const chunk = Chunk.appendAll(Chunk.make(2, 3, 4), Chunk.of(1)) deepStrictEqual(pipe(chunk, Chunk.take(2), Chunk.toReadonlyArray), [2, 3]) deepStrictEqual(pipe(chunk, Chunk.take(3), Chunk.toReadonlyArray), [2, 3, 4]) }) }) }) describe("make", () => { it("should return a NonEmptyChunk", () => { strictEqual(Chunk.make(0, 1).length, 2) }) }) describe("singleton", () => { it("should return a NonEmptyChunk", () => { strictEqual(Chunk.of(1).length, 1) }) it("should return a ISingleton", () => { strictEqual(Chunk.of(1).backing._tag, "ISingleton") }) }) describe("drop", () => { it("should return self on 0", () => { const self = Chunk.make(0, 1) strictEqual(Chunk.drop(0)(self), self) }) it("should drop twice", () => { const self = Chunk.make(0, 1, 2, 3) deepStrictEqual(Chunk.toReadonlyArray(Chunk.drop(1)(Chunk.drop(1)(self))), [2, 3]) }) it("should handle concatenated chunks", () => { const self = pipe(Chunk.make(1), Chunk.appendAll(Chunk.make(2, 3, 4))) deepStrictEqual(pipe(self, Chunk.drop(2), Chunk.toReadonlyArray), [3, 4]) }) }) describe("dropRight", () => { describe("Given a Chunk and an amount to drop below the length", () => { const chunk = Chunk.fromArrayUnsafe([1, 2, 3]) const toDrop = 1 it("should remove the given amount of items", () => { assertEquals(pipe(chunk, Chunk.dropRight(toDrop)), Chunk.fromArrayUnsafe([1, 2])) }) }) describe("Given a Chunk and an amount to drop above the length", () => { const chunk = Chunk.fromArrayUnsafe([1, 2]) const toDrop = 3 it("should return an empty chunk", () => { assertEquals(pipe(chunk, Chunk.dropRight(toDrop)), Chunk.fromArrayUnsafe([])) }) }) }) describe("dropWhile", () => { describe("Given a Chunk and a criteria that applies to part of the chunk", () => { const chunk = Chunk.fromArrayUnsafe([1, 2, 3]) const criteria = (n: number) => n < 3 it("should return the subset that doesn't pass the criteria", () => { assertEquals(pipe(chunk, Chunk.dropWhile(criteria)), Chunk.fromArrayUnsafe([3])) }) }) describe("Given a Chunk and a criteria that applies to the whole chunk", () => { const chunk = Chunk.fromArrayUnsafe([1, 2, 3]) const criteria = (n: number) => n < 4 it("should return an empty chunk", () => { assertEquals(pipe(chunk, Chunk.dropWhile(criteria)), Chunk.fromArrayUnsafe([])) }) }) }) describe("concat", () => { describe("Given 2 chunks of the same length", () => { const chunk1 = Chunk.fromArrayUnsafe([0, 1]) const chunk2 = Chunk.fromArrayUnsafe([2, 3]) it("should concatenate them following order", () => { assertEquals(pipe(chunk1, Chunk.appendAll(chunk2)), Chunk.fromArrayUnsafe([0, 1, 2, 3])) }) }) describe("Given 2 chunks where the first one has more elements than the second one", () => { const chunk1 = Chunk.fromArrayUnsafe([1, 2]) const chunk2 = Chunk.fromArrayUnsafe([3]) it("should concatenate them following order", () => { assertEquals(pipe(chunk1, Chunk.appendAll(chunk2)), Chunk.fromArrayUnsafe([1, 2, 3])) }) }) describe("Given 2 chunks where the first one has fewer elements than the second one", () => { const chunk1 = Chunk.fromArrayUnsafe([1]) const chunk2 = Chunk.fromArrayUnsafe([2, 3, 4]) it("should concatenate them following order", () => { assertEquals(pipe(chunk1, Chunk.appendAll(chunk2)), Chunk.fromArrayUnsafe([1, 2, 3, 4])) }) }) describe("Given 2 chunks where the first one is appended", () => { const chunk1 = pipe( Chunk.empty(), Chunk.append(1) ) const chunk2 = Chunk.fromArrayUnsafe([2, 3, 4]) it("should concatenate them following order", () => { assertEquals(pipe(chunk1, Chunk.appendAll(chunk2)), Chunk.fromArrayUnsafe([1, 2, 3, 4])) }) }) describe("Given 2 chunks where the second one is appended", () => { const chunk1 = Chunk.fromArrayUnsafe([1]) const chunk2 = pipe( Chunk.empty(), Chunk.prepend(2) ) it("should concatenate them following order", () => { assertEquals(pipe(chunk1, Chunk.appendAll(chunk2)), Chunk.fromArrayUnsafe([1, 2])) }) }) describe("Given 2 chunks where the first one is empty", () => { const chunk1 = Chunk.empty() const chunk2 = Chunk.fromArrayUnsafe([1, 2]) it("should concatenate them following order", () => { assertEquals(pipe(chunk1, Chunk.appendAll(chunk2)), Chunk.fromArrayUnsafe([1, 2])) }) }) describe("Given 2 chunks where the second one is empty", () => { const chunk1 = Chunk.fromArrayUnsafe([1, 2]) const chunk2 = Chunk.empty() it("should concatenate them following order", () => { assertEquals(pipe(chunk1, Chunk.appendAll(chunk2)), Chunk.fromArrayUnsafe([1, 2])) }) }) describe("Given several chunks concatenated with each", () => { const chunk1 = Chunk.empty() const chunk2 = Chunk.fromArrayUnsafe([1]) const chunk3 = Chunk.fromArrayUnsafe([2]) const chunk4 = Chunk.fromArrayUnsafe([3, 4]) const chunk5 = Chunk.fromArrayUnsafe([5, 6]) it("should concatenate them following order", () => { assertEquals( pipe( chunk1, Chunk.appendAll(chunk2), Chunk.appendAll(chunk3), Chunk.appendAll(chunk4), Chunk.appendAll(chunk5) ), Chunk.fromArrayUnsafe([1, 2, 3, 4, 5, 6]) ) }) }) }) it("zip", () => { assertEquals(Chunk.zip(Chunk.empty(), Chunk.empty()), Chunk.empty()) assertEquals(Chunk.zip(Chunk.make(1), Chunk.empty()), Chunk.empty()) assertEquals(Chunk.zip(Chunk.empty(), Chunk.make(1)), Chunk.empty()) deepStrictEqual(Chunk.toArray(Chunk.zip(Chunk.make(1), Chunk.make(2))), [[1, 2]]) }) describe("Given two non-materialized chunks of different sizes", () => { it("should zip the chunks together and drop the leftover", () => { // Create two non-materialized Chunks const left = pipe(Chunk.make(-1, 0, 1), Chunk.drop(1)) const right = pipe(Chunk.make(1, 0, 0, 1), Chunk.drop(1)) const zipped = pipe(left, Chunk.zipWith(pipe(right, Chunk.take(left.length)), (a, b) => [a, b])) deepStrictEqual(Array.from(zipped), [[0, 0], [1, 0]]) }) }) it("last", () => { assertNone(Chunk.last(Chunk.empty())) assertSome(Chunk.last(Chunk.make(1, 2, 3)), 3) }) it("map", () => { assertEquals(Chunk.map(Chunk.empty(), (n) => n + 1), Chunk.empty()) assertEquals(Chunk.map(Chunk.of(1), (n) => n + 1), Chunk.of(2)) assertEquals(Chunk.map(Chunk.make(1, 2, 3), (n) => n + 1), Chunk.make(2, 3, 4)) assertEquals(Chunk.map(Chunk.make(1, 2, 3), (n, i) => n + i), Chunk.make(1, 3, 5)) }) it("mapAccum", () => { deepStrictEqual(Chunk.mapAccum(Chunk.make(1, 2, 3), "-", (s, a) => [s + a, a + 1]), ["-123", Chunk.make(2, 3, 4)]) }) it("partition", () => { assertTuple( Chunk.partition(Chunk.empty(), (n) => n > 2 ? Result.succeed(n) : Result.fail(n)), [Chunk.empty(), Chunk.empty()] ) assertTuple( Chunk.partition(Chunk.make(1, 3), (n) => n > 2 ? Result.succeed(n) : Result.fail(n)), [Chunk.make(1), Chunk.make(3)] ) assertTuple( Chunk.partition( Chunk.empty(), (n, i) => n + i > 2 ? Result.succeed(n + i) : Result.fail(`negative:${n + i}`) ), [Chunk.empty(), Chunk.empty()] ) assertTuple( Chunk.partition(Chunk.make(1, 2), (n, i) => n + i > 2 ? Result.succeed(n + i) : Result.fail(`negative:${n + i}`)), [Chunk.make("negative:1"), Chunk.make(3)] ) }) it("partition (identity)", () => { assertTuple(Chunk.partition(Chunk.empty(), identity), [Chunk.empty(), Chunk.empty()]) assertTuple(Chunk.partition(Chunk.make(Result.succeed(1), Result.fail("a"), Result.succeed(2)), identity), [ Chunk.make("a"), Chunk.make(1, 2) ]) }) it("separate", () => { assertTuple(Chunk.separate(Chunk.empty()), [Chunk.empty(), Chunk.empty()]) assertTuple(Chunk.separate(Chunk.make(Result.succeed(1), Result.fail("e"), Result.succeed(2))), [ Chunk.make("e"), Chunk.make(1, 2) ]) }) it("size", () => { strictEqual(Chunk.size(Chunk.empty()), 0) strictEqual(Chunk.size(Chunk.make(1, 2, 3)), 3) }) it("split", () => { assertEquals(pipe(Chunk.empty(), Chunk.split(2)), Chunk.empty()) assertEquals(pipe(Chunk.make(1), Chunk.split(2)), Chunk.make(Chunk.make(1))) assertEquals(pipe(Chunk.make(1, 2), Chunk.split(2)), Chunk.make(Chunk.make(1), Chunk.make(2))) assertEquals(pipe(Chunk.make(1, 2, 3, 4, 5), Chunk.split(2)), Chunk.make(Chunk.make(1, 2, 3), Chunk.make(4, 5))) assertEquals( pipe(Chunk.make(1, 2, 3, 4, 5), Chunk.split(3)), Chunk.make(Chunk.make(1, 2), Chunk.make(3, 4), Chunk.make(5)) ) }) it("tail", () => { assertNone(Chunk.tail(Chunk.empty())) const tail = Chunk.tail(Chunk.make(1, 2, 3)) assertTrue(Option.isSome(tail)) assertEquals(tail.value, Chunk.make(2, 3)) }) it("filter", () => { assertEquals(Chunk.filter(Chunk.make(1, 2, 3), (n) => n % 2 === 1), Chunk.make(1, 3)) assertEquals( Chunk.filter(Chunk.make(Option.some(3), Option.some(2), Option.some(1)), Option.isSome), Chunk.make(Option.some(3), Option.some(2), Option.some(1)) as any ) assertEquals( Chunk.filter(Chunk.make(Option.some(3), Option.none(), Option.some(1)), Option.isSome), Chunk.make(Option.some(3), Option.some(1)) as any ) }) it("filterMap", () => { assertEquals( Chunk.filterMap(Chunk.make(1, 2, 3, 4), (n) => n % 2 === 0 ? Result.succeed(n * 2) : Result.failVoid), Chunk.make(4, 8) ) assertEquals( Chunk.filterMap(Chunk.make(1, 2, 3, 4), (n, i) => i % 2 === 0 ? Result.succeed(n + i) : Result.failVoid), Chunk.make(1, 5) ) }) it("filterMapWhile", () => { assertEquals( Chunk.filterMapWhile(Chunk.make(1, 3, 4, 5), (n) => n % 2 === 1 ? Result.succeed(n) : Result.failVoid), Chunk.make(1, 3) ) }) it("compact", () => { assertEquals(Chunk.compact(Chunk.empty()), Chunk.empty()) assertEquals(Chunk.compact(Chunk.make(Option.some(1), Option.some(2), Option.some(3))), Chunk.make(1, 2, 3)) assertEquals(Chunk.compact(Chunk.make(Option.some(1), Option.none(), Option.some(3))), Chunk.make(1, 3)) }) it("dedupeAdjacent", () => { assertEquals(Chunk.dedupeAdjacent(Chunk.empty()), Chunk.empty()) assertEquals(Chunk.dedupeAdjacent(Chunk.make(1, 2, 3)), Chunk.make(1, 2, 3)) assertEquals(Chunk.dedupeAdjacent(Chunk.make(1, 2, 2, 3, 3)), Chunk.make(1, 2, 3)) }) it("flatMap", () => { assertEquals(Chunk.flatMap(Chunk.make(1), (n) => Chunk.make(n, n + 1)), Chunk.make(1, 2)) assertEquals(Chunk.flatMap(Chunk.make(1, 2, 3), (n) => Chunk.make(n, n + 1)), Chunk.make(1, 2, 2, 3, 3, 4)) }) it("union", () => { assertEquals(Chunk.union(Chunk.make(1, 2, 3), Chunk.empty()), Chunk.make(1, 2, 3)) assertEquals(Chunk.union(Chunk.empty(), Chunk.make(1, 2, 3)), Chunk.make(1, 2, 3)) assertEquals(Chunk.union(Chunk.make(1, 2, 3), Chunk.make(2, 3, 4)), Chunk.make(1, 2, 3, 4)) }) it("intersection", () => { assertEquals(Chunk.intersection(Chunk.make(1, 2, 3), Chunk.empty()), Chunk.empty()) assertEquals(Chunk.intersection(Chunk.empty(), Chunk.make(2, 3, 4)), Chunk.empty()) assertEquals(Chunk.intersection(Chunk.make(1, 2, 3), Chunk.make(2, 3, 4)), Chunk.make(2, 3)) }) it("isEmpty", () => { assertTrue(Chunk.isEmpty(Chunk.empty())) assertFalse(Chunk.isEmpty(Chunk.make(1))) }) it("lastUnsafe", () => { strictEqual(Chunk.lastUnsafe(Chunk.make(1)), 1) strictEqual(Chunk.lastUnsafe(Chunk.make(1, 2, 3)), 3) throws(() => Chunk.lastUnsafe(Chunk.empty()), new Error("Index out of bounds: -1")) }) it("splitNonEmptyAt", () => { assertTuple(Chunk.splitNonEmptyAt(Chunk.make(1, 2, 3, 4), 2), [Chunk.make(1, 2), Chunk.make(3, 4)]) assertTuple(Chunk.splitNonEmptyAt(Chunk.make(1, 2, 3, 4), 10), [Chunk.make(1, 2, 3, 4), Chunk.empty()]) }) it("splitWhere", () => { assertTuple(Chunk.splitWhere(Chunk.empty(), (n) => n > 1), [Chunk.empty(), Chunk.empty()]) assertTuple(Chunk.splitWhere(Chunk.make(1, 2, 3), (n) => n > 1), [Chunk.make(1), Chunk.make(2, 3)]) }) it("takeWhile", () => { assertEquals(Chunk.takeWhile(Chunk.empty(), (n) => n <= 2), Chunk.empty()) assertEquals(Chunk.takeWhile(Chunk.make(1, 2, 3), (n) => n <= 2), Chunk.make(1, 2)) }) it("dedupe", () => { assertEquals(Chunk.dedupe(Chunk.empty()), Chunk.empty()) assertEquals(Chunk.dedupe(Chunk.make(1, 2, 3)), Chunk.make(1, 2, 3)) assertEquals(Chunk.dedupe(Chunk.make(1, 2, 3, 2, 1, 3)), Chunk.make(1, 2, 3)) }) it("unzip", () => { assertTuple(Chunk.unzip(Chunk.empty()), [Chunk.empty(), Chunk.empty()]) assertTuple(Chunk.unzip(Chunk.make(["a", 1] as const, ["b", 2] as const)), [ Chunk.make("a", "b"), Chunk.make(1, 2) ]) }) it("reverse", () => { assertEquals(Chunk.reverse(Chunk.empty()), Chunk.empty()) assertEquals(Chunk.reverse(Chunk.make(1, 2, 3)), Chunk.make(3, 2, 1)) assertEquals(Chunk.reverse(Chunk.take(Chunk.make(1, 2, 3, 4), 3)), Chunk.make(3, 2, 1)) }) it("flatten", () => { assertEquals(Chunk.flatten(Chunk.make(Chunk.make(1), Chunk.make(2), Chunk.make(3))), Chunk.make(1, 2, 3)) }) it("makeBy", () => { assertEquals(Chunk.makeBy(5, (n) => n * 2), Chunk.make(0, 2, 4, 6, 8)) assertEquals(Chunk.makeBy(2.2, (n) => n * 2), Chunk.make(0, 2)) }) it("range", () => { assertEquals(Chunk.range(0, 0), Chunk.make(0)) assertEquals(Chunk.range(0, 1), Chunk.make(0, 1)) assertEquals(Chunk.range(1, 5), Chunk.make(1, 2, 3, 4, 5)) assertEquals(Chunk.range(10, 15), Chunk.make(10, 11, 12, 13, 14, 15)) assertEquals(Chunk.range(-1, 0), Chunk.make(-1, 0)) assertEquals(Chunk.range(-5, -1), Chunk.make(-5, -4, -3, -2, -1)) // out of bound assertEquals(Chunk.range(2, 1), Chunk.make(2)) assertEquals(Chunk.range(-1, -2), Chunk.make(-1)) }) it("some", () => { const isPositive: Predicate.Predicate = (n) => n > 0 assertTrue(Chunk.some(Chunk.make(-1, -2, 3), isPositive)) assertFalse(Chunk.some(Chunk.make(-1, -2, -3), isPositive)) }) it("forEach", () => { const as: Array = [] Chunk.forEach(Chunk.make(1, 2, 3, 4), (n, i) => as.push(`${n}-${i}`)) deepStrictEqual(as, ["1-0", "2-1", "3-2", "4-3"]) }) it("sortWith", () => { type X = { a: string b: number } const chunk: Chunk.Chunk = Chunk.make({ a: "a", b: 2 }, { a: "b", b: 1 }) deepStrictEqual(Chunk.sortWith(chunk, (x) => x.b, Order.Number), Chunk.make({ a: "b", b: 1 }, { a: "a", b: 2 })) }) it("makeEquivalence", () => { const equivalence = Chunk.makeEquivalence(Equivalence.strictEqual()) assertTrue(equivalence(Chunk.empty(), Chunk.empty())) assertTrue(equivalence(Chunk.make(1, 2, 3), Chunk.make(1, 2, 3))) assertFalse(equivalence(Chunk.make(1, 2, 3), Chunk.make(1, 2))) assertFalse(equivalence(Chunk.make(1, 2, 3), Chunk.make(1, 2, 4))) }) it("differenceWith", () => { const eq = (a: E, b: E) => a.id === b.id const differenceWith = pipe(eq, Chunk.differenceWith) const chunk = Chunk.make({ id: 1 }, { id: 2 }, { id: 3 }) deepStrictEqual(differenceWith(chunk, Chunk.make({ id: 1 }, { id: 2 })), Chunk.make({ id: 3 })) assertEquals(differenceWith(Chunk.empty(), chunk), Chunk.empty()) assertEquals(differenceWith(chunk, Chunk.empty()), chunk) assertEquals(differenceWith(chunk, chunk), Chunk.empty()) }) it("difference", () => { const curr = Chunk.make(1, 3, 5, 7, 9) assertEquals(Chunk.difference(curr, Chunk.make(1, 2, 3, 4, 5)), Chunk.make(7, 9)) assertEquals(Chunk.difference(Chunk.empty(), curr), Chunk.empty()) assertEquals(Chunk.difference(curr, Chunk.empty()), curr) assertEquals(Chunk.difference(curr, curr), Chunk.empty()) }) })