/** * Input validation utility tests * * TRACES: UR-009, UR-025 | DR-015 */ import { describe, it, expect } from "vitest"; import { validateItemId, validateImageType, validateMediaSourceId, validateNumericParam, validateQueryParamValue, } from "./validation"; describe("validateItemId", () => { it("should accept valid item IDs", () => { expect(() => validateItemId("123abc")).not.toThrow(); expect(() => validateItemId("abc-123_def")).not.toThrow(); expect(() => validateItemId("12345")).not.toThrow(); }); it("should reject empty or non-string IDs", () => { expect(() => validateItemId("")).toThrow("must be a non-empty string"); expect(() => validateItemId(null as any)).toThrow("must be a non-empty string"); expect(() => validateItemId(undefined as any)).toThrow("must be a non-empty string"); }); it("should reject IDs exceeding max length", () => { expect(() => validateItemId("a".repeat(51))).toThrow("exceeds maximum length"); }); it("should reject IDs with invalid characters", () => { expect(() => validateItemId("abc/def")).toThrow("contains invalid characters"); expect(() => validateItemId("abc..def")).toThrow("contains invalid characters"); expect(() => validateItemId("abc def")).toThrow("contains invalid characters"); }); }); describe("validateImageType", () => { it("should accept valid image types", () => { expect(() => validateImageType("Primary")).not.toThrow(); expect(() => validateImageType("Backdrop")).not.toThrow(); expect(() => validateImageType("Banner")).not.toThrow(); expect(() => validateImageType("Logo")).not.toThrow(); }); it("should reject invalid image types", () => { expect(() => validateImageType("InvalidType")).toThrow("not a valid image type"); expect(() => validateImageType("..")).toThrow("not a valid image type"); expect(() => validateImageType("Primary/Avatar")).toThrow("not a valid image type"); }); it("should reject empty or non-string types", () => { expect(() => validateImageType("")).toThrow("must be a non-empty string"); }); }); describe("validateMediaSourceId", () => { it("should accept valid media source IDs", () => { expect(() => validateMediaSourceId("source-123")).not.toThrow(); expect(() => validateMediaSourceId("video_stream_1")).not.toThrow(); }); it("should reject IDs with invalid characters", () => { expect(() => validateMediaSourceId("source/path")).toThrow("contains invalid characters"); expect(() => validateMediaSourceId("source..path")).toThrow("contains invalid characters"); }); it("should reject IDs exceeding max length", () => { expect(() => validateMediaSourceId("a".repeat(51))).toThrow("exceeds maximum length"); }); }); describe("validateNumericParam", () => { it("should accept valid numbers", () => { expect(validateNumericParam(100)).toBe(100); expect(validateNumericParam(0)).toBe(0); expect(validateNumericParam(9999)).toBe(9999); }); it("should reject non-integers", () => { expect(() => validateNumericParam(10.5)).toThrow("must be an integer"); expect(() => validateNumericParam("100")).toThrow("must be an integer"); }); it("should respect min and max bounds", () => { expect(() => validateNumericParam(-1, 0, 100)).toThrow("must be between 0 and 100"); expect(() => validateNumericParam(101, 0, 100)).toThrow("must be between 0 and 100"); }); it("should allow custom bounds", () => { expect(validateNumericParam(50, 10, 100)).toBe(50); expect(() => validateNumericParam(5, 10, 100)).toThrow("must be between 10 and 100"); }); }); describe("validateQueryParamValue", () => { it("should accept valid query param values", () => { expect(() => validateQueryParamValue("abc123")).not.toThrow(); expect(() => validateQueryParamValue("value-with-dash")).not.toThrow(); expect(() => validateQueryParamValue("value_with_underscore")).not.toThrow(); }); it("should reject values with invalid characters", () => { expect(() => validateQueryParamValue("value with spaces")).toThrow("contains invalid characters"); expect(() => validateQueryParamValue("value/path")).toThrow("contains invalid characters"); expect(() => validateQueryParamValue("value?query")).toThrow("contains invalid characters"); }); it("should reject values exceeding max length", () => { expect(() => validateQueryParamValue("a".repeat(101))).toThrow("exceeds maximum length"); }); it("should respect custom max length", () => { expect(() => validateQueryParamValue("a".repeat(50), 40)).toThrow("exceeds maximum length"); }); });