/*
RFC-1051: test integrity core modules — paths, fs, json, types, discover, policy helpers.
- Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only.
- RFC-1051: initial integrity core tests.
*/
import { test, expect, beforeEach, afterEach } from "vitest";
import { mkdtempSync, rmSync } from "node:fs";
import path from "node:path";
import os from "node:os";
import * as paths from "../paths.ts";
import * as fsMod from "../fs.ts";
import * as jsonMod from "../json.ts";
import * as types from "../types.ts";
import { groupFilesByDirectory } from "../discover.ts";
import { stableStringify } from "../json.ts";
let tmpDir: string;
beforeEach(() => {
tmpDir = mkdtempSync(path.join(os.tmpdir(), "integrity-test-"));
});
afterEach(() => {
rmSync(tmpDir, { recursive: true, force: true });
});
// --- paths.ts ---
test("integrityRoot returns integrity path under repo", () => {
expect(paths.integrityRoot("/repo")).toContain("integrity");
expect(paths.integrityRoot("/repo")).toContain("/repo");
});
test("configDir returns integrity config path", () => {
expect(paths.configDir("/repo")).toContain("integrity");
});
test("schemaDir returns integrity schema path", () => {
expect(paths.schemaDir("/repo")).toContain("schema");
});
test("policyPath returns policy file path", () => {
expect(paths.policyPath("/repo")).toContain("policy");
});
test("indexDir returns index path", () => {
expect(paths.indexDir("/repo")).toContain("index");
});
// --- fs.ts ---
test("ensureDir creates directory recursively", async () => {
const dir = path.join(tmpDir, "a", "b", "c");
await fsMod.ensureDir(dir);
await expect(fsMod.pathExists(dir)).resolves.toBe(true);
});
test("pathExists returns false for non-existent path", async () => {
await expect(fsMod.pathExists(path.join(tmpDir, "nope"))).resolves.toBe(false);
});
test("pathExists returns true for existing path", async () => {
await expect(fsMod.pathExists(tmpDir)).resolves.toBe(true);
});
test("writeText and readText round-trip", async () => {
const filePath = path.join(tmpDir, "test.txt");
await fsMod.writeText(filePath, "hello world");
const content = await fsMod.readText(filePath);
expect(content).toBe("hello world");
});
test("readBuffer returns Buffer", async () => {
const filePath = path.join(tmpDir, "test.bin");
await fsMod.writeText(filePath, "data");
const buf = await fsMod.readBuffer(filePath);
expect(buf).toBeInstanceOf(Buffer);
});
// --- json.ts ---
test("stableStringify produces sorted keys", () => {
const result = stableStringify({ b: 2, a: 1 });
expect(result).toContain('"a"');
expect(result).toContain('"b"');
expect(result.indexOf('"a"')).toBeLessThan(result.indexOf('"b"'));
});
test("writeJsonFile and readJsonFile round-trip", async () => {
const filePath = path.join(tmpDir, "test.json");
await jsonMod.writeJsonFile(filePath, { name: "test", count: 42 });
const result = await jsonMod.readJsonFile<{ name: string; count: number }>(filePath);
expect(result.name).toBe("test");
expect(result.count).toBe(42);
});
// --- types.ts (load verification) ---
test("integrity types module loads without error", () => {
expect(types).toBeDefined();
const status: types.IntegrityStatus = "active";
expect(status).toBe("active");
});
// --- discover.ts ---
test("groupFilesByDirectory groups files by parent directory", async () => {
const files = ["/repo/a.ts", "/repo/b.ts", "/repo/sub/c.ts"];
const grouped = await groupFilesByDirectory(files);
expect(grouped.get("/repo")).toEqual(["/repo/a.ts", "/repo/b.ts"]);
expect(grouped.get("/repo/sub")).toEqual(["/repo/sub/c.ts"]);
});
test("groupFilesByDirectory handles empty input", async () => {
const grouped = await groupFilesByDirectory([]);
expect(grouped.size).toBe(0);
});