import { describe, expect, it } from "@suaveplan/testing/runner"; import { findExtraFields } from "./find-extra-fields.js"; describe("findExtraFields", () => { it("returns empty for null schema", () => { expect(findExtraFields(null, { a: 1 })).toEqual([]); }); it("returns empty for null data", () => { expect(findExtraFields({ a: 1 }, null)).toEqual([]); }); it("returns empty for undefined data", () => { expect(findExtraFields({ a: 1 }, undefined)).toEqual([]); }); it("handles optional wrapper with undefined data", () => { const schema = { _bp: { schema: 255 } }; expect( findExtraFields( schema as unknown as import("@suaveplan/types").BitPackerSchema, undefined ) ).toEqual([]); }); it("unwraps optional schema", () => { const schema = { _bp: { schema: { a: 255 } } }; const data = { a: 1, b: 2 }; const extras = findExtraFields( schema as unknown as import("@suaveplan/types").BitPackerSchema, data ); expect(extras.length).toBe(1); expect(extras[0]).toMatchObject({ path: "b", value: 2 }); }); it("returns empty for primitive schemas", () => { expect(findExtraFields(true, false)).toEqual([]); expect(findExtraFields(255, 100)).toEqual([]); expect(findExtraFields("-8", "hello")).toEqual([]); }); it("finds extra elements in arrays", () => { const schema = [255, 255]; const data = [1, 2, 3, 4]; const extras = findExtraFields(schema, data); expect(extras.length).toBe(2); expect(extras[0]).toMatchObject({ path: "[2]", value: 3 }); expect(extras[1]).toMatchObject({ path: "[3]", value: 4 }); }); it("recursively checks array elements", () => { const schema = [{ a: 255 }]; const data = [{ a: 1, b: 2 }]; const extras = findExtraFields(schema, data); expect(extras.length).toBe(1); expect(extras[0]).toMatchObject({ path: "[0].b", value: 2 }); }); it("finds extra fields in objects", () => { const schema = { a: 255 }; const data = { a: 1, b: 2 }; const extras = findExtraFields(schema, data); expect(extras.length).toBe(1); expect(extras[0]).toMatchObject({ path: "b", value: 2 }); }); it("recursively checks nested objects", () => { const schema = { outer: { a: 255 } }; const data = { outer: { a: 1, b: 2 } }; const extras = findExtraFields(schema, data); expect(extras.length).toBe(1); expect(extras[0]).toMatchObject({ path: "outer.b", value: 2 }); }); it("returns empty when no extra fields", () => { const schema = { a: 255, b: "-8" }; const data = { a: 1, b: "hello" }; expect(findExtraFields(schema, data)).toEqual([]); }); it("handles path prefix", () => { const schema = { a: 255 }; const data = { a: 1, b: 2 }; const extras = findExtraFields(schema, data, "root"); expect(extras[0].path).toBe("root.b"); }); it("handles array path prefix", () => { const schema = [255]; const data = [1, 2]; const extras = findExtraFields(schema, data, "items"); expect(extras[0].path).toBe("items[1]"); }); it("skips undefined schema properties", () => { const schema = { a: 255 }; const data = { a: 1 }; expect(findExtraFields(schema, data)).toEqual([]); }); it("returns empty for array schema with non-array data", () => { expect(findExtraFields([255], "not array")).toEqual([]); }); it("returns empty for object schema with non-object data", () => { expect(findExtraFields({ a: 255 }, "not object")).toEqual([]); }); it("skips inherited properties in data", () => { const schema = { a: 255 }; const data = Object.create({ inherited: 1 }); data.a = 1; expect(findExtraFields(schema, data)).toEqual([]); }); it("skips undefined schema property values", () => { const schema: Record = { a: 255 }; schema.b = undefined; const data = { a: 1, b: 2 }; const extras = findExtraFields( schema as import("@suaveplan/types").BitPackerSchema, data ); // undefined schema properties are skipped, not treated as extra fields expect(extras).toEqual([]); }); });