test: Add comprehensive test coverage for critical modules
- Add tests for chat/encryption.js: encryption/decryption, hashing, token generation - Add tests for chat/tokenManager.js: JWT tokens, device fingerprints, cookie handling - Add tests for chat/prompt-sanitizer.js: security patterns, attack detection, obfuscation - Add tests for admin panel: session management, rate limiting, user/token management - Add tests for OpenCode write tool: file creation, overwrites, nested directories - Add tests for OpenCode todo tools: todo CRUD operations - Add tests for Console billing/account/provider: schemas, validation, price utilities These tests cover previously untested critical paths including: - Authentication and security - Payment processing validation - Admin functionality - Model routing and management - Account management
This commit is contained in:
264
opencode/packages/opencode/test/tool/write.test.ts
Normal file
264
opencode/packages/opencode/test/tool/write.test.ts
Normal file
@@ -0,0 +1,264 @@
|
||||
import { describe, expect, test, beforeEach } from "bun:test"
|
||||
import path from "path"
|
||||
import { WriteTool } from "../../src/tool/write"
|
||||
import { Instance } from "../../src/project/instance"
|
||||
import { tmpdir } from "../fixture/fixture"
|
||||
import { PermissionNext } from "../../src/permission/next"
|
||||
import { Agent } from "../../src/agent/agent"
|
||||
import { TodoWriteTool, TodoReadTool } from "../../src/tool/todo"
|
||||
import { Todo } from "../../src/session/todo"
|
||||
|
||||
const ctx = {
|
||||
sessionID: "test",
|
||||
messageID: "",
|
||||
callID: "",
|
||||
agent: "build",
|
||||
abort: AbortSignal.any([]),
|
||||
messages: [],
|
||||
metadata: () => {},
|
||||
ask: async () => {},
|
||||
}
|
||||
|
||||
describe("tool.write", () => {
|
||||
test("creates new file", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const write = await WriteTool.init()
|
||||
const result = await write.execute(
|
||||
{ filePath: path.join(tmp.path, "new.txt"), content: "hello world" },
|
||||
ctx
|
||||
)
|
||||
expect(result.output).toContain("Wrote file successfully")
|
||||
|
||||
const file = Bun.file(path.join(tmp.path, "new.txt"))
|
||||
expect(await file.exists()).toBe(true)
|
||||
expect(await file.text()).toBe("hello world")
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("overwrites existing file", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
await Bun.write(path.join(dir, "existing.txt"), "old content")
|
||||
},
|
||||
})
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const write = await WriteTool.init()
|
||||
const result = await write.execute(
|
||||
{ filePath: path.join(tmp.path, "existing.txt"), content: "new content" },
|
||||
ctx
|
||||
)
|
||||
expect(result.output).toContain("Wrote file successfully")
|
||||
|
||||
const file = Bun.file(path.join(tmp.path, "existing.txt"))
|
||||
expect(await file.text()).toBe("new content")
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("handles nested directories", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const write = await WriteTool.init()
|
||||
const nestedPath = path.join(tmp.path, "deeply", "nested", "dir", "file.txt")
|
||||
await write.execute(
|
||||
{ filePath: nestedPath, content: "nested content" },
|
||||
ctx
|
||||
)
|
||||
|
||||
const file = Bun.file(nestedPath)
|
||||
expect(await file.exists()).toBe(true)
|
||||
expect(await file.text()).toBe("nested content")
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("sets metadata correctly", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
await Bun.write(path.join(dir, "existing.txt"), "old")
|
||||
},
|
||||
})
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const write = await WriteTool.init()
|
||||
const result = await write.execute(
|
||||
{ filePath: path.join(tmp.path, "existing.txt"), content: "new" },
|
||||
ctx
|
||||
)
|
||||
expect(result.metadata.exists).toBe(true)
|
||||
expect(result.metadata.filepath).toBe(path.join(tmp.path, "existing.txt"))
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("handles large files", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const largeContent = "x".repeat(100000)
|
||||
const write = await WriteTool.init()
|
||||
const result = await write.execute(
|
||||
{ filePath: path.join(tmp.path, "large.txt"), content: largeContent },
|
||||
ctx
|
||||
)
|
||||
expect(result.output).toContain("Wrote file successfully")
|
||||
|
||||
const file = Bun.file(path.join(tmp.path, "large.txt"))
|
||||
expect(await file.text()).toBe(largeContent)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("writes JSON content", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const jsonContent = JSON.stringify({ key: "value", nested: { a: 1 } }, null, 2)
|
||||
const write = await WriteTool.init()
|
||||
await write.execute(
|
||||
{ filePath: path.join(tmp.path, "data.json"), content: jsonContent },
|
||||
ctx
|
||||
)
|
||||
|
||||
const file = Bun.file(path.join(tmp.path, "data.json"))
|
||||
const parsed = JSON.parse(await file.text())
|
||||
expect(parsed.key).toBe("value")
|
||||
expect(parsed.nested.a).toBe(1)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("writes TypeScript content", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const tsContent = `export function greet(name: string): string {\n return \`Hello, \${name}!\`\n}`
|
||||
const write = await WriteTool.init()
|
||||
await write.execute(
|
||||
{ filePath: path.join(tmp.path, "greet.ts"), content: tsContent },
|
||||
ctx
|
||||
)
|
||||
|
||||
const file = Bun.file(path.join(tmp.path, "greet.ts"))
|
||||
expect(await file.text()).toBe(tsContent)
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("tool.todowrite", () => {
|
||||
beforeEach(async () => {
|
||||
await Todo.update({ sessionID: "test", todos: [] })
|
||||
})
|
||||
|
||||
test("creates todo list", async () => {
|
||||
const todos = [
|
||||
{ content: "Task 1", status: "pending", priority: "high" },
|
||||
{ content: "Task 2", status: "pending", priority: "medium" },
|
||||
]
|
||||
|
||||
const result = await TodoWriteTool.execute({ todos }, ctx)
|
||||
|
||||
expect(result.output).toContain("Task 1")
|
||||
expect(result.output).toContain("Task 2")
|
||||
expect(result.title).toBe("2 todos")
|
||||
})
|
||||
|
||||
test("updates existing todos", async () => {
|
||||
const initialTodos = [
|
||||
{ content: "Task 1", status: "pending", priority: "high" },
|
||||
]
|
||||
await TodoWriteTool.execute({ todos: initialTodos }, ctx)
|
||||
|
||||
const updatedTodos = [
|
||||
{ content: "Task 1", status: "completed", priority: "high" },
|
||||
{ content: "Task 2", status: "pending", priority: "medium" },
|
||||
]
|
||||
const result = await TodoWriteTool.execute({ todos: updatedTodos }, ctx)
|
||||
|
||||
expect(result.title).toBe("1 todos")
|
||||
})
|
||||
|
||||
test("handles empty todo list", async () => {
|
||||
const result = await TodoWriteTool.execute({ todos: [] }, ctx)
|
||||
|
||||
expect(result.title).toBe("0 todos")
|
||||
expect(result.output).toBe("[]")
|
||||
})
|
||||
|
||||
test("handles all priority levels", async () => {
|
||||
const todos = [
|
||||
{ content: "High priority", status: "pending", priority: "high" },
|
||||
{ content: "Medium priority", status: "pending", priority: "medium" },
|
||||
{ content: "Low priority", status: "pending", priority: "low" },
|
||||
]
|
||||
|
||||
const result = await TodoWriteTool.execute({ todos }, ctx)
|
||||
expect(result.metadata.todos.length).toBe(3)
|
||||
})
|
||||
|
||||
test("handles all status values", async () => {
|
||||
const todos = [
|
||||
{ content: "Pending task", status: "pending", priority: "high" },
|
||||
{ content: "In progress task", status: "in_progress", priority: "high" },
|
||||
{ content: "Completed task", status: "completed", priority: "high" },
|
||||
{ content: "Cancelled task", status: "cancelled", priority: "high" },
|
||||
]
|
||||
|
||||
const result = await TodoWriteTool.execute({ todos }, ctx)
|
||||
expect(result.metadata.todos.length).toBe(4)
|
||||
expect(result.title).toBe("3 todos")
|
||||
})
|
||||
})
|
||||
|
||||
describe("tool.todoread", () => {
|
||||
beforeEach(async () => {
|
||||
await Todo.update({ sessionID: "test", todos: [] })
|
||||
})
|
||||
|
||||
test("reads empty todo list", async () => {
|
||||
const result = await TodoReadTool.execute({}, ctx)
|
||||
|
||||
expect(result.output).toBe("[]")
|
||||
expect(result.title).toBe("0 todos")
|
||||
})
|
||||
|
||||
test("reads existing todos", async () => {
|
||||
const todos = [
|
||||
{ content: "Task 1", status: "pending", priority: "high" },
|
||||
{ content: "Task 2", status: "completed", priority: "medium" },
|
||||
]
|
||||
await TodoWriteTool.execute({ todos }, ctx)
|
||||
|
||||
const result = await TodoReadTool.execute({}, ctx)
|
||||
const parsed = JSON.parse(result.output)
|
||||
|
||||
expect(parsed.length).toBe(2)
|
||||
expect(parsed[0].content).toBe("Task 1")
|
||||
expect(parsed[1].status).toBe("completed")
|
||||
})
|
||||
|
||||
test("counts non-completed todos in title", async () => {
|
||||
const todos = [
|
||||
{ content: "Done", status: "completed", priority: "high" },
|
||||
{ content: "Done 2", status: "completed", priority: "high" },
|
||||
{ content: "Active", status: "pending", priority: "high" },
|
||||
]
|
||||
await TodoWriteTool.execute({ todos }, ctx)
|
||||
|
||||
const result = await TodoReadTool.execute({}, ctx)
|
||||
expect(result.title).toBe("1 todos")
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user