From ea0dc1fb6ad270ce6e32666d039829af93a8b555 Mon Sep 17 00:00:00 2001 From: Smoren Date: Sun, 3 Mar 2024 13:40:03 +0300 Subject: [PATCH] Package size optimization --- CHANGELOG.md | 4 + package.json | 5 +- src/async-stream.ts | 2 +- tests/async-stream/summary.test.ts | 100 +-- tests/examples/async-stram.test.ts | 1141 ++++++++++++++++++++++++++++ tests/examples/stream.test.ts | 1064 ++++++++++++++++++++++++++ 6 files changed, 2262 insertions(+), 54 deletions(-) create mode 100644 tests/examples/async-stram.test.ts create mode 100644 tests/examples/stream.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 07e8a02..83f325b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # IterTools Typescript Change Log +## v1.27.1 - 2024-03-03 + +Package Size Optimization. + ## v1.27.0 - 2023-11-13 ### New features diff --git a/package.json b/package.json index c98fe8e..71da882 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "itertools-ts", - "version": "1.27.0", + "version": "1.27.1", "description": "Extended itertools port for TypeScript and JavaScript. Provides a huge set of functions for working with iterable collections (including async ones)", "license": "MIT", "repository": { @@ -32,8 +32,7 @@ "es", "lib", "src", - "tests/stream", - "tests/async-stream", + "tests/examples", "tests/fixture.ts", "tests/tools" ], diff --git a/src/async-stream.ts b/src/async-stream.ts index e43783e..d383015 100644 --- a/src/async-stream.ts +++ b/src/async-stream.ts @@ -965,7 +965,7 @@ export class AsyncStream { * * @see summary.exactlyNAsync */ - async exactlyNAsync( + async exactlyN( n: number, predicate?: (item: unknown) => Promise | boolean ): Promise { diff --git a/tests/async-stream/summary.test.ts b/tests/async-stream/summary.test.ts index faf144e..1f03ea1 100644 --- a/tests/async-stream/summary.test.ts +++ b/tests/async-stream/summary.test.ts @@ -111,17 +111,17 @@ function dataProviderForArraysTrue(): Array { [ [], (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ [''], (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ [1, 3, 5], (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(3), + .exactlyN(3), ], [ [1, -1, 2, -2, 3, -3], @@ -226,17 +226,17 @@ function dataProviderForGeneratorsTrue(): Array { [ createGeneratorFixture([]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ createGeneratorFixture(['']), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ createGeneratorFixture([1, 3, 5]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(3), + .exactlyN(3), ], [ createGeneratorFixture([1, -1, 2, -2, 3, -3]), @@ -341,17 +341,17 @@ function dataProviderForIterablesTrue(): Array { [ createIterableFixture([]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ createIterableFixture(['']), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ createIterableFixture([1, 3, 5]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(3), + .exactlyN(3), ], [ createIterableFixture([1, -1, 2, -2, 3, -3]), @@ -456,17 +456,17 @@ function dataProviderForIteratorsTrue(): Array { [ createIteratorFixture([]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ createIteratorFixture(['']), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ createIteratorFixture([1, 3, 5]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(3), + .exactlyN(3), ], [ createIteratorFixture([1, -1, 2, -2, 3, -3]), @@ -566,7 +566,7 @@ function dataProviderForStringsTrue(): Array { [ '', (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ '123', @@ -679,17 +679,17 @@ function dataProviderForSetsTrue(): Array { [ new Set([]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ new Set(['']), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ new Set([1, 3, 5]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(3), + .exactlyN(3), ], [ new Set([1, -1, 2, -2, 3, -3]), @@ -906,17 +906,17 @@ function dataProviderForAsyncGeneratorsTrue(): Array { [ createAsyncGeneratorFixture([]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ createAsyncGeneratorFixture(['']), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ createAsyncGeneratorFixture([1, 3, 5]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(3), + .exactlyN(3), ], [ createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), @@ -1030,17 +1030,17 @@ function dataProviderForAsyncIterablesTrue(): Array { [ createAsyncIterableFixture([]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ createAsyncIterableFixture(['']), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ createAsyncIterableFixture([1, 3, 5]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(3), + .exactlyN(3), ], [ createAsyncIterableFixture([1, -1, 2, -2, 3, -3]), @@ -1154,17 +1154,17 @@ function dataProviderForAsyncIteratorsTrue(): Array { [ createAsyncIteratorFixture([]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ createAsyncIteratorFixture(['']), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(0), + .exactlyN(0), ], [ createAsyncIteratorFixture([1, 3, 5]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(3), + .exactlyN(3), ], [ createAsyncIteratorFixture([1, -1, 2, -2, 3, -3]), @@ -1257,17 +1257,17 @@ function dataProviderForArraysFalse(): Array { [ [], (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ [''], (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ [1, 3, 5], (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(4), + .exactlyN(4), ], [ [1, -1, 2, -2, 3, -3], @@ -1345,17 +1345,17 @@ function dataProviderForGeneratorsFalse(): Array { [ createGeneratorFixture([]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ createGeneratorFixture(['']), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ createGeneratorFixture([1, 3, 5]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(4), + .exactlyN(4), ], [ createGeneratorFixture([1, -1, 2, -2, 3, -3]), @@ -1433,17 +1433,17 @@ function dataProviderForIterablesFalse(): Array { [ createIterableFixture([]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ createIterableFixture(['']), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ createIterableFixture([1, 3, 5]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(4), + .exactlyN(4), ], [ createIterableFixture([1, -1, 2, -2, 3, -3]), @@ -1521,17 +1521,17 @@ function dataProviderForIteratorsFalse(): Array { [ createIteratorFixture([]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ createIteratorFixture(['']), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ createIteratorFixture([1, 3, 5]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(4), + .exactlyN(4), ], [ createIteratorFixture([1, -1, 2, -2, 3, -3]), @@ -1609,7 +1609,7 @@ function dataProviderForStringsFalse(): Array { [ '', (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ '131', @@ -1686,17 +1686,17 @@ function dataProviderForSetsFalse(): Array { [ new Set([]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ new Set(['']), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ new Set([1, 3, 5]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(4), + .exactlyN(4), ], [ new Set([1, -1, 2, -2, 3, -3]), @@ -1860,17 +1860,17 @@ function dataProviderForAsyncGeneratorsFalse(): Array { [ createAsyncGeneratorFixture([]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ createAsyncGeneratorFixture(['']), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ createAsyncGeneratorFixture([1, 3, 5]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(4), + .exactlyN(4), ], [ createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), @@ -1957,17 +1957,17 @@ function dataProviderForAsyncIterablesFalse(): Array { [ createAsyncIterableFixture([]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ createAsyncIterableFixture(['']), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ createAsyncIterableFixture([1, 3, 5]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(4), + .exactlyN(4), ], [ createAsyncIterableFixture([1, -1, 2, -2, 3, -3]), @@ -2054,17 +2054,17 @@ function dataProviderForAsyncIteratorsFalse(): Array { [ createAsyncIteratorFixture([]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ createAsyncIteratorFixture(['']), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(1), + .exactlyN(1), ], [ createAsyncIteratorFixture([1, 3, 5]), (iterable: Iterable) => AsyncStream.of(iterable) - .exactlyNAsync(4), + .exactlyN(4), ], [ createAsyncIteratorFixture([1, -1, 2, -2, 3, -3]), diff --git a/tests/examples/async-stram.test.ts b/tests/examples/async-stram.test.ts new file mode 100644 index 0000000..61cd77d --- /dev/null +++ b/tests/examples/async-stram.test.ts @@ -0,0 +1,1141 @@ +import { + asyncTimeout, + createAsyncGeneratorFixture, + createAsyncIterableFixture, + createAsyncIteratorFixture, + createGeneratorFixture, + createIterableFixture, + createIteratorFixture, + createMapFixture, + expectToBeCloseToArray, + // @ts-ignore +} from "../fixture"; +import { AsyncStream, Comparable, multi, single, Stream } from "../../src"; + +describe.each([ + ...dataProviderForOfCount(), +] as Array<[Array, number, Array]>)( + "Stream Infinite Of Count Test", + ( + inputParams: Array, + limit: number, + expected: Array + ) => { + it("", async () => { + // When + const stream = AsyncStream.ofCount(...inputParams); + const result = await stream.limit(limit).toArray() as Array; + + // Then + expectToBeCloseToArray(result, expected); + }); + } +); + +describe.each([ + ...dataProviderForOfCycle(), +] as Array<[Array, number, Array]>)( + "Stream Infinite Of Cycle Test", + ( + iterable: Iterable, + limit: number, + expected: Array + ) => { + it("", async () => { + // When + const stream = AsyncStream.ofCycle(iterable); + const result = await stream.limit(limit).toArray() as Array; + + // Then + expect(result).toEqual(expected); + }); + } +); + +describe.each([ + ...dataProviderForOfRepeat(), +] as Array<[Array, number, Array]>)( + "Stream Infinite Of Repeat Test", + ( + itemToRepeat: unknown, + limit: number, + expected: Array + ) => { + it("", async () => { + // When + const stream = AsyncStream.ofRepeat(itemToRepeat); + const result = await stream.limit(limit).toArray() as Array; + + // Then + expect(result).toEqual(expected); + }); + } +); + +function dataProviderForOfCount(): Array { + return [ + [ + [1, 2], + 5, + [1, 3, 5, 7, 9], + ], + [ + [0, -1], + 5, + [0, -1, -2, -3, -4], + ], + ]; +} + +function dataProviderForOfCycle(): Array { + return [ + [ + [0, 1, 2], + 10, + [0, 1, 2, 0, 1, 2, 0, 1, 2, 0], + ], + ]; +} + +function dataProviderForOfRepeat(): Array { + return [ + [ + 1, + 5, + [1, 1, 1, 1, 1], + ], + ]; +} + +describe.each([ + ...dataProviderForMath(), +] as Array<[ + AsyncIterable|AsyncIterator|Iterable|Iterator, + (data: unknown) => AsyncStream, + Array +]>)( + "AsyncStream Math Test", + ( + input: AsyncIterable|AsyncIterator|Iterable|Iterator, + streamFactory: (data: unknown) => AsyncStream, + expected: Array + ) => { + it("", async () => { + // Given + const result = await streamFactory(input); + + // Then + expect(result).toEqual(expected); + }); + } +); + +function dataProviderForMath(): Array { + return [ + [ + createAsyncGeneratorFixture([1, 2, 3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .runningAverage() + .toArray(), + [1, 1.5, 2], + ], + [ + createAsyncGeneratorFixture([1, 2, 3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .runningDifference() + .toArray(), + [-1, -3, -6], + ], + [ + createAsyncGeneratorFixture([1, 2, 3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .runningMax(1) + .toArray(), + [1, 1, 2, 3], + ], + [ + createAsyncGeneratorFixture([1, 2, 3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .runningMin(1) + .toArray(), + [1, 1, 1, 1], + ], + [ + createAsyncGeneratorFixture([1, 2, 3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .runningProduct() + .toArray(), + [1, 2, 6], + ], + [ + createAsyncGeneratorFixture([1, 2, 3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .runningTotal() + .toArray(), + [1, 3, 6], + ], + ]; +} + +describe.each([ + ...dataProviderForMulti(), +] as Array<[ + AsyncIterable|AsyncIterator|Iterable|Iterator, + (data: unknown) => AsyncStream, + Array +]>)( + "AsyncStream Multi Test", + ( + input: AsyncIterable|AsyncIterator|Iterable|Iterator, + streamFactory: (data: unknown) => AsyncStream, + expected: Array + ) => { + it("", async () => { + // Given + const result = await streamFactory(input); + + // Then + expect(result).toEqual(expected); + }); + } +); + +function dataProviderForMulti(): Array { + return [ + [ + [1, 2, 3, 4, 5], + (iterable: Iterable) => AsyncStream.of(iterable) + .zipWith( + createAsyncGeneratorFixture([11, 22, 33]), + createIterableFixture([111, 222, 333, 444]), + createIteratorFixture([1111, 2222, 3333]), + new Set([11111, 22222, 33333]), + 'abcdefg', + ) + .toArray(), + [ + [1, 11, 111, 1111, 11111, 'a'], + [2, 22, 222, 2222, 22222, 'b'], + [3, 33, 333, 3333, 33333, 'c'], + ], + ], + [ + [1, 2, 3, 4, 5], + (iterable: Iterable) => AsyncStream.of(iterable) + .zipLongestWith( + createGeneratorFixture([11, 22, 33]), + createAsyncIterableFixture([111, 222, 333, 444]), + createIteratorFixture([1111, 2222, 3333]), + new Set([11111, 22222, 33333]), + 'abcdefg', + ) + .toArray(), + [ + [1, 11, 111, 1111, 11111, 'a'], + [2, 22, 222, 2222, 22222, 'b'], + [3, 33, 333, 3333, 33333, 'c'], + [4, undefined, 444, undefined, undefined, 'd'], + [5, undefined, undefined, undefined, undefined, 'e'], + [undefined, undefined, undefined, undefined, undefined, 'f'], + [undefined, undefined, undefined, undefined, undefined, 'g'], + ], + ], + [ + [1, 2, 3, 4, 5], + (iterable: Iterable) => AsyncStream.of(iterable) + .zipFilledWith( + 'filler', + createAsyncGeneratorFixture([11, 22, 33]), + createAsyncIterableFixture([111, 222, 333, 444]), + createAsyncIteratorFixture([1111, 2222, 3333]), + new Set([11111, 22222, 33333]), + 'abcdefg', + ) + .toArray(), + [ + [1, 11, 111, 1111, 11111, 'a'], + [2, 22, 222, 2222, 22222, 'b'], + [3, 33, 333, 3333, 33333, 'c'], + [4, 'filler', 444, 'filler', 'filler', 'd'], + [5, 'filler', 'filler', 'filler', 'filler', 'e'], + ['filler', 'filler', 'filler', 'filler', 'filler', 'f'], + ['filler', 'filler', 'filler', 'filler', 'filler', 'g'], + ], + ], + [ + [1, 2, 3], + (iterable: Iterable) => AsyncStream.of(iterable) + .zipEqualWith( + createGeneratorFixture([11, 22, 33]), + createAsyncIterableFixture([111, 222, 333]), + createAsyncIteratorFixture([1111, 2222, 3333]), + new Set([11111, 22222, 33333]), + 'abc', + ) + .toArray(), + [ + [1, 11, 111, 1111, 11111, 'a'], + [2, 22, 222, 2222, 22222, 'b'], + [3, 33, 333, 3333, 33333, 'c'], + ], + ], + [ + [1, 2], + (iterable: Iterable) => AsyncStream.of(iterable) + .chainWith(createAsyncGeneratorFixture([3, 4])) + .chainWith(createAsyncIterableFixture([5])) + .chainWith(createAsyncIteratorFixture([6])) + .chainWith(new Set([7])) + .chainWith(AsyncStream.of(createMapFixture([8, 9])).map((item) => (item as Array)[1])) + .chainWith('abc') + .toArray(), + [1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c'], + ], + [ + [1, 2], + (iterable: Iterable) => AsyncStream.of(iterable) + .chainWith(createGeneratorFixture([3, 4])) + .chainWith(createAsyncIterableFixture([5])) + .chainWith(createAsyncIteratorFixture([6])) + .chainWith(new Set([7])) + .chainWith(AsyncStream.of(createMapFixture([8])).map((item) => (item as Array)[1])) + .chainWith('abc') + .zipWith([11, 22, 33, 44, 55, 66, 77, 88, 'x', 'y', 'z']) + .toArray(), + [[1, 11], [2, 22], [3, 33], [4, 44], [5, 55], [6, 66], [7, 77], [8, 88], ['a', 'x'], ['b', 'y'], ['c', 'z']], + ], + ]; +} + +describe.each([ + ...dataProviderForPeek(), +] as Array<[ + AsyncIterable|AsyncIterator|Iterable|Iterator, + (data: AsyncIterable|AsyncIterator|Iterable|Iterator) => AsyncStream, + (stream: AsyncStream) => AsyncStream, + Array, + Array, +]>)( + "AsyncStream Peek Test", + ( + input: AsyncIterable|AsyncIterator|Iterable|Iterator, + leftChainFunc: (data: AsyncIterable|AsyncIterator|Iterable|Iterator) => AsyncStream, + rightChainFunc: (stream: AsyncStream) => AsyncStream, + expectedPeeked: Array, + expectedResult: Array, + ) => { + it("", async () => { + // Given + const stream = leftChainFunc(input); + const peeked: Array = []; + + // When + stream.peek((item) => { + peeked.push(item); + }); + + // And when + const result = await rightChainFunc(stream).toArray(); + + // Then + expect(peeked).toEqual(expectedPeeked); + expect(result).toEqual(expectedResult); + }); + } +); + +describe.each([ + ...dataProviderForPeek(), +] as Array<[ + AsyncIterable|AsyncIterator|Iterable|Iterator, + (data: AsyncIterable|AsyncIterator|Iterable|Iterator) => AsyncStream, + (stream: AsyncStream) => AsyncStream, + Array, + Array, +]>)( + "AsyncStream Peek Stream Test", + ( + input: AsyncIterable|AsyncIterator|Iterable|Iterator, + leftChainFunc: (data: AsyncIterable|AsyncIterator|Iterable|Iterator) => AsyncStream, + rightChainFunc: (stream: AsyncStream) => AsyncStream, + expectedPeeked: Array, + expectedResult: Array, + ) => { + it("", async () => { + // Given + const stream = leftChainFunc(input); + const peeked: Array = []; + + // When + stream.peekStream(async (stream) => { + for await (const item of stream) { + peeked.push(item); + } + }); + + // And when + const result = await rightChainFunc(stream).toArray(); + + // Then + expect(peeked).toEqual(expectedPeeked); + expect(result).toEqual(expectedResult); + }); + } +); + +function dataProviderForPeek(): Array { + return [ + [ + createAsyncIterableFixture([5, 4, 3, 2, 1]), + (iterable: Iterable) => AsyncStream.of(iterable), + (stream: AsyncStream) => stream, + [5, 4, 3, 2, 1], + [5, 4, 3, 2, 1], + ], + [ + createAsyncIterableFixture([1, 2, 3, 4, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .zipWith([11, 22, 33, 44, 55]), + (stream: AsyncStream) => stream + .limit(3), + [[1, 11], [2, 22], [3, 33], [4, 44], [5, 55]], + [[1, 11], [2, 22], [3, 33]], + ], + [ + createAsyncIterableFixture([9, 8, 7, 6, 5, 4, 3, 2, 1]), + (iterable: Iterable) => AsyncStream.of(iterable) + .filter((x) => (x as number) % 2 !== 0) + .sort(), + (stream: AsyncStream) => stream + .map((x) => (x as number) + 1) + .pairwise(), + [1, 3, 5, 7, 9], + [[2, 4], [4, 6], [6, 8], [8, 10]], + ], + ]; +} + +describe.each([ + ...dataProviderForReduce(), +] as Array<[ + AsyncIterable|AsyncIterator|Iterable|Iterator, + (data: unknown) => AsyncStream, + Array +]>)( + "AsyncStream Reduce Test", + ( + input: AsyncIterable|AsyncIterator|Iterable|Iterator, + streamFactory: (data: unknown) => AsyncStream, + expected: Array + ) => { + it("", async () => { + // Given + const result = await (streamFactory as (data: unknown) => AsyncStream)(input); + + // Then + expect(result).toEqual(expected); + }); + } +); + +function dataProviderForReduce(): Array { + return [ + [ + createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .toValue(function (carry, item) { + return (carry as number) + (item as number); + }, 0), + 0, + ], + [ + createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .toAverage(), + 0, + ], + [ + createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .toRange(), + 6, + ], + [ + createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .toCount(), + 6, + ], + [ + createAsyncGeneratorFixture([2, 1, 3, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .toFirst(), + 2, + ], + [ + createAsyncGeneratorFixture([2, 1, 3, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .toFirstAndLast(), + [2, 5], + ], + [ + createAsyncGeneratorFixture([2, 3, 1, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .toLast(), + 5, + ], + [ + createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .toMax(), + 3, + ], + [ + createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .toMin(), + -3, + ], + [ + createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .toMinMax((item) => -(item as number)), + [3, -3], + ], + [ + createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable).toProduct(), + -36, + ], + [ + createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .filter((value) => (value as number) > 0) + .toSum(), + 6, + ], + ]; +} + +describe.each([ + ...dataProviderForSet(), +] as Array<[ + AsyncIterable|AsyncIterator|Iterable|Iterator, + (data: unknown) => AsyncStream, + Array +]>)( + "AsyncStream Set Test", + ( + input: AsyncIterable|AsyncIterator|Iterable|Iterator, + streamFactory: (data: unknown) => AsyncStream, + expected: Array + ) => { + it("", async () => { + // Given + const result = await streamFactory(input); + + // Then + expect(result).toEqual(expected); + }); + } +); + +describe.each([ + ...dataProviderForPartialIntersection(), +] as Array<[ + AsyncIterable|AsyncIterator|Iterable|Iterator, + number, + (minIntersectionCount: number, data: unknown) => Promise, + Array +]>)( + "AsyncStream Set Partial Intersection Test", + ( + input: AsyncIterable|AsyncIterator|Iterable|Iterator, + minIntersectionCount: number, + streamFactory: (minIntersectionCount: number, data: unknown) => Promise, + expected: Array + ) => { + it("", async () => { + // Given + const result = await streamFactory( + minIntersectionCount as number, + input as Array> + ); + + // Then + expect(result).toEqual(expected); + }); + } +); + +function dataProviderForSet(): Array { + return [ + [ + createAsyncGeneratorFixture([1, 2, 3, '1', '2', '3']), + (iterable: Iterable) => AsyncStream.of(iterable) + .distinct() + .toArray(), + [1, 2, 3, '1', '2', '3'], + ], + [ + createAsyncGeneratorFixture([ + { 'name': 'John', 'id': 1 }, + { 'name': 'Mary', 'id': 2 }, + { 'name': 'Mary', 'id': 3 }, + { 'name': 'John', 'id': 4 }, + { 'name': 'Jane', 'id': 5 }, + ]), + (iterable: Iterable) => AsyncStream.of(iterable) + .distinct((datum: unknown) => (datum as Record)['name'] as Comparable) + .toArray(), + [ + { 'name': 'John', 'id': 1 }, + { 'name': 'Mary', 'id': 2 }, + { 'name': 'Jane', 'id': 5 }, + ], + ], + [ + [ + createAsyncGeneratorFixture([1, 2, 3, 4, 5]), + createAsyncGeneratorFixture([2, 3, 4, 5, 6, 7]), + createAsyncGeneratorFixture(['3', 4, 5, 6, 7, 8, 9]), + ], + (iterables: Array>) => AsyncStream.of(iterables.shift() as Iterable) + .intersectionWith(...iterables) + .toArray(), + [4, 5], + ], + [ + [ + createAsyncGeneratorFixture([1, 2, 3, 4, 5, 6]), + createAsyncGeneratorFixture([3, 4, 5, 6, 7, 8]), + createAsyncGeneratorFixture([5, 6, 7, 8, 9, 10]), + ], + (iterables: Array>) => AsyncStream.of(iterables.shift() as Iterable) + .symmetricDifferenceWith(...iterables) + .toArray(), + [1, 2, 9, 10], + ], + [ + [ + createAsyncGeneratorFixture([1, 2, 3, 4, 5]), + createAsyncGeneratorFixture([2, 3, 4, 5, 6]), + createAsyncGeneratorFixture([3, 4, 5, 6, 7]), + ], + (iterables: Array>) => AsyncStream.of(iterables.shift() as Iterable) + .unionWith(...iterables) + .toArray(), + [1, 2, 3, 4, 5, 6, 7], + ], + [ + [ + createAsyncGeneratorFixture([1, 2, 3]), + createAsyncGeneratorFixture([11, 22]), + createAsyncGeneratorFixture(['a', 'b']), + ], + (iterables: Array>) => AsyncStream.of(iterables.shift() as Iterable) + .cartesianProductWith(...iterables) + .toArray(), + [ + [1, 11, 'a'], + [1, 11, 'b'], + [1, 22, 'a'], + [1, 22, 'b'], + [2, 11, 'a'], + [2, 11, 'b'], + [2, 22, 'a'], + [2, 22, 'b'], + [3, 11, 'a'], + [3, 11, 'b'], + [3, 22, 'a'], + [3, 22, 'b'], + ], + ], + ]; +} + +function dataProviderForPartialIntersection(): Array { + return [ + [ + [ + createAsyncGeneratorFixture([1, 2]), + createAsyncIterableFixture([2, 3, 4]), + [2, 3, 4, 5, 6], + ], + 3, + (minIntersectionCount: number, iterables: Array>) => AsyncStream.of(iterables.shift() as Iterable) + .partialIntersectionWith(minIntersectionCount, ...iterables) + .toArray(), + [2], + ], + [ + [ + createAsyncIterableFixture([1, 2, 3, 4, 5, 6, 7, 8, 9]), + createAsyncGeneratorFixture(['1', '2', 3, 4, 5, 6, 7, '8', '9']), + [1, 3, 5, 7, 9, 11], + ], + 2, + (minIntersectionCount: number, iterables: Array>) => AsyncStream.of(iterables.shift() as Iterable) + .partialIntersectionWith(minIntersectionCount, ...iterables) + .toArray(), + [1, 3, 4, 5, 6, 7, 9], + ], + ]; +} + +describe.each([ + ...dataProviderForSingle(), +] as Array<[ + AsyncIterable|AsyncIterator|Iterable|Iterator, + (data: unknown) => AsyncStream, + Array +]>)( + "AsyncStream Single Test", + ( + input: AsyncIterable|AsyncIterator|Iterable|Iterator, + streamFactory: (data: unknown) => AsyncStream, + expected: Array + ) => { + it("", async () => { + // Given + const result = await streamFactory(input); + + // Then + expect(result).toEqual(expected); + }); + } +); +function dataProviderForSingle(): Array { + return [ + [ + createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .filter((value) => (value as number) > 0) + .compress(createAsyncGeneratorFixture([0, 1, 1])) + .toArray(), + [2, 3], + ], + [ + createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .dropWhile((value) => Math.abs(value as number) < 3) + .compress(createAsyncGeneratorFixture([0, 1])) + .toArray(), + [-3], + ], + [ + createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .takeWhile((value) => Math.abs(value as number) < 3) + .toArray(), + [1, -1, 2, -2], + ], + [ + createAsyncGeneratorFixture([1, 2, 3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .enumerate() + .toArray(), + [[0, 1], [1, 2], [2, 3]], + ], + [ + createAsyncGeneratorFixture([['a', 1], ['b', 2], ['c', 3]]), + (iterable: Iterable) => AsyncStream.of(iterable) + .keys() + .toArray(), + ['a', 'b', 'c'], + ], + [ + createAsyncGeneratorFixture([['a', 1], ['b', 2], ['c', 3]]), + (iterable: Iterable) => AsyncStream.of(iterable) + .values() + .toArray(), + [1, 2, 3], + ], + [ + createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .filter((value) => (value as number) > 0) + .toArray(), + [1, 2, 3], + ], + [ + createAsyncGeneratorFixture([1, 2, 3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .map((item) => (item as number) + 1) + .toArray(), + [2, 3, 4], + ], + [ + createAsyncGeneratorFixture([1, 2, 3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .flatMap((item) => single.repeatAsync(item, (item as number) + 1)) + .toArray(), + [1, 1, 2, 2, 2, 3, 3, 3, 3], + ], + [ + createAsyncGeneratorFixture([1, 2, [3, 4], [5, 6], 7, 8]), + (iterable: Iterable) => AsyncStream.of(iterable) + .flatMap(async (item) => { + await asyncTimeout(1); + return item; + }) + .toArray(), + [1, 2, 3, 4, 5, 6, 7, 8], + ], + [ + createAsyncGeneratorFixture([1, 2, [3, 4], [5, 6], 7, 8]), + (iterable: Iterable) => AsyncStream.of(iterable) + .flatten() + .toArray(), + [1, 2, 3, 4, 5, 6, 7, 8], + ], + [ + createAsyncGeneratorFixture([-3, -2, -1, 0, 1, 2, 3, 4, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .filter((value) => (value as number) > 0) + .chunkwise(2) + .toArray(), + [[1, 2], [3, 4], [5]], + ], + [ + createAsyncGeneratorFixture([-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + (iterable: Iterable) => AsyncStream.of(iterable) + .filter((value) => (value as number) >= 0) + .chunkwiseOverlap(3, 1) + .toArray(), + [[0, 1, 2], [2, 3, 4], [4, 5, 6], [6, 7, 8], [8, 9]], + ], + [ + createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .filter((value) => (value as number) > 0) + .pairwise() + .toArray(), + [[1, 2], [2, 3]], + ], + [ + createAsyncGeneratorFixture([1, 2, 3, 4, 5, 6, 7]), + (iterable: Iterable) => AsyncStream.of(iterable) + .limit(5) + .toArray(), + [1, 2, 3, 4, 5], + ], + [ + createAsyncGeneratorFixture([]), + (iterable: Iterable) => AsyncStream.of(iterable) + .limit(0) + .chainWith(createAsyncGeneratorFixture([1, 2, 3])) + .toArray(), + [1, 2, 3], + ], + [ + createAsyncGeneratorFixture([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), + (iterable: Iterable) => AsyncStream.of(iterable) + .skip(3, 2) + .toArray(), + [1, 2, 6, 7, 8, 9, 10], + ], + [ + createAsyncGeneratorFixture([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), + (iterable: Iterable) => AsyncStream.of(iterable) + .slice(2, 4) + .toArray(), + [3, 4, 5, 6], + ], + [ + createAsyncGeneratorFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .filter((value) => (value as number) % 2 !== 0) + .groupBy((item) => (item as number) > 0 ? 'pos' : 'neg') + .toArray(), + [['pos', [1, 3]], ['neg', [-1, -3]]], + ], + [ + createAsyncGeneratorFixture([2, 3, 1, 2, -3, -2, 5, 7, 3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .sort((lhs: unknown, rhs: unknown) => (lhs as number) - (rhs as number)) + .toArray(), + [-3, -2, 1, 2, 2, 3, 3, 5, 7], + ], + ]; +} + +describe.each([ + ...dataProviderForSummaryTrue(), +] as Array<[ + AsyncIterable|AsyncIterator|Iterable|Iterator, + (data: unknown) => AsyncStream +]>)( + "AsyncStream Summary Test True", + ( + input: AsyncIterable|AsyncIterator|Iterable|Iterator, + streamFactory: (data: unknown) => AsyncStream + ) => { + it("", async () => { + // Given + const result = await streamFactory(input); + + // Then + expect(result).toBeTruthy(); + }); + } +); + +describe.each([ + ...dataProviderForSummaryFalse(), +] as Array<[ + AsyncIterable|AsyncIterator|Iterable|Iterator, + (data: unknown) => AsyncStream +]>)( + "AsyncStream Summary Test False", + ( + input: AsyncIterable|AsyncIterator|Iterable|Iterator, + streamFactory: (data: unknown) => AsyncStream + ) => { + it("", async () => { + // Given + const result = await streamFactory(input); + + // Then + expect(result).toBeFalsy(); + }); + } +); + +function dataProviderForSummaryTrue(): Array { + return [ + [ + createAsyncIterableFixture([1, 3, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .allMatch((x) => (x as number) > 0), + ], + [ + createAsyncIterableFixture([1, 2, 3, 4, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .allUnique(), + ], + [ + createAsyncIterableFixture([1, 3, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .anyMatch(async (x) => { + await asyncTimeout(1); + return (x as number) === 3; + }), + ], + [ + createAsyncIterableFixture([1, 3, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .anyMatch((x) => (x as number) > 0), + ], + [ + createAsyncIterableFixture([1, 3, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .exactlyN(3), + ], + [ + createAsyncIterableFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .filter((item) => (item as number) > 0) + .runningTotal() + .isSorted(), + ], + [ + createAsyncIterableFixture([5, -1, 4, -2, 3, -3, 2, -4, 1, -5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .filter((item) => (item as number) > 0) + .isReversed(), + ], + [ + createAsyncIterableFixture([1, 3, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .noneMatch((x) => (x as number) === 9), + ], + [ + createAsyncIterableFixture([1, 3, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .runningTotal() + .sameWith([1, 4, 9]), + ], + [ + createAsyncIterableFixture([1, 3, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .runningTotal() + .sameCountWith([11, 22, 33]), + ], + ]; +} + +function dataProviderForSummaryFalse(): Array { + return [ + [ + createAsyncIterableFixture([1, 3, -5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .allMatch(async (x) => { + await asyncTimeout(1); + return (x as number) > 0; + }), + ], + [ + createAsyncIterableFixture([1, 2, 1, 3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .allUnique(), + ], + [ + createAsyncIterableFixture([1, 3, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .anyMatch((x) => (x as number) > 10), + ], + [ + createAsyncIterableFixture([1, 3, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .exactlyN(4), + ], + [ + createAsyncIterableFixture([1, -1, 2, -2, 3, -3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .runningTotal() + .isSorted(), + ], + [ + createAsyncIterableFixture([5, -1, 4, -2, 3, -3, 2, -4, 1, -5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .isReversed(), + ], + [ + createAsyncIterableFixture([1, 3, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .noneMatch(async (x) => { + await asyncTimeout(1); + return (x as number) === 3; + }), + ], + [ + createAsyncIterableFixture([1, 3, 5]), + (iterable: Iterable) => AsyncStream.of(iterable) + .runningTotal() + .sameWith([1, 4, 10]), + ], + [ + createAsyncIterableFixture([]), + (iterable: Iterable) => AsyncStream.of(iterable) + .sameCountWith([1, 2, 3]), + ], + ]; +} + +describe.each([ + ...dataProviderForTransform(), +] as Array<[ + AsyncIterable|AsyncIterator|Iterable|Iterator, + (data: unknown) => AsyncStream, + Array +]>)( + "AsyncStream Transform Test", + ( + input: AsyncIterable|AsyncIterator|Iterable|Iterator, + streamFactory: (data: unknown) => AsyncStream, + expected: Array + ) => { + it("", async () => { + // Given + const result = await streamFactory(input); + + // Then + expect(result).toEqual(expected); + }); + } +); + +describe.each([ + ...dataProviderForTee(), +] as Array<[ + AsyncIterable|AsyncIterator|Iterable|Iterator, + number, + Array<(stream: AsyncStream) => AsyncStream>, + Array +]>)( + "AsyncStream Transform Tee Test", + ( + input: AsyncIterable|AsyncIterator|Iterable|Iterator, + count: number, + extraOperations: Array<(stream: AsyncStream) => AsyncStream>, + expected: Array + ) => { + it("", async () => { + // Given + const inputStream = AsyncStream.of(input); + const result = []; + + // When + const streams = inputStream.tee(count); + for (const [stream, func] of multi.zipEqual(streams, extraOperations)) { + result.push(await func(stream).toArray()); + } + + // Then + expect(streams.length).toEqual(count); + expect(result).toEqual(expected); + }); + } +); + +function dataProviderForTransform(): Array { + return [ + [ + createAsyncGeneratorFixture([1, 2, 3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .toArray(), + [1, 2, 3], + ], + [ + createAsyncGeneratorFixture([1, 1, 2, 2, 3, 3]), + (iterable: Iterable) => AsyncStream.of(iterable) + .toSet(), + new Set([1, 2, 3]), + ], + [ + createAsyncGeneratorFixture([['a', 1], ['b', 2], ['c', 3]]), + (iterable: Iterable) => AsyncStream.of(iterable) + .toMap(), + new Map([['a', 1], ['b', 2], ['c', 3]]), + ], + ]; +} + +function dataProviderForTee(): Array { + return [ + [ + createIterableFixture([1, 2, 3]), + 3, + [ + (stream: Stream) => stream, + (stream: Stream) => stream + .map((datum) => (datum as number) * 2), + (stream: Stream) => stream + .map((datum) => (datum as number) ** 3), + ], + [ + [1, 2, 3], + [2, 4, 6], + [1, 8, 27], + ], + ], + [ + new Set([1, 2, 3]), + 3, + [ + (stream: Stream) => stream, + (stream: Stream) => stream + .map((datum) => (datum as number) * 2), + (stream: Stream) => stream + .map((datum) => (datum as number) ** 3) + .filter((datum) => (datum as number) < 10), + ], + [ + [1, 2, 3], + [2, 4, 6], + [1, 8], + ], + ], + ]; +} diff --git a/tests/examples/stream.test.ts b/tests/examples/stream.test.ts new file mode 100644 index 0000000..b87ce14 --- /dev/null +++ b/tests/examples/stream.test.ts @@ -0,0 +1,1064 @@ +import { + createGeneratorFixture, + createIterableFixture, + createIteratorFixture, + createMapFixture, + expectToBeCloseToArray, + // @ts-ignore +} from "../fixture"; +import { Comparable, multi, single, Stream } from "../../src"; + +describe.each([ + ...dataProviderForOfCount(), +] as Array<[Array, number, Array]>)( + "Stream Infinite Of Count Test", + ( + inputParams: Array, + limit: number, + expected: Array + ) => { + it("", () => { + // When + const stream = Stream.ofCount(...inputParams); + const result = stream.limit(limit).toArray() as Array; + + // Then + expectToBeCloseToArray(result, expected); + }); + } +); + +describe.each([ + ...dataProviderForOfCycle(), +] as Array<[Array, number, Array]>)( + "Stream Infinite Of Cycle Test", + ( + iterable: Iterable, + limit: number, + expected: Array + ) => { + it("", () => { + // When + const stream = Stream.ofCycle(iterable); + const result = stream.limit(limit).toArray() as Array; + + // Then + expect(result).toEqual(expected); + }); + } +); + +describe.each([ + ...dataProviderForOfRepeat(), +] as Array<[Array, number, Array]>)( + "Stream Infinite Of Repeat Test", + ( + itemToRepeat: unknown, + limit: number, + expected: Array + ) => { + it("", () => { + // When + const stream = Stream.ofRepeat(itemToRepeat); + const result = stream.limit(limit).toArray() as Array; + + // Then + expect(result).toEqual(expected); + }); + } +); + +function dataProviderForOfCount(): Array { + return [ + [ + [2, 0.1], + 5, + [2, 2.1, 2.2, 2.3, 2.4], + ], + [ + [-2.2, -1.2], + 5, + [-2.2, -3.4, -4.6, -5.8, -7], + ], + ]; +} + +function dataProviderForOfCycle(): Array { + return [ + [ + [0, 1, 2], + 10, + [0, 1, 2, 0, 1, 2, 0, 1, 2, 0], + ], + [ + [1, 1], + 6, + [1, 1, 1, 1, 1, 1], + ], + ]; +} + +function dataProviderForOfRepeat(): Array { + return [ + [ + 0, + 5, + [0, 0, 0, 0, 0], + ], + [ + 1, + 5, + [1, 1, 1, 1, 1], + ], + ]; +} + +describe.each([ + ...dataProviderForMath(), +] as Array<[Iterable|Iterator, (data: unknown) => Stream, Array]>)( + "Stream Math Test", + ( + input: Iterable|Iterator, + streamFactory: (data: unknown) => Stream, + expected: Array + ) => { + it("", () => { + // Given + const result = streamFactory(input); + + // Then + expect(result).toEqual(expected); + }); + } +); + +function dataProviderForMath(): Array { + return [ + [ + [1, 2, 3], + (iterable: Iterable) => Stream.of(iterable) + .runningAverage() + .toArray(), + [1, 1.5, 2], + ], + [ + [1, 2, 3], + (iterable: Iterable) => Stream.of(iterable) + .runningDifference() + .toArray(), + [-1, -3, -6], + ], + [ + [1, 2, 3], + (iterable: Iterable) => Stream.of(iterable) + .runningMax() + .toArray(), + [1, 2, 3], + ], + [ + [1, 2, 3], + (iterable: Iterable) => Stream.of(iterable) + .runningMin() + .toArray(), + [1, 1, 1], + ], + [ + [1, 2, 3], + (iterable: Iterable) => Stream.of(iterable) + .runningProduct() + .toArray(), + [1, 2, 6], + ], + [ + [1, 2, 3], + (iterable: Iterable) => Stream.of(iterable) + .runningTotal() + .toArray(), + [1, 3, 6], + ], + ]; +} + +describe.each([ + ...dataProviderForMulti(), +] as Array<[Iterable|Iterator, (data: unknown) => Stream, Array]>)( + "Stream Multi Test", + ( + input: Iterable|Iterator, + streamFactory: (data: unknown) => Stream, + expected: Array + ) => { + it("", () => { + // Given + const result = streamFactory(input); + + // Then + expect(result).toEqual(expected); + }); + } +); + +function dataProviderForMulti(): Array { + return [ + [ + [1, 2, 3, 4, 5], + (iterable: Iterable) => Stream.of(iterable) + .zipWith( + createGeneratorFixture([11, 22, 33]), + createIterableFixture([111, 222, 333, 444]), + createIteratorFixture([1111, 2222, 3333]), + new Set([11111, 22222, 33333]), + 'abcdefg', + ) + .toArray(), + [ + [1, 11, 111, 1111, 11111, 'a'], + [2, 22, 222, 2222, 22222, 'b'], + [3, 33, 333, 3333, 33333, 'c'], + ], + ], + [ + [1, 2, 3, 4, 5], + (iterable: Iterable) => Stream.of(iterable) + .zipLongestWith( + createGeneratorFixture([11, 22, 33]), + createIterableFixture([111, 222, 333, 444]), + createIteratorFixture([1111, 2222, 3333]), + new Set([11111, 22222, 33333]), + 'abcdefg', + ) + .toArray(), + [ + [1, 11, 111, 1111, 11111, 'a'], + [2, 22, 222, 2222, 22222, 'b'], + [3, 33, 333, 3333, 33333, 'c'], + [4, undefined, 444, undefined, undefined, 'd'], + [5, undefined, undefined, undefined, undefined, 'e'], + [undefined, undefined, undefined, undefined, undefined, 'f'], + [undefined, undefined, undefined, undefined, undefined, 'g'], + ], + ], + [ + [1, 2, 3, 4, 5], + (iterable: Iterable) => Stream.of(iterable) + .zipFilledWith( + 'filler', + createGeneratorFixture([11, 22, 33]), + createIterableFixture([111, 222, 333, 444]), + createIteratorFixture([1111, 2222, 3333]), + new Set([11111, 22222, 33333]), + 'abcdefg', + ) + .toArray(), + [ + [1, 11, 111, 1111, 11111, 'a'], + [2, 22, 222, 2222, 22222, 'b'], + [3, 33, 333, 3333, 33333, 'c'], + [4, 'filler', 444, 'filler', 'filler', 'd'], + [5, 'filler', 'filler', 'filler', 'filler', 'e'], + ['filler', 'filler', 'filler', 'filler', 'filler', 'f'], + ['filler', 'filler', 'filler', 'filler', 'filler', 'g'], + ], + ], + [ + [1, 2, 3], + (iterable: Iterable) => Stream.of(iterable) + .zipEqualWith( + createGeneratorFixture([11, 22, 33]), + createIterableFixture([111, 222, 333]), + createIteratorFixture([1111, 2222, 3333]), + new Set([11111, 22222, 33333]), + 'abc', + ) + .toArray(), + [ + [1, 11, 111, 1111, 11111, 'a'], + [2, 22, 222, 2222, 22222, 'b'], + [3, 33, 333, 3333, 33333, 'c'], + ], + ], + [ + [1, 2], + (iterable: Iterable) => Stream.of(iterable) + .chainWith(createGeneratorFixture([3, 4])) + .chainWith(createIterableFixture([5])) + .chainWith(createIteratorFixture([6])) + .chainWith(new Set([7])) + .chainWith(Stream.of(createMapFixture([8, 9])).map((item) => (item as Array)[1])) + .chainWith('abc') + .toArray(), + [1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c'], + ], + [ + [1, 2], + (iterable: Iterable) => Stream.of(iterable) + .chainWith(createGeneratorFixture([3, 4])) + .chainWith(createIterableFixture([5])) + .chainWith(createIteratorFixture([6])) + .chainWith(new Set([7])) + .chainWith(Stream.of(createMapFixture([8])).map((item) => (item as Array)[1])) + .chainWith('abc') + .zipWith([11, 22, 33, 44, 55, 66, 77, 88, 'x', 'y', 'z']) + .toArray(), + [[1, 11], [2, 22], [3, 33], [4, 44], [5, 55], [6, 66], [7, 77], [8, 88], ['a', 'x'], ['b', 'y'], ['c', 'z']], + ], + ]; +} + +describe.each([ + ...dataProviderForPeek(), +] as Array<[ + Iterable|Iterator, + (data: Iterable|Iterator) => Stream, + (stream: Stream) => Stream, + Array, + Array, +]>)( + "Stream Peek Test", + ( + input: Iterable|Iterator, + leftChainFunc: (data: Iterable|Iterator) => Stream, + rightChainFunc: (stream: Stream) => Stream, + expectedPeeked: Array, + expectedResult: Array, + ) => { + it("", () => { + // Given + const stream = leftChainFunc(input); + const peeked: Array = []; + + // When + stream.peek((item) => { + peeked.push(item); + }); + + // And when + const result = rightChainFunc(stream).toArray(); + + // Then + expect(peeked).toEqual(expectedPeeked); + expect(result).toEqual(expectedResult); + }); + } +); + +describe.each([ + ...dataProviderForPeek(), +] as Array<[ + Iterable|Iterator, + (data: Iterable|Iterator) => Stream, + (stream: Stream) => Stream, + Array, + Array, +]>)( + "Stream Peek Stream Test", + ( + input: Iterable|Iterator, + leftChainFunc: (data: Iterable|Iterator) => Stream, + rightChainFunc: (stream: Stream) => Stream, + expectedPeeked: Array, + expectedResult: Array, + ) => { + it("", () => { + // Given + const stream = leftChainFunc(input); + const peeked: Array = []; + + // When + stream.peekStream((stream) => { + for (const item of stream) { + peeked.push(item); + } + }); + + // And when + const result = rightChainFunc(stream).toArray(); + + // Then + expect(peeked).toEqual(expectedPeeked); + expect(result).toEqual(expectedResult); + }); + } +); + +function dataProviderForPeek(): Array { + return [ + [ + [5, 4, 3, 2, 1], + (iterable: Iterable) => Stream.of(iterable), + (stream: Stream) => stream, + [5, 4, 3, 2, 1], + [5, 4, 3, 2, 1], + ], + [ + [1, 2, 3, 4, 5], + (iterable: Iterable) => Stream.of(iterable) + .zipWith([11, 22, 33, 44, 55]), + (stream: Stream) => stream + .limit(3), + [[1, 11], [2, 22], [3, 33], [4, 44], [5, 55]], + [[1, 11], [2, 22], [3, 33]], + ], + [ + [9, 8, 7, 6, 5, 4, 3, 2, 1], + (iterable: Iterable) => Stream.of(iterable) + .filter((x) => (x as number) % 2 !== 0) + .sort(), + (stream: Stream) => stream + .map((x) => (x as number) + 1) + .pairwise(), + [1, 3, 5, 7, 9], + [[2, 4], [4, 6], [6, 8], [8, 10]], + ], + ]; +} + +describe.each([ + ...dataProviderForReduce(), +] as Array<[Iterable|Iterator, (data: unknown) => Stream, Array]>)( + "Stream Reduce Test", + ( + input: Iterable|Iterator, + streamFactory: (data: unknown) => Stream, + expected: Array + ) => { + it("", () => { + // Given + const result = (streamFactory as (data: unknown) => Stream)(input); + + // Then + expect(result).toEqual(expected); + }); + } +); + +function dataProviderForReduce(): Array { + return [ + [ + [1, -1, 2, -2, 3, -3], + (iterable: Iterable) => Stream.of(iterable) + .toValue(function (carry, item) { + return (carry as number) + (item as number); + }, 0), + 0, + ], + [ + [1, 2, 3, 4, 5], + (iterable: Iterable) => Stream.of(iterable) + .zipLongestWith( + [10, 20, 30], + [100, 200, 300] + ) + .toValue(function (carry, item) { + return (carry as number) + (item as Array) + .reduce((accumulator, current) => accumulator + (current ?? 0)); + }, 0), + 675, + ], + [ + [1, -1, 2, -2, 3, -3], + (iterable: Iterable) => Stream.of(iterable) + .toRange(), + 6, + ], + [ + [1, -1, 2, -2, 3, -3], + (iterable: Iterable) => Stream.of(iterable) + .toCount(), + 6, + ], + [ + [2, 1, 3, 5], + (iterable: Iterable) => Stream.of(iterable) + .toFirst(), + 2, + ], + [ + [2, 1, 3, 5], + (iterable: Iterable) => Stream.of(iterable) + .toFirstAndLast(), + [2, 5], + ], + [ + [2, 3, 1, 5], + (iterable: Iterable) => Stream.of(iterable) + .toLast(), + 5, + ], + [ + [1, -1, 2, -2, 3, -3], + (iterable: Iterable) => Stream.of(iterable) + .toMax(), + 3, + ], + [ + [1, -1, 2, -2, 3, -3], + (iterable: Iterable) => Stream.of(iterable) + .toMin(), + -3, + ], + [ + [1, -1, 2, -2, 3, -3], + (iterable: Iterable) => Stream.of(iterable) + .toMinMax((item) => -(item as number)), + [3, -3], + ], + [ + [1, -1, 2, -2, 3, -3], + (iterable: Iterable) => Stream.of(iterable).toProduct(), + -36, + ], + [ + [1, -1, 2, -2, 3, -3], + (iterable: Iterable) => Stream.of(iterable).toSum(), + 0, + ], + ]; +} + +describe.each([ + ...dataProviderForSet(), +] as Array<[Iterable|Iterator, (data: unknown) => Stream, Array]>)( + "Stream Set Test", + ( + input: Iterable|Iterator, + streamFactory: (data: unknown) => Stream, + expected: Array + ) => { + it("", () => { + // Given + const result = streamFactory(input); + + // Then + expect(result).toEqual(expected); + }); + } +); + +describe.each([ + ...dataProviderForPartialIntersection(), +] as Array<[ + Iterable|Iterator, + number, + (minIntersectionCount: number, data: unknown) => Stream, + Array +]>)( + "Stream Set Partial Intersection Test", + ( + input: Iterable|Iterator, + minIntersectionCount: number, + streamFactory: (minIntersectionCount: number, data: unknown) => Stream, + expected: Array + ) => { + it("", () => { + // Given + const result = streamFactory( + minIntersectionCount as number, + input as Array> + ); + + // Then + expect(result).toEqual(expected); + }); + } +); + +function dataProviderForSet(): Array { + return [ + [ + [1, 2, 3, '1', '2', '3'], + (iterable: Iterable) => Stream.of(iterable) + .distinct() + .toArray(), + [1, 2, 3, '1', '2', '3'], + ], + [ + [ + { 'name': 'John', 'id': 1 }, + { 'name': 'Mary', 'id': 2 }, + { 'name': 'Mary', 'id': 3 }, + { 'name': 'John', 'id': 4 }, + { 'name': 'Jane', 'id': 5 }, + ], + (iterable: Iterable) => Stream.of(iterable) + .distinct((datum: unknown) => (datum as Record)['name'] as Comparable) + .toArray(), + [ + { 'name': 'John', 'id': 1 }, + { 'name': 'Mary', 'id': 2 }, + { 'name': 'Jane', 'id': 5 }, + ], + ], + [ + [ + [1, 2, 3, 4, 5], + [2, 3, 4, 5, 6, 7], + ['3', 4, 5, 6, 7, 8, 9], + ], + (iterables: Array>) => Stream.of(iterables.shift() as Iterable) + .intersectionWith(...iterables) + .toArray(), + [4, 5], + ], + [ + [ + [1, 2, 3, 4, 5, 6], + [3, 4, 5, 6, 7, 8], + [5, 6, 7, 8, 9, 10], + ], + (iterables: Array>) => Stream.of(iterables.shift() as Iterable) + .symmetricDifferenceWith(...iterables) + .toArray(), + [1, 2, 9, 10], + ], + [ + [ + [1, 2, 3, 4, 5], + [2, 3, 4, 5, 6], + [3, 4, 5, 6, 7], + ], + (iterables: Array>) => Stream.of(iterables.shift() as Iterable) + .unionWith(...iterables) + .toArray(), + [1, 2, 3, 4, 5, 6, 7], + ], + [ + [ + [1, 2, 3], + [11, 22], + ['a', 'b'], + ], + (iterables: Array>) => Stream.of(iterables.shift() as Iterable) + .cartesianProductWith(...iterables) + .toArray(), + [ + [1, 11, 'a'], + [1, 11, 'b'], + [1, 22, 'a'], + [1, 22, 'b'], + [2, 11, 'a'], + [2, 11, 'b'], + [2, 22, 'a'], + [2, 22, 'b'], + [3, 11, 'a'], + [3, 11, 'b'], + [3, 22, 'a'], + [3, 22, 'b'], + ], + ], + ]; +} + +function dataProviderForPartialIntersection(): Array { + return [ + [ + [ + createIterableFixture([1, 2, 3, 4, 5, 6, 7, 8, 9]), + createGeneratorFixture(['1', '2', 3, 4, 5, 6, 7, '8', '9']), + [1, 3, 5, 7, 9, 11], + ], + 2, + (minIntersectionCount: number, iterables: Array>) => Stream.of(iterables.shift() as Iterable) + .partialIntersectionWith(minIntersectionCount, ...iterables) + .toArray(), + [1, 3, 4, 5, 6, 7, 9], + ], + ]; +} + +describe.each([ + ...dataProviderForSingle(), +] as Array<[Iterable|Iterator, (data: unknown) => Stream, Array]>)( + "Stream Single Test", + ( + input: Iterable|Iterator, + streamFactory: (data: unknown) => Stream, + expected: Array + ) => { + it("", () => { + // Given + const result = streamFactory(input); + + // Then + expect(result).toEqual(expected); + }); + } +); + +function dataProviderForSingle(): Array { + return [ + [ + [1, -1, 2, -2, 3, -3], + (iterable: Iterable) => Stream.of(iterable) + .filter((value) => (value as number) > 0) + .compress([0, 1, 1]) + .toArray(), + [2, 3], + ], + [ + [1, -1, 2, -2, 3, -3], + (iterable: Iterable) => Stream.of(iterable) + .takeWhile((value) => Math.abs(value as number) < 3) + .toArray(), + [1, -1, 2, -2], + ], + [ + [1, 2, 3], + (iterable: Iterable) => Stream.of(iterable) + .enumerate() + .toArray(), + [[0, 1], [1, 2], [2, 3]], + ], + [ + [['a', 1], ['b', 2], ['c', 3]], + (iterable: Iterable) => Stream.of(iterable) + .keys() + .toArray(), + ['a', 'b', 'c'], + ], + [ + ['a', 'b', 'c'], + (iterable: Iterable) => Stream.of(iterable) + .enumerate() + .values() + .toArray(), + ['a', 'b', 'c'], + ], + [ + [1, -1, 2, -2, 3, -3], + (iterable: Iterable) => Stream.of(iterable) + .filter((value) => (value as number) > 0) + .toArray(), + [1, 2, 3], + ], + [ + [1, 2, 3], + (iterable: Iterable) => Stream.of(iterable) + .map((item) => (item as number) + 1) + .toArray(), + [2, 3, 4], + ], + [ + [1, 2, 3], + (iterable: Iterable) => Stream.of(iterable) + .flatMap((item) => single.repeat(item, (item as number) + 1)) + .toArray(), + [1, 1, 2, 2, 2, 3, 3, 3, 3], + ], + [ + [1, 2, [3, 4], [5, 6], 7, 8], + (iterable: Iterable) => Stream.of(iterable) + .flatMap((item) => item) + .toArray(), + [1, 2, 3, 4, 5, 6, 7, 8], + ], + [ + [1, 2, [3, 4], [5, 6], 7, 8], + (iterable: Iterable) => Stream.of(iterable) + .flatten() + .toArray(), + [1, 2, 3, 4, 5, 6, 7, 8], + ], + [ + [-3, -2, -1, 0, 1, 2, 3, 4, 5], + (iterable: Iterable) => Stream.of(iterable) + .filter((value) => (value as number) >= 0) + .chunkwise(2) + .toArray(), + [[0, 1], [2, 3], [4, 5]], + ], + [ + [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + (iterable: Iterable) => Stream.of(iterable) + .filter((value) => (value as number) >= 0) + .chunkwiseOverlap(3, 1) + .toArray(), + [[0, 1, 2], [2, 3, 4], [4, 5, 6], [6, 7, 8], [8, 9]], + ], + [ + [1, -1, 2, -2, 3, -3], + (iterable: Iterable) => Stream.of(iterable) + .filter((value) => (value as number) > 0) + .pairwise() + .toArray(), + [[1, 2], [2, 3]], + ], + [ + [1, 2, 3, 4, 5, 6, 7], + (iterable: Iterable) => Stream.of(iterable) + .limit(5) + .toArray(), + [1, 2, 3, 4, 5], + ], + [ + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + (iterable: Iterable) => Stream.of(iterable) + .skip(3, 2) + .toArray(), + [1, 2, 6, 7, 8, 9, 10], + ], + [ + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + (iterable: Iterable) => Stream.of(iterable) + .slice(2, 4) + .toArray(), + [3, 4, 5, 6], + ], + [ + [1, -1, 2, -2, 3, -3], + (iterable: Iterable) => Stream.of(iterable) + .filter((value) => (value as number) % 2 !== 0) + .groupBy((item) => (item as number) > 0 ? 'pos' : 'neg') + .toArray(), + [['pos', [1, 3]], ['neg', [-1, -3]]], + ], + [ + [2, 3, 1, 2, -3, -2, 5, 7, 3], + (iterable: Iterable) => Stream.of(iterable) + .sort((lhs: unknown, rhs: unknown) => (lhs as number) - (rhs as number)) + .toArray(), + [-3, -2, 1, 2, 2, 3, 3, 5, 7], + ], + ]; +} + +describe.each([ + ...dataProviderForSummaryTrue(), +] as Array<[Iterable|Iterator, (data: unknown) => Stream]>)( + "Stream Summary Test True", + ( + input: Iterable|Iterator, + streamFactory: (data: unknown) => Stream + ) => { + it("", () => { + // Given + const result = streamFactory(input); + + // Then + expect(result).toBeTruthy(); + }); + } +); + + +describe.each([ + ...dataProviderForSummaryFalse(), +] as Array<[Iterable|Iterator, (data: unknown) => Stream]>)( + "Stream Summary Test False", + ( + input: Iterable|Iterator, + streamFactory: (data: unknown) => Stream + ) => { + it("", () => { + // Given + const result = streamFactory(input); + + // Then + expect(result).toBeFalsy(); + }); + } +); + +function dataProviderForSummaryTrue(): Array { + return [ + [ + [1, 3, 5], + (iterable: Iterable) => Stream.of(iterable) + .allMatch((x) => (x as number) > 0), + ], + [ + [1, 2, 3, 4, 5], + (iterable: Iterable) => Stream.of(iterable) + .allUnique(), + ], + [ + [1, 3, 5], + (iterable: Iterable) => Stream.of(iterable) + .anyMatch((x) => (x as number) === 3), + ], + [ + [1, 3, 5], + (iterable: Iterable) => Stream.of(iterable) + .exactlyN(3), + ], + [ + [1, -1, 2, -2, 3, -3], + (iterable: Iterable) => Stream.of(iterable) + .filter((item) => (item as number) > 0) + .runningTotal() + .isSorted(), + ], + [ + [5, -1, 4, -2, 3, -3, 2, -4, 1, -5], + (iterable: Iterable) => Stream.of(iterable) + .filter((item) => (item as number) > 0) + .isReversed(), + ], + [ + [1, 3, 5], + (iterable: Iterable) => Stream.of(iterable) + .noneMatch((x) => (x as number) === 9), + ], + [ + [1, 3, 5], + (iterable: Iterable) => Stream.of(iterable) + .runningTotal() + .sameWith([1, 4, 9]), + ], + [ + [1, 3, 5], + (iterable: Iterable) => Stream.of(iterable) + .runningTotal() + .sameCountWith([11, 22, 33]), + ], + ]; +} + +function dataProviderForSummaryFalse(): Array { + return [ + [ + [1, 3, -5], + (iterable: Iterable) => Stream.of(iterable) + .allMatch((x) => (x as number) > 0), + ], + [ + [1, 2, 1, 3], + (iterable: Iterable) => Stream.of(iterable) + .allUnique(), + ], + [ + [1, 3, 5], + (iterable: Iterable) => Stream.of(iterable) + .anyMatch((x) => (x as number) > 10), + ], + [ + [1, 3, 5], + (iterable: Iterable) => Stream.of(iterable) + .exactlyN(4), + ], + [ + [1, -1, 2, -2, 3, -3], + (iterable: Iterable) => Stream.of(iterable) + .runningTotal() + .isSorted(), + ], + [ + [5, -1, 4, -2, 3, -3, 2, -4, 1, -5], + (iterable: Iterable) => Stream.of(iterable) + .isReversed(), + ], + [ + [1, 3, 5], + (iterable: Iterable) => Stream.of(iterable) + .noneMatch((x) => (x as number) === 3), + ], + [ + [1, 3, 5], + (iterable: Iterable) => Stream.of(iterable) + .runningTotal() + .sameWith([1, 4, 10]), + ], + [ + [1, 3, 5], + (iterable: Iterable) => Stream.of(iterable) + .runningTotal() + .sameCountWith([11, 22]), + ], + ]; +} + +describe.each([ + ...dataProviderForTransform(), +] as Array<[Iterable | Iterator, (data: unknown) => Stream, Array]>)( + "Stream Transform Test", + ( + input: Iterable | Iterator, + streamFactory: (data: unknown) => Stream, + expected: Array + ) => { + it("", () => { + // Given + const result = streamFactory(input); + + // Then + expect(result).toEqual(expected); + }); + } +); + +describe.each([ + ...dataProviderForTee(), +] as Array<[ + Iterable | Iterator, + number, + Array<(stream: Stream) => Stream>, + Array +]>)( + "Stream Transform Tee Test", + ( + input: Iterable | Iterator, + count: number, + extraOperations: Array<(stream: Stream) => Stream>, + expected: Array + ) => { + it("", () => { + // Given + const inputStream = Stream.of(input); + const result = []; + + // When + const streams = inputStream.tee(count); + for (const [stream, func] of multi.zipEqual(streams, extraOperations)) { + result.push(func(stream).toArray()); + } + + // Then + expect(streams.length).toEqual(count); + expect(result).toEqual(expected); + }); + } +); + +function dataProviderForTransform(): Array { + return [ + [ + [1, 2, 3], + (iterable: Iterable) => Stream.of(iterable) + .toArray(), + [1, 2, 3], + ], + [ + [1, 1, 2, 2, 3, 3], + (iterable: Iterable) => Stream.of(iterable) + .toSet(), + new Set([1, 2, 3]), + ], + [ + [['a', 1], ['b', 2], ['c', 3]], + (iterable: Iterable) => Stream.of(iterable) + .toMap(), + new Map([['a', 1], ['b', 2], ['c', 3]]), + ], + ]; +} + +function dataProviderForTee(): Array { + return [ + [ + createIterableFixture([1, 2, 3]), + 3, + [ + (stream: Stream) => stream, + (stream: Stream) => stream + .map((datum) => (datum as number) * 2), + (stream: Stream) => stream + .map((datum) => (datum as number) ** 3), + ], + [ + [1, 2, 3], + [2, 4, 6], + [1, 8, 27], + ], + ], + ]; +}