import { describe, it } from "@effect/vitest" import { assertFalse, assertTrue, deepStrictEqual, strictEqual } from "@effect/vitest/utils" import { Array as Arr, Order, pipe } from "effect" describe("Order", () => { it("Struct", () => { const O = Order.Struct({ a: Order.String, b: Order.String }) strictEqual(O({ a: "a", b: "b" }, { a: "a", b: "c" }), -1) strictEqual(O({ a: "a", b: "b" }, { a: "a", b: "b" }), 0) strictEqual(O({ a: "a", b: "c" }, { a: "a", b: "b" }), 1) }) it("Tuple", () => { const O = Order.Tuple([Order.String, Order.String]) strictEqual(O(["a", "b"], ["a", "c"]), -1) strictEqual(O(["a", "b"], ["a", "b"]), 0) strictEqual(O(["a", "b"], ["a", "a"]), 1) strictEqual(O(["a", "b"], ["b", "a"]), -1) }) it("mapInput", () => { const O = Order.mapInput(Order.Number, (s: string) => s.length) strictEqual(O("a", "b"), 0) strictEqual(O("a", "bb"), -1) strictEqual(O("aa", "b"), 1) }) it("Number compares numeric values and treats NaN as the lowest value", () => { const O = Order.Number strictEqual(O(1, 1), 0) strictEqual(O(1, 2), -1) strictEqual(O(2, 1), 1) strictEqual(O(0, -0), 0) strictEqual(O(NaN, NaN), 0) strictEqual(O(NaN, 1), -1) strictEqual(O(1, NaN), 1) }) it("Date compares by timestamp", () => { const O = Order.Date strictEqual(O(new Date(0), new Date(1)), -1) strictEqual(O(new Date(1), new Date(1)), 0) strictEqual(O(new Date(1), new Date(0)), 1) }) it("clamp keeps values inside inclusive bounds", () => { const clamp = Order.clamp(Order.Number)({ minimum: 1, maximum: 10 }) strictEqual(clamp(2), 2) strictEqual(clamp(10), 10) strictEqual(clamp(20), 10) strictEqual(clamp(1), 1) strictEqual(clamp(-10), 1) strictEqual(Order.clamp(Order.Number)({ minimum: 1, maximum: 10 })(2), 2) }) it("isBetween checks inclusive bounds", () => { const between = Order.isBetween(Order.Number)({ minimum: 1, maximum: 10 }) assertTrue(between(2)) assertTrue(between(10)) assertFalse(between(20)) assertTrue(between(1)) assertFalse(between(-10)) assertTrue(Order.isBetween(Order.Number)(2, { minimum: 1, maximum: 10 })) }) it("flip reverses an existing order", () => { const O = Order.flip(Order.Number) strictEqual(O(1, 2), 1) strictEqual(O(2, 1), -1) strictEqual(O(2, 2), 0) }) it("isLessThan returns true only for strictly smaller values", () => { const lessThan = Order.isLessThan(Order.Number) assertTrue(lessThan(0, 1)) assertFalse(lessThan(1, 1)) assertFalse(lessThan(2, 1)) }) it("isLessThanOrEqualTo returns true for smaller or equal values", () => { const lessThanOrEqualTo = Order.isLessThanOrEqualTo(Order.Number) assertTrue(lessThanOrEqualTo(0, 1)) assertTrue(lessThanOrEqualTo(1, 1)) assertFalse(lessThanOrEqualTo(2, 1)) }) it("isGreaterThan returns true only for strictly greater values", () => { const greaterThan = Order.isGreaterThan(Order.Number) assertFalse(greaterThan(0, 1)) assertFalse(greaterThan(1, 1)) assertTrue(greaterThan(2, 1)) }) it("isGreaterThanOrEqualTo returns true for greater or equal values", () => { const greaterThanOrEqualTo = Order.isGreaterThanOrEqualTo(Order.Number) assertFalse(greaterThanOrEqualTo(0, 1)) assertTrue(greaterThanOrEqualTo(1, 1)) assertTrue(greaterThanOrEqualTo(2, 1)) }) it("min", () => { type A = { a: number } const min = Order.min( pipe( Order.Number, Order.mapInput((a: A) => a.a) ) ) deepStrictEqual(min({ a: 1 }, { a: 2 }), { a: 1 }) deepStrictEqual(min({ a: 2 }, { a: 1 }), { a: 1 }) const first = { a: 1 } const second = { a: 1 } deepStrictEqual(min(first, second), first) }) it("max", () => { type A = { a: number } const max = Order.max( pipe( Order.Number, Order.mapInput((a: A) => a.a) ) ) deepStrictEqual(max({ a: 1 }, { a: 2 }), { a: 2 }) deepStrictEqual(max({ a: 2 }, { a: 1 }), { a: 2 }) const first = { a: 1 } const second = { a: 1 } deepStrictEqual(max(first, second), first) }) it("combine", () => { type T = [number, string] const tuples: Array = [ [2, "c"], [1, "b"], [2, "a"], [1, "c"] ] const sortByFst = pipe( Order.Number, Order.mapInput((x: T) => x[0]) ) const sortBySnd = pipe( Order.String, Order.mapInput((x: T) => x[1]) ) deepStrictEqual(Arr.sort(Order.combine(sortByFst, sortBySnd))(tuples), [ [1, "b"], [1, "c"], [2, "a"], [2, "c"] ]) deepStrictEqual(Arr.sort(Order.combine(sortBySnd, sortByFst))(tuples), [ [2, "a"], [1, "b"], [1, "c"], [2, "c"] ]) }) })