/** * embedding-provider.test.ts - Tests for the EmbeddingProvider abstraction * (interface-level: model-id guard, ModelMismatchError). */ import { describe, test, expect } from "vitest"; import { ModelMismatchError, assertModelCompatible, } from "../src/embedding/provider.js"; describe("assertModelCompatible", () => { test("empty existingModels → no throw (fresh DB)", () => { expect(() => assertModelCompatible("anything", [])).not.toThrow(); }); test("matching model id → no throw", () => { expect(() => assertModelCompatible("embeddinggemma", ["embeddinggemma"]), ).not.toThrow(); }); test("matching one of several → no throw", () => { expect(() => assertModelCompatible("embeddinggemma", ["embeddinggemma", "qwen3-embed"]), ).not.toThrow(); }); test("mismatch throws ModelMismatchError", () => { expect(() => assertModelCompatible("openai-text-embedding", ["embeddinggemma"]), ).toThrow(ModelMismatchError); }); test("error message lists existing models + provider model", () => { try { assertModelCompatible("provider-x", ["model-a", "model-b"]); throw new Error("should have thrown"); } catch (err) { expect(err).toBeInstanceOf(ModelMismatchError); const e = err as ModelMismatchError; expect(e.providerModel).toBe("provider-x"); expect(e.existingModels).toEqual(["model-a", "model-b"]); expect(e.message).toContain("provider-x"); expect(e.message).toContain("model-a"); expect(e.message).toContain("qmd embed -f"); expect(e.message).toContain("QMD_EMBED_MODEL_ID"); } }); }); describe("ModelMismatchError", () => { test("name set correctly", () => { const err = new ModelMismatchError("a", ["b"]); expect(err.name).toBe("ModelMismatchError"); }); test("instanceof Error", () => { const err = new ModelMismatchError("a", ["b"]); expect(err).toBeInstanceOf(Error); expect(err).toBeInstanceOf(ModelMismatchError); }); });