mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 14:25:51 +00:00
test: Phase 2-4 — 添加 12 个测试文件 (+321 tests, 968 total)
Phase 2 (轻 Mock): envUtils, sleep/sequential, memoize, groupToolUses, dangerousPatterns, outputLimits Phase 3 (补全): zodToJsonSchema, PermissionMode, envValidation Phase 4 (工具模块): mcpStringUtils, destructiveCommandWarning, commandSemantics Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
162
src/utils/permissions/__tests__/PermissionMode.test.ts
Normal file
162
src/utils/permissions/__tests__/PermissionMode.test.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
import { mock, describe, expect, test } from "bun:test";
|
||||
|
||||
// Mock slowOperations to cut bootstrap/state dependency chain
|
||||
// (figures.js → env.js → fsOperations.js → slowOperations.js → bootstrap/state.js)
|
||||
mock.module("src/utils/slowOperations.ts", () => ({
|
||||
jsonStringify: JSON.stringify,
|
||||
jsonParse: JSON.parse,
|
||||
slowLogging: { enabled: false },
|
||||
clone: (v: any) => structuredClone(v),
|
||||
cloneDeep: (v: any) => structuredClone(v),
|
||||
callerFrame: () => "",
|
||||
SLOW_OPERATION_THRESHOLD_MS: 100,
|
||||
writeFileSync_DEPRECATED: () => {},
|
||||
}));
|
||||
mock.module("src/utils/log.ts", () => ({
|
||||
logError: () => {},
|
||||
logToFile: () => {},
|
||||
getLogDisplayTitle: () => "",
|
||||
logEvent: () => {},
|
||||
}));
|
||||
|
||||
const {
|
||||
isExternalPermissionMode,
|
||||
toExternalPermissionMode,
|
||||
permissionModeFromString,
|
||||
permissionModeTitle,
|
||||
isDefaultMode,
|
||||
permissionModeShortTitle,
|
||||
permissionModeSymbol,
|
||||
getModeColor,
|
||||
PERMISSION_MODES,
|
||||
EXTERNAL_PERMISSION_MODES,
|
||||
} = await import("../PermissionMode");
|
||||
|
||||
// ─── PERMISSION_MODES / EXTERNAL_PERMISSION_MODES ──────────────────────
|
||||
|
||||
describe("PERMISSION_MODES", () => {
|
||||
test("includes all external modes", () => {
|
||||
for (const m of EXTERNAL_PERMISSION_MODES) {
|
||||
expect(PERMISSION_MODES).toContain(m);
|
||||
}
|
||||
});
|
||||
|
||||
test("includes default, plan, acceptEdits, bypassPermissions, dontAsk", () => {
|
||||
expect(PERMISSION_MODES).toContain("default");
|
||||
expect(PERMISSION_MODES).toContain("plan");
|
||||
expect(PERMISSION_MODES).toContain("acceptEdits");
|
||||
expect(PERMISSION_MODES).toContain("bypassPermissions");
|
||||
expect(PERMISSION_MODES).toContain("dontAsk");
|
||||
});
|
||||
});
|
||||
|
||||
// ─── permissionModeFromString ──────────────────────────────────────────
|
||||
|
||||
describe("permissionModeFromString", () => {
|
||||
test("returns valid mode for known string", () => {
|
||||
expect(permissionModeFromString("plan")).toBe("plan");
|
||||
expect(permissionModeFromString("default")).toBe("default");
|
||||
expect(permissionModeFromString("dontAsk")).toBe("dontAsk");
|
||||
});
|
||||
|
||||
test("returns 'default' for unknown string", () => {
|
||||
expect(permissionModeFromString("unknown")).toBe("default");
|
||||
expect(permissionModeFromString("")).toBe("default");
|
||||
});
|
||||
});
|
||||
|
||||
// ─── permissionModeTitle ───────────────────────────────────────────────
|
||||
|
||||
describe("permissionModeTitle", () => {
|
||||
test("returns title for known modes", () => {
|
||||
expect(permissionModeTitle("default")).toBe("Default");
|
||||
expect(permissionModeTitle("plan")).toBe("Plan Mode");
|
||||
expect(permissionModeTitle("acceptEdits")).toBe("Accept edits");
|
||||
});
|
||||
|
||||
test("falls back to Default for unknown mode", () => {
|
||||
expect(permissionModeTitle("nonexistent" as any)).toBe("Default");
|
||||
});
|
||||
});
|
||||
|
||||
// ─── permissionModeShortTitle ──────────────────────────────────────────
|
||||
|
||||
describe("permissionModeShortTitle", () => {
|
||||
test("returns short title for known modes", () => {
|
||||
expect(permissionModeShortTitle("default")).toBe("Default");
|
||||
expect(permissionModeShortTitle("plan")).toBe("Plan");
|
||||
expect(permissionModeShortTitle("bypassPermissions")).toBe("Bypass");
|
||||
});
|
||||
});
|
||||
|
||||
// ─── permissionModeSymbol ──────────────────────────────────────────────
|
||||
|
||||
describe("permissionModeSymbol", () => {
|
||||
test("returns empty string for default", () => {
|
||||
expect(permissionModeSymbol("default")).toBe("");
|
||||
});
|
||||
|
||||
test("returns non-empty for non-default modes", () => {
|
||||
expect(permissionModeSymbol("plan").length).toBeGreaterThan(0);
|
||||
expect(permissionModeSymbol("acceptEdits").length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
// ─── getModeColor ──────────────────────────────────────────────────────
|
||||
|
||||
describe("getModeColor", () => {
|
||||
test("returns 'text' for default", () => {
|
||||
expect(getModeColor("default")).toBe("text");
|
||||
});
|
||||
|
||||
test("returns 'planMode' for plan", () => {
|
||||
expect(getModeColor("plan")).toBe("planMode");
|
||||
});
|
||||
|
||||
test("returns 'error' for bypassPermissions", () => {
|
||||
expect(getModeColor("bypassPermissions")).toBe("error");
|
||||
});
|
||||
});
|
||||
|
||||
// ─── isDefaultMode ─────────────────────────────────────────────────────
|
||||
|
||||
describe("isDefaultMode", () => {
|
||||
test("returns true for 'default'", () => {
|
||||
expect(isDefaultMode("default")).toBe(true);
|
||||
});
|
||||
|
||||
test("returns true for undefined", () => {
|
||||
expect(isDefaultMode(undefined)).toBe(true);
|
||||
});
|
||||
|
||||
test("returns false for other modes", () => {
|
||||
expect(isDefaultMode("plan")).toBe(false);
|
||||
expect(isDefaultMode("dontAsk")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
// ─── toExternalPermissionMode ──────────────────────────────────────────
|
||||
|
||||
describe("toExternalPermissionMode", () => {
|
||||
test("maps default to default", () => {
|
||||
expect(toExternalPermissionMode("default")).toBe("default");
|
||||
});
|
||||
|
||||
test("maps plan to plan", () => {
|
||||
expect(toExternalPermissionMode("plan")).toBe("plan");
|
||||
});
|
||||
|
||||
test("maps dontAsk to dontAsk", () => {
|
||||
expect(toExternalPermissionMode("dontAsk")).toBe("dontAsk");
|
||||
});
|
||||
});
|
||||
|
||||
// ─── isExternalPermissionMode ──────────────────────────────────────────
|
||||
|
||||
describe("isExternalPermissionMode", () => {
|
||||
test("returns true for external modes (non-ant)", () => {
|
||||
// USER_TYPE is not 'ant' in tests, so always true
|
||||
expect(isExternalPermissionMode("default")).toBe(true);
|
||||
expect(isExternalPermissionMode("plan")).toBe(true);
|
||||
});
|
||||
});
|
||||
55
src/utils/permissions/__tests__/dangerousPatterns.test.ts
Normal file
55
src/utils/permissions/__tests__/dangerousPatterns.test.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import {
|
||||
CROSS_PLATFORM_CODE_EXEC,
|
||||
DANGEROUS_BASH_PATTERNS,
|
||||
} from "../dangerousPatterns";
|
||||
|
||||
describe("CROSS_PLATFORM_CODE_EXEC", () => {
|
||||
test("is a non-empty readonly array of strings", () => {
|
||||
expect(CROSS_PLATFORM_CODE_EXEC.length).toBeGreaterThan(0);
|
||||
for (const p of CROSS_PLATFORM_CODE_EXEC) {
|
||||
expect(typeof p).toBe("string");
|
||||
}
|
||||
});
|
||||
|
||||
test("includes core interpreters", () => {
|
||||
expect(CROSS_PLATFORM_CODE_EXEC).toContain("python");
|
||||
expect(CROSS_PLATFORM_CODE_EXEC).toContain("node");
|
||||
expect(CROSS_PLATFORM_CODE_EXEC).toContain("ruby");
|
||||
expect(CROSS_PLATFORM_CODE_EXEC).toContain("perl");
|
||||
});
|
||||
|
||||
test("includes package runners", () => {
|
||||
expect(CROSS_PLATFORM_CODE_EXEC).toContain("npx");
|
||||
expect(CROSS_PLATFORM_CODE_EXEC).toContain("bunx");
|
||||
});
|
||||
|
||||
test("includes shells", () => {
|
||||
expect(CROSS_PLATFORM_CODE_EXEC).toContain("bash");
|
||||
expect(CROSS_PLATFORM_CODE_EXEC).toContain("sh");
|
||||
});
|
||||
});
|
||||
|
||||
describe("DANGEROUS_BASH_PATTERNS", () => {
|
||||
test("includes all cross-platform patterns", () => {
|
||||
for (const p of CROSS_PLATFORM_CODE_EXEC) {
|
||||
expect(DANGEROUS_BASH_PATTERNS).toContain(p);
|
||||
}
|
||||
});
|
||||
|
||||
test("includes unix-specific patterns", () => {
|
||||
expect(DANGEROUS_BASH_PATTERNS).toContain("zsh");
|
||||
expect(DANGEROUS_BASH_PATTERNS).toContain("fish");
|
||||
expect(DANGEROUS_BASH_PATTERNS).toContain("eval");
|
||||
expect(DANGEROUS_BASH_PATTERNS).toContain("exec");
|
||||
expect(DANGEROUS_BASH_PATTERNS).toContain("sudo");
|
||||
expect(DANGEROUS_BASH_PATTERNS).toContain("xargs");
|
||||
expect(DANGEROUS_BASH_PATTERNS).toContain("env");
|
||||
});
|
||||
|
||||
test("all elements are strings", () => {
|
||||
for (const p of DANGEROUS_BASH_PATTERNS) {
|
||||
expect(typeof p).toBe("string");
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user