mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-30 05:43:55 +00:00
- Rename packages/opencode → packages/tfcode (directory only) - Rename bin/opencode → bin/tfcode (CLI binary) - Rename .opencode → .tfcode (config directory) - Update package.json name and bin field - Update config directory path references (.tfcode) - Keep internal code references as 'opencode' for easy upstream sync - Keep @opencode-ai/* workspace package names This minimal branding approach allows clean merges from upstream opencode repository while providing tfcode branding for users.
112 lines
3.3 KiB
TypeScript
112 lines
3.3 KiB
TypeScript
import { describe, expect, test } from "bun:test"
|
|
import path from "path"
|
|
import { GrepTool } from "../../src/tool/grep"
|
|
import { Instance } from "../../src/project/instance"
|
|
import { tmpdir } from "../fixture/fixture"
|
|
import { SessionID, MessageID } from "../../src/session/schema"
|
|
|
|
const ctx = {
|
|
sessionID: SessionID.make("ses_test"),
|
|
messageID: MessageID.make(""),
|
|
callID: "",
|
|
agent: "build",
|
|
abort: AbortSignal.any([]),
|
|
messages: [],
|
|
metadata: () => {},
|
|
ask: async () => {},
|
|
}
|
|
|
|
const projectRoot = path.join(__dirname, "../..")
|
|
|
|
describe("tool.grep", () => {
|
|
test("basic search", async () => {
|
|
await Instance.provide({
|
|
directory: projectRoot,
|
|
fn: async () => {
|
|
const grep = await GrepTool.init()
|
|
const result = await grep.execute(
|
|
{
|
|
pattern: "export",
|
|
path: path.join(projectRoot, "src/tool"),
|
|
include: "*.ts",
|
|
},
|
|
ctx,
|
|
)
|
|
expect(result.metadata.matches).toBeGreaterThan(0)
|
|
expect(result.output).toContain("Found")
|
|
},
|
|
})
|
|
})
|
|
|
|
test("no matches returns correct output", async () => {
|
|
await using tmp = await tmpdir({
|
|
init: async (dir) => {
|
|
await Bun.write(path.join(dir, "test.txt"), "hello world")
|
|
},
|
|
})
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
const grep = await GrepTool.init()
|
|
const result = await grep.execute(
|
|
{
|
|
pattern: "xyznonexistentpatternxyz123",
|
|
path: tmp.path,
|
|
},
|
|
ctx,
|
|
)
|
|
expect(result.metadata.matches).toBe(0)
|
|
expect(result.output).toBe("No files found")
|
|
},
|
|
})
|
|
})
|
|
|
|
test("handles CRLF line endings in output", async () => {
|
|
// This test verifies the regex split handles both \n and \r\n
|
|
await using tmp = await tmpdir({
|
|
init: async (dir) => {
|
|
// Create a test file with content
|
|
await Bun.write(path.join(dir, "test.txt"), "line1\nline2\nline3")
|
|
},
|
|
})
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
const grep = await GrepTool.init()
|
|
const result = await grep.execute(
|
|
{
|
|
pattern: "line",
|
|
path: tmp.path,
|
|
},
|
|
ctx,
|
|
)
|
|
expect(result.metadata.matches).toBeGreaterThan(0)
|
|
},
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("CRLF regex handling", () => {
|
|
test("regex correctly splits Unix line endings", () => {
|
|
const unixOutput = "file1.txt|1|content1\nfile2.txt|2|content2\nfile3.txt|3|content3"
|
|
const lines = unixOutput.trim().split(/\r?\n/)
|
|
expect(lines.length).toBe(3)
|
|
expect(lines[0]).toBe("file1.txt|1|content1")
|
|
expect(lines[2]).toBe("file3.txt|3|content3")
|
|
})
|
|
|
|
test("regex correctly splits Windows CRLF line endings", () => {
|
|
const windowsOutput = "file1.txt|1|content1\r\nfile2.txt|2|content2\r\nfile3.txt|3|content3"
|
|
const lines = windowsOutput.trim().split(/\r?\n/)
|
|
expect(lines.length).toBe(3)
|
|
expect(lines[0]).toBe("file1.txt|1|content1")
|
|
expect(lines[2]).toBe("file3.txt|3|content3")
|
|
})
|
|
|
|
test("regex handles mixed line endings", () => {
|
|
const mixedOutput = "file1.txt|1|content1\nfile2.txt|2|content2\r\nfile3.txt|3|content3"
|
|
const lines = mixedOutput.trim().split(/\r?\n/)
|
|
expect(lines.length).toBe(3)
|
|
})
|
|
})
|