Files
OmniRoute/tests/unit/numeric-helpers.test.ts
2026-07-22 02:35:08 -03:00

90 lines
3.3 KiB
TypeScript

import assert from "node:assert/strict";
import { test } from "node:test";
import {
toNumber,
toNumberOrNull,
toNumberArray,
} from "../../src/shared/utils/numeric.ts";
// Shared input matrix covering the coercion edge cases that motivated
// consolidating ~51 near-duplicate `toNumber` definitions (#7879).
const CASES: Array<{ label: string; input: unknown; finite: number | null }> = [
{ label: "null", input: null, finite: null },
{ label: "undefined", input: undefined, finite: null },
{ label: "empty string", input: "", finite: null },
{ label: "whitespace string", input: " ", finite: null },
{ label: "numeric string", input: "12", finite: 12 },
{ label: "decimal string", input: "12.5", finite: 12.5 },
{ label: "negative string", input: "-3", finite: -3 },
{ label: "zero string", input: "0", finite: 0 },
{ label: "non-numeric string", input: "abc", finite: null },
{ label: "partially-numeric string", input: "12abc", finite: null },
{ label: "NaN", input: NaN, finite: null },
{ label: "Infinity", input: Infinity, finite: null },
{ label: "-Infinity", input: -Infinity, finite: null },
{ label: "plain object", input: {}, finite: null },
{ label: "empty array", input: [], finite: null },
{ label: "exponential string", input: "1e3", finite: 1000 },
{ label: "boolean true", input: true, finite: null },
];
test("toNumber: matrix with default fallback (0)", () => {
for (const { label, input, finite } of CASES) {
const expected = finite ?? 0;
assert.equal(toNumber(input), expected, `toNumber(${label}) should be ${expected}`);
}
});
test("toNumber: matrix with custom fallback", () => {
for (const { label, input, finite } of CASES) {
const expected = finite ?? -1;
assert.equal(
toNumber(input, -1),
expected,
`toNumber(${label}, -1) should be ${expected}`
);
}
});
test("toNumber: numbers pass through untouched", () => {
assert.equal(toNumber(42), 42);
assert.equal(toNumber(-7.5), -7.5);
assert.equal(toNumber(0), 0);
});
test("toNumberOrNull: matrix returns null instead of 0 fallback", () => {
for (const { label, input, finite } of CASES) {
assert.equal(
toNumberOrNull(input),
finite,
`toNumberOrNull(${label}) should be ${finite}`
);
}
});
test("toNumberOrNull: numbers pass through untouched", () => {
assert.equal(toNumberOrNull(42), 42);
assert.equal(toNumberOrNull(0), 0);
});
test("toNumberArray: non-array input returns the fallback unchanged", () => {
assert.deepEqual(toNumberArray(null), []);
assert.deepEqual(toNumberArray(undefined), []);
assert.deepEqual(toNumberArray("not an array"), []);
assert.deepEqual(toNumberArray({}), []);
assert.deepEqual(toNumberArray(null, [1, 2]), [1, 2]);
});
test("toNumberArray: maps each element through toNumber, bad elements become 0", () => {
assert.deepEqual(toNumberArray(["12", "12.5", "abc", null, 3]), [12, 12.5, 0, 0, 3]);
assert.deepEqual(toNumberArray([]), []);
});
test("toNumberArray: element-level fallback (0) is independent of the array-level fallback", () => {
// Array itself IS present (so array-level fallback does not apply), but one
// element fails to coerce and must fall back to 0, not to the caller's
// array-level fallback value.
assert.deepEqual(toNumberArray(["abc"], [99]), [0]);
});