/** * Unit tests for collection config path resolution (PR #190). * * Tests that getConfigDir() respects XDG_CONFIG_HOME, QMD_CONFIG_DIR, * and falls back to ~/.config/qmd. */ import { describe, test, expect, beforeEach, afterEach } from "vitest"; import { join } from "path"; import { homedir, tmpdir } from "os"; import { mkdtempSync, rmSync, readFileSync } from "fs"; import { getConfigPath, setConfigIndexName, setConfigSource, loadConfig, saveConfig, } from "../src/collections.js"; import type { CollectionConfig } from "../src/collections.js"; // Save/restore env vars around each test let savedEnv: Record; beforeEach(() => { savedEnv = { QMD_CONFIG_DIR: process.env.QMD_CONFIG_DIR, XDG_CONFIG_HOME: process.env.XDG_CONFIG_HOME, }; // Reset index name to default setConfigIndexName("index"); }); afterEach(() => { // Reset index name to default (prevents leaking into other test files under bun test) setConfigIndexName("index"); for (const [key, val] of Object.entries(savedEnv)) { if (val === undefined) { delete process.env[key]; } else { process.env[key] = val; } } }); describe("getConfigDir via getConfigPath", () => { test("defaults to ~/.config/qmd when no env vars are set", () => { delete process.env.QMD_CONFIG_DIR; delete process.env.XDG_CONFIG_HOME; expect(getConfigPath()).toBe(join(homedir(), ".config", "qmd", "index.yml")); }); test("QMD_CONFIG_DIR takes highest priority", () => { process.env.QMD_CONFIG_DIR = "/custom/qmd-config"; process.env.XDG_CONFIG_HOME = "/xdg/config"; expect(getConfigPath()).toBe(join("/custom/qmd-config", "index.yml")); }); test("XDG_CONFIG_HOME is used when QMD_CONFIG_DIR is not set", () => { delete process.env.QMD_CONFIG_DIR; process.env.XDG_CONFIG_HOME = "/xdg/config"; expect(getConfigPath()).toBe(join("/xdg/config", "qmd", "index.yml")); }); test("XDG_CONFIG_HOME appends qmd subdirectory", () => { delete process.env.QMD_CONFIG_DIR; process.env.XDG_CONFIG_HOME = "/home/agent/.config"; expect(getConfigPath()).toBe(join("/home/agent/.config", "qmd", "index.yml")); }); test("QMD_CONFIG_DIR overrides XDG_CONFIG_HOME", () => { process.env.QMD_CONFIG_DIR = "/override"; process.env.XDG_CONFIG_HOME = "/should-not-use"; expect(getConfigPath()).toBe(join("/override", "index.yml")); }); test("respects custom index name", () => { delete process.env.QMD_CONFIG_DIR; process.env.XDG_CONFIG_HOME = "/xdg/config"; setConfigIndexName("myindex"); expect(getConfigPath()).toBe(join("/xdg/config", "qmd", "myindex.yml")); }); }); // ============================================================================ // chunkStrategy schema round-trip (Phase 2 — i-bud0h8vu) // ============================================================================ describe("Collection.chunkStrategy YAML round-trip", () => { let tmpDir: string; beforeEach(() => { tmpDir = mkdtempSync(join(tmpdir(), "qmd-chunkstrategy-")); process.env.QMD_CONFIG_DIR = tmpDir; setConfigIndexName("index"); }); afterEach(() => { // Reset config source so we don't leak inline state setConfigSource(); try { rmSync(tmpDir, { recursive: true, force: true }); } catch { // best-effort } }); test("chunkStrategy field persists through save/load cycle", () => { const config: CollectionConfig = { collections: { "oivo-cli": { path: "/srv/cli/src", pattern: "**/*.ts", chunkStrategy: "function", }, "oivo-docs": { path: "/srv/docs", pattern: "**/*.md", // no chunkStrategy — should remain unset after round-trip }, }, }; saveConfig(config); const loaded = loadConfig(); expect(loaded.collections["oivo-cli"]?.chunkStrategy).toBe("function"); expect(loaded.collections["oivo-docs"]?.chunkStrategy).toBeUndefined(); }); test("chunkStrategy 'auto' and 'regex' round-trip", () => { const config: CollectionConfig = { collections: { a: { path: "/a", pattern: "*.ts", chunkStrategy: "auto" }, b: { path: "/b", pattern: "*.ts", chunkStrategy: "regex" }, }, }; saveConfig(config); const loaded = loadConfig(); expect(loaded.collections.a?.chunkStrategy).toBe("auto"); expect(loaded.collections.b?.chunkStrategy).toBe("regex"); }); test("omitted chunkStrategy does not appear in serialized YAML", () => { const config: CollectionConfig = { collections: { plain: { path: "/p", pattern: "*.md" }, }, }; saveConfig(config); const yaml = readFileSync(join(tmpDir, "index.yml"), "utf-8"); expect(yaml).not.toContain("chunkStrategy"); }); });