import { describe, expect, it } from "vitest"; import { cosineSimilarity, StubEmbeddingProvider, stubEmbed, STUB_EMBEDDING_DIMENSION } from "./embeddings.js"; describe("stubEmbed", () => { it("is deterministic: same text → byte-identical vector", () => { expect(stubEmbed("hello world")).toEqual(stubEmbed("hello world")); }); it("is dimension-exact and L2-normalized", () => { const v = stubEmbed("the quick brown fox jumps over the lazy dog"); expect(v).toHaveLength(STUB_EMBEDDING_DIMENSION); const norm = Math.sqrt(v.reduce((acc, x) => acc + x * x, 0)); expect(norm).toBeCloseTo(1, 10); }); it("respects a custom dimension", () => { expect(stubEmbed("abc", 16)).toHaveLength(16); }); it("returns a zero vector for empty text", () => { const v = stubEmbed(" "); expect(v.every((x) => x === 0)).toBe(true); }); it("case- and whitespace-insensitive at the surface", () => { expect(stubEmbed("Hello World")).toEqual(stubEmbed("hello world")); }); it("similar texts score higher than dissimilar ones", () => { const base = stubEmbed("quarterly revenue forecast for the sales team"); const near = stubEmbed("quarterly revenue forecast targets for sales"); const far = stubEmbed("recipe for chocolate chip cookies with butter"); expect(cosineSimilarity(base, near)).toBeGreaterThan(cosineSimilarity(base, far)); }); }); describe("StubEmbeddingProvider", () => { it("exposes the contract (model, dimension, embed)", async () => { const provider = new StubEmbeddingProvider(); expect(provider.model).toBe("stub-v1"); expect(provider.dimension).toBe(STUB_EMBEDDING_DIMENSION); const vectors = await provider.embed(["alpha", "beta", "alpha"]); expect(vectors).toHaveLength(3); expect(vectors[0]).toEqual(vectors[2]); // same text → same vector expect(vectors[0]).not.toEqual(vectors[1]); }); }); describe("cosineSimilarity", () => { it("is 1 for identical unit vectors and 0 for orthogonal", () => { expect(cosineSimilarity([1, 0], [1, 0])).toBeCloseTo(1, 12); expect(cosineSimilarity([1, 0], [0, 1])).toBeCloseTo(0, 12); }); it("returns 0 for zero vectors (no NaN)", () => { expect(cosineSimilarity([0, 0], [1, 1])).toBe(0); }); it("throws on dimension mismatch (the §7.3 structural guard)", () => { expect(() => cosineSimilarity([1], [1, 2])).toThrow("dimension mismatch"); }); });