mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 13:44:32 +00:00
test: dedupe workspace path-resolution scenarios
This commit is contained in:
@@ -7,80 +7,40 @@ import { createOpenClawCodingTools } from "./pi-tools.js";
|
|||||||
import { expectReadWriteEditTools } from "./test-helpers/pi-tools-fs-helpers.js";
|
import { expectReadWriteEditTools } from "./test-helpers/pi-tools-fs-helpers.js";
|
||||||
|
|
||||||
describe("createOpenClawCodingTools", () => {
|
describe("createOpenClawCodingTools", () => {
|
||||||
it("uses workspaceDir for Read tool path resolution", async () => {
|
it("uses workspaceDir for read/write/edit path resolution", async () => {
|
||||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-ws-"));
|
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-ws-"));
|
||||||
try {
|
try {
|
||||||
// Create a test file in the "workspace"
|
|
||||||
const testFile = "test-workspace-file.txt";
|
|
||||||
const testContent = "workspace path resolution test";
|
|
||||||
await fs.writeFile(path.join(tmpDir, testFile), testContent, "utf8");
|
|
||||||
|
|
||||||
// Create tools with explicit workspaceDir
|
|
||||||
const tools = createOpenClawCodingTools({ workspaceDir: tmpDir });
|
const tools = createOpenClawCodingTools({ workspaceDir: tmpDir });
|
||||||
const readTool = tools.find((tool) => tool.name === "read");
|
const { readTool, writeTool, editTool } = expectReadWriteEditTools(tools);
|
||||||
expect(readTool).toBeDefined();
|
|
||||||
|
|
||||||
// Read using relative path - should resolve against workspaceDir
|
const readPath = "test-workspace-file.txt";
|
||||||
const result = await readTool?.execute("tool-ws-1", {
|
const readContent = "workspace path resolution test";
|
||||||
path: testFile,
|
await fs.writeFile(path.join(tmpDir, readPath), readContent, "utf8");
|
||||||
|
const readResult = await readTool?.execute("tool-ws-1", {
|
||||||
|
path: readPath,
|
||||||
});
|
});
|
||||||
|
const textBlocks = readResult?.content?.filter((block) => block.type === "text") as
|
||||||
const textBlocks = result?.content?.filter((block) => block.type === "text") as
|
|
||||||
| Array<{ text?: string }>
|
| Array<{ text?: string }>
|
||||||
| undefined;
|
| undefined;
|
||||||
const combinedText = textBlocks?.map((block) => block.text ?? "").join("\n");
|
const combinedText = textBlocks?.map((block) => block.text ?? "").join("\n");
|
||||||
expect(combinedText).toContain(testContent);
|
expect(combinedText).toContain(readContent);
|
||||||
} finally {
|
|
||||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
it("uses workspaceDir for Write tool path resolution", async () => {
|
|
||||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-ws-"));
|
|
||||||
try {
|
|
||||||
const testFile = "test-write-file.txt";
|
|
||||||
const testContent = "written via workspace path";
|
|
||||||
|
|
||||||
// Create tools with explicit workspaceDir
|
const writePath = "test-write-file.txt";
|
||||||
const tools = createOpenClawCodingTools({ workspaceDir: tmpDir });
|
const writeContent = "written via workspace path";
|
||||||
const writeTool = tools.find((tool) => tool.name === "write");
|
|
||||||
expect(writeTool).toBeDefined();
|
|
||||||
|
|
||||||
// Write using relative path - should resolve against workspaceDir
|
|
||||||
await writeTool?.execute("tool-ws-2", {
|
await writeTool?.execute("tool-ws-2", {
|
||||||
path: testFile,
|
path: writePath,
|
||||||
content: testContent,
|
content: writeContent,
|
||||||
});
|
});
|
||||||
|
expect(await fs.readFile(path.join(tmpDir, writePath), "utf8")).toBe(writeContent);
|
||||||
|
|
||||||
// Verify file was written to workspaceDir
|
const editPath = "test-edit-file.txt";
|
||||||
const written = await fs.readFile(path.join(tmpDir, testFile), "utf8");
|
await fs.writeFile(path.join(tmpDir, editPath), "hello world", "utf8");
|
||||||
expect(written).toBe(testContent);
|
|
||||||
} finally {
|
|
||||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
it("uses workspaceDir for Edit tool path resolution", async () => {
|
|
||||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-ws-"));
|
|
||||||
try {
|
|
||||||
const testFile = "test-edit-file.txt";
|
|
||||||
const originalContent = "hello world";
|
|
||||||
const expectedContent = "hello universe";
|
|
||||||
await fs.writeFile(path.join(tmpDir, testFile), originalContent, "utf8");
|
|
||||||
|
|
||||||
// Create tools with explicit workspaceDir
|
|
||||||
const tools = createOpenClawCodingTools({ workspaceDir: tmpDir });
|
|
||||||
const editTool = tools.find((tool) => tool.name === "edit");
|
|
||||||
expect(editTool).toBeDefined();
|
|
||||||
|
|
||||||
// Edit using relative path - should resolve against workspaceDir
|
|
||||||
await editTool?.execute("tool-ws-3", {
|
await editTool?.execute("tool-ws-3", {
|
||||||
path: testFile,
|
path: editPath,
|
||||||
oldText: "world",
|
oldText: "world",
|
||||||
newText: "universe",
|
newText: "universe",
|
||||||
});
|
});
|
||||||
|
expect(await fs.readFile(path.join(tmpDir, editPath), "utf8")).toBe("hello universe");
|
||||||
// Verify file was edited in workspaceDir
|
|
||||||
const edited = await fs.readFile(path.join(tmpDir, testFile), "utf8");
|
|
||||||
expect(edited).toBe(expectedContent);
|
|
||||||
} finally {
|
} finally {
|
||||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,74 +21,38 @@ async function withTempDir<T>(prefix: string, fn: (dir: string) => Promise<T>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("workspace path resolution", () => {
|
describe("workspace path resolution", () => {
|
||||||
it("reads relative paths against workspaceDir even after cwd changes", async () => {
|
it("resolves relative read/write/edit paths against workspaceDir even after cwd changes", async () => {
|
||||||
await withTempDir("openclaw-ws-", async (workspaceDir) => {
|
await withTempDir("openclaw-ws-", async (workspaceDir) => {
|
||||||
await withTempDir("openclaw-cwd-", async (otherDir) => {
|
await withTempDir("openclaw-cwd-", async (otherDir) => {
|
||||||
const testFile = "read.txt";
|
|
||||||
const contents = "workspace read ok";
|
|
||||||
await fs.writeFile(path.join(workspaceDir, testFile), contents, "utf8");
|
|
||||||
|
|
||||||
const cwdSpy = vi.spyOn(process, "cwd").mockReturnValue(otherDir);
|
const cwdSpy = vi.spyOn(process, "cwd").mockReturnValue(otherDir);
|
||||||
try {
|
try {
|
||||||
const tools = createOpenClawCodingTools({ workspaceDir });
|
const tools = createOpenClawCodingTools({ workspaceDir });
|
||||||
const readTool = tools.find((tool) => tool.name === "read");
|
const { readTool, writeTool, editTool } = expectReadWriteEditTools(tools);
|
||||||
expect(readTool).toBeDefined();
|
|
||||||
|
|
||||||
const result = await readTool?.execute("ws-read", { path: testFile });
|
const readFile = "read.txt";
|
||||||
expect(getTextContent(result)).toContain(contents);
|
await fs.writeFile(path.join(workspaceDir, readFile), "workspace read ok", "utf8");
|
||||||
} finally {
|
const readResult = await readTool.execute("ws-read", { path: readFile });
|
||||||
cwdSpy.mockRestore();
|
expect(getTextContent(readResult)).toContain("workspace read ok");
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("writes relative paths against workspaceDir even after cwd changes", async () => {
|
const writeFile = "write.txt";
|
||||||
await withTempDir("openclaw-ws-", async (workspaceDir) => {
|
await writeTool.execute("ws-write", {
|
||||||
await withTempDir("openclaw-cwd-", async (otherDir) => {
|
path: writeFile,
|
||||||
const testFile = "write.txt";
|
content: "workspace write ok",
|
||||||
const contents = "workspace write ok";
|
|
||||||
|
|
||||||
const cwdSpy = vi.spyOn(process, "cwd").mockReturnValue(otherDir);
|
|
||||||
try {
|
|
||||||
const tools = createOpenClawCodingTools({ workspaceDir });
|
|
||||||
const writeTool = tools.find((tool) => tool.name === "write");
|
|
||||||
expect(writeTool).toBeDefined();
|
|
||||||
|
|
||||||
await writeTool?.execute("ws-write", {
|
|
||||||
path: testFile,
|
|
||||||
content: contents,
|
|
||||||
});
|
});
|
||||||
|
expect(await fs.readFile(path.join(workspaceDir, writeFile), "utf8")).toBe(
|
||||||
|
"workspace write ok",
|
||||||
|
);
|
||||||
|
|
||||||
const written = await fs.readFile(path.join(workspaceDir, testFile), "utf8");
|
const editFile = "edit.txt";
|
||||||
expect(written).toBe(contents);
|
await fs.writeFile(path.join(workspaceDir, editFile), "hello world", "utf8");
|
||||||
} finally {
|
await editTool.execute("ws-edit", {
|
||||||
cwdSpy.mockRestore();
|
path: editFile,
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("edits relative paths against workspaceDir even after cwd changes", async () => {
|
|
||||||
await withTempDir("openclaw-ws-", async (workspaceDir) => {
|
|
||||||
await withTempDir("openclaw-cwd-", async (otherDir) => {
|
|
||||||
const testFile = "edit.txt";
|
|
||||||
await fs.writeFile(path.join(workspaceDir, testFile), "hello world", "utf8");
|
|
||||||
|
|
||||||
const cwdSpy = vi.spyOn(process, "cwd").mockReturnValue(otherDir);
|
|
||||||
try {
|
|
||||||
const tools = createOpenClawCodingTools({ workspaceDir });
|
|
||||||
const editTool = tools.find((tool) => tool.name === "edit");
|
|
||||||
expect(editTool).toBeDefined();
|
|
||||||
|
|
||||||
await editTool?.execute("ws-edit", {
|
|
||||||
path: testFile,
|
|
||||||
oldText: "world",
|
oldText: "world",
|
||||||
newText: "openclaw",
|
newText: "openclaw",
|
||||||
});
|
});
|
||||||
|
expect(await fs.readFile(path.join(workspaceDir, editFile), "utf8")).toBe(
|
||||||
const updated = await fs.readFile(path.join(workspaceDir, testFile), "utf8");
|
"hello openclaw",
|
||||||
expect(updated).toBe("hello openclaw");
|
);
|
||||||
} finally {
|
} finally {
|
||||||
cwdSpy.mockRestore();
|
cwdSpy.mockRestore();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user