mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-31 06:42:03 +00:00
Added extensive test coverage for previously untested files: Platform package (94.69% coverage, +47 tests): - paths.test.ts: 22 tests for path construction and directory creation - security.test.ts: 25 tests for path validation and security Utils package (94.3% coverage, +109 tests): - logger.test.ts: 23 tests for logging with levels - fs-utils.test.ts: 20 tests for safe file operations - conversation-utils.test.ts: 24 tests for message formatting - image-handler.test.ts: 25 tests for image processing - prompt-builder.test.ts: 17 tests for prompt construction Coverage improvements: - Platform: 63.71% → 94.69% stmts, 40% → 97.14% funcs - Utils: 19.51% → 94.3% stmts, 18.51% → 100% funcs Updated thresholds to enforce high quality: - Platform: 90% lines/stmts, 95% funcs, 75% branches - Utils: 90% lines/stmts, 95% funcs, 85% branches Total new tests: 156 (platform: 47, utils: 109) All tests passing with new coverage thresholds. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
255 lines
7.2 KiB
TypeScript
255 lines
7.2 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
import fs from "fs/promises";
|
|
import path from "path";
|
|
import os from "os";
|
|
import { mkdirSafe, existsSafe } from "../src/fs-utils";
|
|
|
|
describe("fs-utils.ts", () => {
|
|
let tempDir: string;
|
|
|
|
beforeEach(async () => {
|
|
// Create a temporary directory for testing
|
|
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "fs-utils-test-"));
|
|
});
|
|
|
|
afterEach(async () => {
|
|
// Clean up temporary directory
|
|
try {
|
|
await fs.rm(tempDir, { recursive: true, force: true });
|
|
} catch (error) {
|
|
// Ignore cleanup errors
|
|
}
|
|
});
|
|
|
|
describe("mkdirSafe", () => {
|
|
it("should create a new directory", async () => {
|
|
const newDir = path.join(tempDir, "new-directory");
|
|
|
|
await mkdirSafe(newDir);
|
|
|
|
const stats = await fs.stat(newDir);
|
|
expect(stats.isDirectory()).toBe(true);
|
|
});
|
|
|
|
it("should create nested directories recursively", async () => {
|
|
const nestedDir = path.join(tempDir, "level1", "level2", "level3");
|
|
|
|
await mkdirSafe(nestedDir);
|
|
|
|
const stats = await fs.stat(nestedDir);
|
|
expect(stats.isDirectory()).toBe(true);
|
|
});
|
|
|
|
it("should succeed when directory already exists", async () => {
|
|
const existingDir = path.join(tempDir, "existing");
|
|
await fs.mkdir(existingDir);
|
|
|
|
await expect(mkdirSafe(existingDir)).resolves.not.toThrow();
|
|
});
|
|
|
|
it("should succeed when path is a symlink to a directory", async () => {
|
|
const targetDir = path.join(tempDir, "target");
|
|
const symlinkPath = path.join(tempDir, "symlink");
|
|
|
|
await fs.mkdir(targetDir);
|
|
await fs.symlink(targetDir, symlinkPath, "dir");
|
|
|
|
await expect(mkdirSafe(symlinkPath)).resolves.not.toThrow();
|
|
});
|
|
|
|
it("should throw when path exists as a file", async () => {
|
|
const filePath = path.join(tempDir, "existing-file.txt");
|
|
await fs.writeFile(filePath, "content");
|
|
|
|
await expect(mkdirSafe(filePath)).rejects.toThrow(
|
|
"Path exists and is not a directory"
|
|
);
|
|
});
|
|
|
|
it("should resolve relative paths", async () => {
|
|
const originalCwd = process.cwd();
|
|
try {
|
|
process.chdir(tempDir);
|
|
|
|
await mkdirSafe("relative-dir");
|
|
|
|
const stats = await fs.stat(path.join(tempDir, "relative-dir"));
|
|
expect(stats.isDirectory()).toBe(true);
|
|
} finally {
|
|
process.chdir(originalCwd);
|
|
}
|
|
});
|
|
|
|
it("should handle concurrent creation gracefully", async () => {
|
|
const newDir = path.join(tempDir, "concurrent");
|
|
|
|
const promises = [
|
|
mkdirSafe(newDir),
|
|
mkdirSafe(newDir),
|
|
mkdirSafe(newDir),
|
|
];
|
|
|
|
await expect(Promise.all(promises)).resolves.not.toThrow();
|
|
|
|
const stats = await fs.stat(newDir);
|
|
expect(stats.isDirectory()).toBe(true);
|
|
});
|
|
|
|
it("should handle paths with special characters", async () => {
|
|
const specialDir = path.join(tempDir, "dir with spaces & special-chars");
|
|
|
|
await mkdirSafe(specialDir);
|
|
|
|
const stats = await fs.stat(specialDir);
|
|
expect(stats.isDirectory()).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("existsSafe", () => {
|
|
it("should return true for existing directory", async () => {
|
|
const existingDir = path.join(tempDir, "exists");
|
|
await fs.mkdir(existingDir);
|
|
|
|
const result = await existsSafe(existingDir);
|
|
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it("should return true for existing file", async () => {
|
|
const filePath = path.join(tempDir, "file.txt");
|
|
await fs.writeFile(filePath, "content");
|
|
|
|
const result = await existsSafe(filePath);
|
|
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it("should return false for non-existent path", async () => {
|
|
const nonExistent = path.join(tempDir, "does-not-exist");
|
|
|
|
const result = await existsSafe(nonExistent);
|
|
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
it("should return true for symlink", async () => {
|
|
const target = path.join(tempDir, "target.txt");
|
|
const symlink = path.join(tempDir, "link.txt");
|
|
|
|
await fs.writeFile(target, "content");
|
|
await fs.symlink(target, symlink);
|
|
|
|
const result = await existsSafe(symlink);
|
|
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it("should return true for broken symlink", async () => {
|
|
const symlink = path.join(tempDir, "broken-link");
|
|
|
|
// Create symlink to non-existent target
|
|
await fs.symlink("/non/existent/path", symlink);
|
|
|
|
const result = await existsSafe(symlink);
|
|
|
|
// lstat succeeds on broken symlinks
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it("should handle relative paths", async () => {
|
|
const originalCwd = process.cwd();
|
|
try {
|
|
process.chdir(tempDir);
|
|
|
|
await fs.writeFile("test.txt", "content");
|
|
|
|
const result = await existsSafe("test.txt");
|
|
|
|
expect(result).toBe(true);
|
|
} finally {
|
|
process.chdir(originalCwd);
|
|
}
|
|
});
|
|
|
|
it("should handle paths with special characters", async () => {
|
|
const specialFile = path.join(tempDir, "file with spaces & chars.txt");
|
|
await fs.writeFile(specialFile, "content");
|
|
|
|
const result = await existsSafe(specialFile);
|
|
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it("should return false for parent of non-existent nested path", async () => {
|
|
const nonExistent = path.join(tempDir, "does", "not", "exist");
|
|
|
|
const result = await existsSafe(nonExistent);
|
|
|
|
expect(result).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("Error handling", () => {
|
|
it("should handle permission errors in mkdirSafe", async () => {
|
|
// Skip on Windows where permissions work differently
|
|
if (process.platform === "win32") {
|
|
return;
|
|
}
|
|
|
|
const restrictedDir = path.join(tempDir, "restricted");
|
|
await fs.mkdir(restrictedDir);
|
|
|
|
// Make directory read-only
|
|
await fs.chmod(restrictedDir, 0o444);
|
|
|
|
const newDir = path.join(restrictedDir, "new");
|
|
|
|
try {
|
|
await expect(mkdirSafe(newDir)).rejects.toThrow();
|
|
} finally {
|
|
// Restore permissions for cleanup
|
|
await fs.chmod(restrictedDir, 0o755);
|
|
}
|
|
});
|
|
|
|
it("should propagate unexpected errors in existsSafe", async () => {
|
|
const mockError = new Error("Unexpected error");
|
|
(mockError as any).code = "EACCES";
|
|
|
|
const spy = vi.spyOn(fs, "lstat").mockRejectedValueOnce(mockError);
|
|
|
|
await expect(existsSafe("/some/path")).rejects.toThrow(
|
|
"Unexpected error"
|
|
);
|
|
|
|
spy.mockRestore();
|
|
});
|
|
});
|
|
|
|
describe("Integration scenarios", () => {
|
|
it("should work together: check existence then create if missing", async () => {
|
|
const dirPath = path.join(tempDir, "check-then-create");
|
|
|
|
const existsBefore = await existsSafe(dirPath);
|
|
expect(existsBefore).toBe(false);
|
|
|
|
await mkdirSafe(dirPath);
|
|
|
|
const existsAfter = await existsSafe(dirPath);
|
|
expect(existsAfter).toBe(true);
|
|
});
|
|
|
|
it("should handle nested directory creation with existence checks", async () => {
|
|
const level1 = path.join(tempDir, "level1");
|
|
const level2 = path.join(level1, "level2");
|
|
const level3 = path.join(level2, "level3");
|
|
|
|
await mkdirSafe(level3);
|
|
|
|
expect(await existsSafe(level1)).toBe(true);
|
|
expect(await existsSafe(level2)).toBe(true);
|
|
expect(await existsSafe(level3)).toBe(true);
|
|
});
|
|
});
|
|
});
|