import { Database } from "bun:sqlite"; import { afterEach, beforeEach, describe, expect, test } from "bun:test"; import { mkdtempSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { getRootLastActivity } from "./root-activity"; let sqlite: Database; let tempDir: string; beforeEach(() => { tempDir = mkdtempSync(join(tmpdir(), "scribe-root-activity-")); sqlite = new Database(join(tempDir, "scribe.db"), { create: true }); sqlite.exec(` CREATE TABLE timeline_events ( id TEXT PRIMARY KEY, timestamp INTEGER NOT NULL, project_root_id TEXT ); `); }); afterEach(() => { sqlite.close(); rmSync(tempDir, { recursive: true, force: true }); }); function insertEvent(id: string, rootId: string | null, seconds: number): void { sqlite .prepare( "INSERT INTO timeline_events (id, project_root_id, timestamp) VALUES (?, ?, ?)", ) .run(id, rootId, seconds); } describe("getRootLastActivity", () => { test("returns the latest event per root in epoch milliseconds", () => { insertEvent("e1", "root-a", 100); insertEvent("e2", "root-a", 300); // newest for root-a insertEvent("e3", "root-a", 200); insertEvent("e4", "root-b", 150); const activity = getRootLastActivity(sqlite); expect(activity.get("root-a")).toBe(300_000); expect(activity.get("root-b")).toBe(150_000); }); test("ignores events with no project root", () => { insertEvent("e1", null, 500); const activity = getRootLastActivity(sqlite); expect(activity.size).toBe(0); }); test("is empty when there are no events", () => { expect(getRootLastActivity(sqlite).size).toBe(0); }); });