Files
oh-my-opencode/src/tools/lsp/directory-diagnostics.test.ts
T

123 lines
3.9 KiB
TypeScript
Raw Normal View History

import { beforeEach, describe, expect, it, mock } from "bun:test"
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "fs"
import { join } from "path"
import os from "os"
import type { Diagnostic } from "./types"
const diagnosticsMock = mock(async (_filePath: string) => ({ items: [] as Diagnostic[] }))
const getClientMock = mock(async () => ({ diagnostics: diagnosticsMock }))
const releaseClientMock = mock(() => {})
mock.module("./config", () => ({
findServerForExtension: (extension: string) => ({
status: "found" as const,
server: {
id: "test-server",
command: ["test-server"],
extensions: [extension],
priority: 1,
},
}),
getLanguageId: () => "typescript",
}))
mock.module("./lsp-server", () => ({
lspManager: {
getClient: getClientMock,
releaseClient: releaseClientMock,
},
}))
const { isDirectoryPath } = await import("./lsp-client-wrapper")
const { aggregateDiagnosticsForDirectory } = await import("./directory-diagnostics")
function createDiagnostic(message: string): Diagnostic {
return {
message,
severity: 1,
range: {
start: { line: 0, character: 0 },
end: { line: 0, character: 1 },
},
}
}
describe("directory diagnostics", () => {
beforeEach(() => {
diagnosticsMock.mockReset()
diagnosticsMock.mockImplementation(async (_filePath: string) => ({ items: [] }))
getClientMock.mockClear()
releaseClientMock.mockClear()
})
describe("isDirectoryPath", () => {
it("returns true for existing directory", () => {
const tmp = mkdtempSync(join(os.tmpdir(), "omo-isdir-"))
try {
expect(isDirectoryPath(tmp)).toBe(true)
} finally {
rmSync(tmp, { recursive: true, force: true })
}
})
it("returns false for existing file", () => {
const tmp = mkdtempSync(join(os.tmpdir(), "omo-isdir-file-"))
try {
const file = join(tmp, "test.txt")
writeFileSync(file, "content")
expect(isDirectoryPath(file)).toBe(false)
} finally {
rmSync(tmp, { recursive: true, force: true })
}
})
it("returns false for non-existent path", () => {
const nonExistent = join(os.tmpdir(), "omo-nonexistent-" + Date.now())
expect(isDirectoryPath(nonExistent)).toBe(false)
})
})
describe("aggregateDiagnosticsForDirectory", () => {
it("throws error when extension does not start with dot", async () => {
const tmp = mkdtempSync(join(os.tmpdir(), "omo-aggr-ext-"))
try {
await expect(aggregateDiagnosticsForDirectory(tmp, "ts")).rejects.toThrow(
'Extension must start with a dot (e.g., ".ts", not "ts")'
)
} finally {
rmSync(tmp, { recursive: true, force: true })
}
})
it("throws error when directory does not exist", async () => {
const nonExistent = join(os.tmpdir(), "omo-nonexistent-dir-" + Date.now())
await expect(aggregateDiagnosticsForDirectory(nonExistent, ".ts")).rejects.toThrow(
"Directory does not exist"
)
})
it("#given diagnostics from multiple files #when aggregating directory diagnostics #then each entry includes the source file path", async () => {
const tmp = mkdtempSync(join(os.tmpdir(), "omo-aggr-files-"))
try {
const firstFile = join(tmp, "first.ts")
const secondFile = join(tmp, "second.ts")
writeFileSync(firstFile, "export const first = true\n")
writeFileSync(secondFile, "export const second = true\n")
diagnosticsMock.mockImplementation(async (filePath: string) => ({
items: [createDiagnostic(`problem in ${filePath}`)],
}))
const result = await aggregateDiagnosticsForDirectory(tmp, ".ts")
expect(result).toContain(`${firstFile}: error at 1:0: problem in ${firstFile}`)
expect(result).toContain(`${secondFile}: error at 1:0: problem in ${secondFile}`)
} finally {
rmSync(tmp, { recursive: true, force: true })
}
})
})
})