test: 添加 Utils 纯函数单元测试 (测试计划 02)

覆盖 xml, hash, stringUtils, semver, uuid, format, frontmatterParser,
file, glob, diff 共 10 个模块的纯函数测试。
json.ts 因模块加载链路过重暂跳过。
共 190 个测试用例(含已有 array/set)全部通过。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
claude-code-best
2026-04-01 22:03:02 +08:00
parent 67baea3c7f
commit cad6409bfe
10 changed files with 935 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
import { describe, expect, test } from "bun:test";
import {
convertLeadingTabsToSpaces,
addLineNumbers,
stripLineNumberPrefix,
pathsEqual,
normalizePathForComparison,
} from "../file";
describe("convertLeadingTabsToSpaces", () => {
test("converts leading tabs to 2 spaces each", () => {
expect(convertLeadingTabsToSpaces("\t\thello")).toBe(" hello");
});
test("only converts leading tabs", () => {
expect(convertLeadingTabsToSpaces("\thello\tworld")).toBe(" hello\tworld");
});
test("returns unchanged if no tabs", () => {
expect(convertLeadingTabsToSpaces("no tabs")).toBe("no tabs");
});
test("handles empty string", () => {
expect(convertLeadingTabsToSpaces("")).toBe("");
});
test("handles multiline content", () => {
const input = "\tline1\n\t\tline2\nline3";
const expected = " line1\n line2\nline3";
expect(convertLeadingTabsToSpaces(input)).toBe(expected);
});
});
describe("addLineNumbers", () => {
test("adds line numbers starting from 1", () => {
const result = addLineNumbers({ content: "a\nb\nc", startLine: 1 });
expect(result).toContain("1");
expect(result).toContain("a");
expect(result).toContain("b");
expect(result).toContain("c");
});
test("returns empty string for empty content", () => {
expect(addLineNumbers({ content: "", startLine: 1 })).toBe("");
});
test("respects startLine offset", () => {
const result = addLineNumbers({ content: "hello", startLine: 10 });
expect(result).toContain("10");
});
});
describe("stripLineNumberPrefix", () => {
test("strips arrow-separated prefix", () => {
expect(stripLineNumberPrefix(" 1→content")).toBe("content");
});
test("strips tab-separated prefix", () => {
expect(stripLineNumberPrefix("1\tcontent")).toBe("content");
});
test("returns line unchanged if no prefix", () => {
expect(stripLineNumberPrefix("no prefix")).toBe("no prefix");
});
test("handles large line numbers", () => {
expect(stripLineNumberPrefix("123456→content")).toBe("content");
});
});
describe("normalizePathForComparison", () => {
test("normalizes redundant separators", () => {
const result = normalizePathForComparison("/a//b/c");
expect(result).toBe("/a/b/c");
});
test("resolves dot segments", () => {
const result = normalizePathForComparison("/a/./b/../c");
expect(result).toBe("/a/c");
});
});
describe("pathsEqual", () => {
test("returns true for identical paths", () => {
expect(pathsEqual("/a/b/c", "/a/b/c")).toBe(true);
});
test("returns true for equivalent paths with dot segments", () => {
expect(pathsEqual("/a/./b", "/a/b")).toBe(true);
});
test("returns false for different paths", () => {
expect(pathsEqual("/a/b", "/a/c")).toBe(false);
});
});