// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. import { assertEquals, assertThrows } from "@std/assert"; import { slidingWindows } from "./unstable_sliding_windows.ts"; function slidingWindowsTest( input: Parameters, expected: T[][], message?: string, ) { const actual = slidingWindows(...input); assertEquals(actual, expected, message); } function slidingWindowsThrowsTest( input: [ collection: T[], size: number, config?: { step?: number; partial?: boolean }, ], ErrorClass: ErrorConstructor, msgIncludes?: string, msg?: string | undefined, ) { assertThrows( () => { slidingWindows(...input); }, ErrorClass, msgIncludes, msg, ); } Deno.test({ name: "slidingWindows() handles no mutation", fn() { const numbers = [1, 2, 3, 4, 5]; slidingWindows(numbers, 3); assertEquals(numbers, [1, 2, 3, 4, 5]); }, }); Deno.test({ name: "slidingWindows() handles empty input", fn() { slidingWindowsTest([[], 3], []); slidingWindowsTest([[], 3, {}], []); slidingWindowsTest([[], 3, { step: 2 }], []); slidingWindowsTest([[], 3, { partial: true }], []); slidingWindowsTest([[], 3, { step: 2, partial: true }], []); }, }); Deno.test({ name: "slidingWindows() handles default option", fn() { slidingWindowsTest([[1, 2, 3, 4, 5], 5], [[1, 2, 3, 4, 5]]); slidingWindowsTest( [[1, 2, 3, 4, 5], 3], [ [1, 2, 3], [2, 3, 4], [3, 4, 5], ], ); slidingWindowsTest([[1, 2, 3, 4, 5], 1], [[1], [2], [3], [4], [5]]); }, }); Deno.test({ name: "slidingWindows() handles step option", fn() { slidingWindowsTest([[1, 2, 3, 4, 5], 5, { step: 2 }], [[1, 2, 3, 4, 5]]); slidingWindowsTest( [[1, 2, 3, 4, 5], 3, { step: 2 }], [ [1, 2, 3], [3, 4, 5], ], ); slidingWindowsTest([[1, 2, 3, 4, 5], 1, { step: 2 }], [[1], [3], [5]]); }, }); Deno.test({ name: "slidingWindows() handles partial option", fn() { slidingWindowsTest( [[1, 2, 3, 4, 5], 5, { partial: true }], [[1, 2, 3, 4, 5], [2, 3, 4, 5], [3, 4, 5], [4, 5], [5]], ); slidingWindowsTest( [[1, 2, 3, 4, 5], 3, { partial: true }], [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5], [5]], ); slidingWindowsTest( [[1, 2, 3, 4, 5], 1, { partial: true }], [[1], [2], [3], [4], [5]], ); }, }); Deno.test({ name: "slidingWindows() handles step and partial option", fn() { slidingWindowsTest( [[1, 2, 3, 4, 5], 5, { step: 2, partial: true }], [[1, 2, 3, 4, 5], [3, 4, 5], [5]], ); slidingWindowsTest( [[1, 2, 3, 4, 5], 3, { step: 2, partial: true }], [[1, 2, 3], [3, 4, 5], [5]], ); slidingWindowsTest( [[1, 2, 3, 4, 5], 1, { step: 2, partial: true }], [[1], [3], [5]], ); }, }); Deno.test({ name: "slidingWindows() handles invalid size or step: other than number", fn() { slidingWindowsThrowsTest( [[1, 2, 3, 4, 5], NaN], RangeError, "Cannot create sliding windows: size must be a positive integer, current value is NaN", ); slidingWindowsThrowsTest( [[1, 2, 3, 4, 5], 3, { step: NaN }], RangeError, "Cannot create sliding windows: step must be a positive integer, current value is NaN", ); slidingWindowsThrowsTest( // @ts-ignore: for test [[1, 2, 3, 4, 5], "invalid"], RangeError, "Cannot create sliding windows: size must be a positive integer, current value is invalid", ); slidingWindowsThrowsTest( // @ts-ignore: for test [[1, 2, 3, 4, 5], 3, { step: "invalid" }], RangeError, "Cannot create sliding windows: step must be a positive integer, current value is invalid", ); }, }); Deno.test({ name: "slidingWindows() handles invalid size or step: not integer number", fn() { slidingWindowsThrowsTest( [[1, 2, 3, 4, 5], 0.5], RangeError, "Cannot create sliding windows: size must be a positive integer, current value is 0.5", ); slidingWindowsThrowsTest( [[1, 2, 3, 4, 5], 3, { step: 0.5 }], RangeError, "Cannot create sliding windows: step must be a positive integer, current value is 0.5", ); slidingWindowsThrowsTest( [[1, 2, 3, 4, 5], 1.5], RangeError, "Cannot create sliding windows: size must be a positive integer, current value is 1.5", ); slidingWindowsThrowsTest( [[1, 2, 3, 4, 5], 3, { step: 1.5 }], RangeError, "Cannot create sliding windows: step must be a positive integer, current value is 1.5", ); }, }); Deno.test({ name: "slidingWindows() handles invalid size or step: not positive number", fn() { slidingWindowsThrowsTest( [[1, 2, 3, 4, 5], 0], RangeError, "Cannot create sliding windows: size must be a positive integer, current value is 0", ); slidingWindowsThrowsTest( [[1, 2, 3, 4, 5], 3, { step: 0 }], RangeError, "Cannot create sliding windows: step must be a positive integer, current value is 0", ); slidingWindowsThrowsTest( [[1, 2, 3, 4, 5], -1], RangeError, "Cannot create sliding windows: size must be a positive integer, current value is -1", ); slidingWindowsThrowsTest( [[1, 2, 3, 4, 5], 3, { step: -1 }], RangeError, "Cannot create sliding windows: step must be a positive integer, current value is -1", ); }, }); Deno.test({ name: "slidingWindows() handles invalid size or step: infinity", fn() { slidingWindowsThrowsTest( [[1, 2, 3, 4, 5], Number.NEGATIVE_INFINITY], RangeError, "Cannot create sliding windows: size must be a positive integer, current value is -Infinity", ); slidingWindowsThrowsTest( [[1, 2, 3, 4, 5], 3, { step: Number.NEGATIVE_INFINITY }], RangeError, "Cannot create sliding windows: step must be a positive integer, current value is -Infinity", ); slidingWindowsThrowsTest( [[1, 2, 3, 4, 5], Number.POSITIVE_INFINITY], RangeError, "Cannot create sliding windows: size must be a positive integer, current value is Infinity", ); slidingWindowsThrowsTest( [[1, 2, 3, 4, 5], 3, { step: Number.POSITIVE_INFINITY }], RangeError, "Cannot create sliding windows: step must be a positive integer, current value is Infinity", ); }, }); Deno.test({ name: "slidingWindows() handles large size", fn() { slidingWindowsTest([[1, 2, 3, 4, 5], 100], []); slidingWindowsTest([[1, 2, 3, 4, 5], 100, { step: 2 }], []); slidingWindowsTest( [[1, 2, 3, 4, 5], 100, { step: 2, partial: true }], [[1, 2, 3, 4, 5], [3, 4, 5], [5]], ); }, }); Deno.test({ name: "slidingWindows() handles large step", fn() { slidingWindowsTest([[1, 2, 3, 4, 5], 3, { step: 100 }], [[1, 2, 3]]); slidingWindowsTest( [[1, 2, 3, 4, 5], 3, { step: 100, partial: true }], [[1, 2, 3]], ); }, }); Deno.test({ name: "slidingWindows() handles empty Array", fn() { slidingWindowsTest([Array(5), 5], [ Array(5), ]); slidingWindowsTest([Array(5), 3], [ Array(3), Array(3), Array(3), ]); slidingWindowsTest([Array(5), 1], [ Array(1), Array(1), Array(1), Array(1), Array(1), ]); }, }); Deno.test("slidingWindows() handles a generator", () => { function* gen() { yield 1; yield 2; yield 3; yield 4; yield 5; } function* emptyGen() {} slidingWindowsTest([gen(), 5], [[1, 2, 3, 4, 5]]); slidingWindowsTest([gen(), 3], [[1, 2, 3], [2, 3, 4], [3, 4, 5]]); slidingWindowsTest([gen(), 1], [[1], [2], [3], [4], [5]]); slidingWindowsTest([gen(), 3, { partial: true }], [ [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5], [5], ]); slidingWindowsTest([gen(), 3, { step: 2 }], [[1, 2, 3], [3, 4, 5]]); slidingWindowsTest([gen(), 1, { step: 2, partial: true }], [[1], [3], [5]]); slidingWindowsTest([emptyGen(), 3], []); }); Deno.test("slidingWindows() handles a string", () => { const str = "12345"; slidingWindowsTest([str, 5], [["1", "2", "3", "4", "5"]]); slidingWindowsTest([str, 3], [["1", "2", "3"], ["2", "3", "4"], [ "3", "4", "5", ]]); slidingWindowsTest([str, 1], [["1"], ["2"], ["3"], ["4"], ["5"]]); }); Deno.test("slidingWindows() handles a Set", () => { const set = new Set([1, 2, 3, 4, 5]); slidingWindowsTest([set, 5], [[1, 2, 3, 4, 5]]); slidingWindowsTest([set, 3], [[1, 2, 3], [2, 3, 4], [3, 4, 5]]); slidingWindowsTest([set, 1], [[1], [2], [3], [4], [5]]); }); Deno.test("slidingWindows() handles a Map", () => { const map = new Map([ ["a", 1], ["b", 2], ["c", 3], ["d", 4], ["e", 5], ]); slidingWindowsTest([map, 3], [ [["a", 1], ["b", 2], ["c", 3]], [["b", 2], ["c", 3], ["d", 4]], [["c", 3], ["d", 4], ["e", 5]], ]); slidingWindowsTest([map, 1], [ [["a", 1]], [["b", 2]], [["c", 3]], [["d", 4]], [["e", 5]], ]); });