import { describe, expect, test } from "bun:test"; import { truncatePathMiddle, truncateToWidth, truncateStartToWidth, truncateToWidthNoEllipsis, truncate, wrapText, } from "../truncate"; // ─── truncateToWidth ──────────────────────────────────────────────────── describe("truncateToWidth", () => { test("returns original when within limit", () => { expect(truncateToWidth("hello", 10)).toBe("hello"); }); test("truncates long string with ellipsis", () => { const result = truncateToWidth("hello world", 8); expect(result).toBe("hello w…"); }); test("returns ellipsis for maxWidth 1", () => { expect(truncateToWidth("hello", 1)).toBe("…"); }); test("handles empty string", () => { expect(truncateToWidth("", 10)).toBe(""); }); // ── CJK / wide-character tests ── test("truncates CJK string at width boundary (2 per char)", () => { expect(truncateToWidth("你好世界", 4)).toBe("你…"); }); test("truncates CJK string preserving full characters", () => { expect(truncateToWidth("你好世界", 6)).toBe("你好…"); }); test("passes through CJK string when within limit", () => { expect(truncateToWidth("你好", 4)).toBe("你好"); }); test("handles mixed ASCII + CJK", () => { expect(truncateToWidth("hello你好", 8)).toBe("hello你…"); }); test("passes through mixed ASCII + CJK at exact limit", () => { expect(truncateToWidth("hello你好", 9)).toBe("hello你好"); }); test("truncates string containing emoji", () => { const result = truncateToWidth("hello 👋 world", 10); expect(result).toBe("hello 👋 …"); }); test("passes through single emoji at sufficient width", () => { expect(truncateToWidth("👋", 2)).toBe("👋"); }); }); // ─── truncateStartToWidth ─────────────────────────────────────────────── describe("truncateStartToWidth", () => { test("returns original when within limit", () => { expect(truncateStartToWidth("hello", 10)).toBe("hello"); }); test("truncates from start with ellipsis prefix", () => { expect(truncateStartToWidth("hello world", 8)).toBe("…o world"); }); test("returns ellipsis for maxWidth 1", () => { expect(truncateStartToWidth("hello", 1)).toBe("…"); }); test("truncates CJK from start", () => { expect(truncateStartToWidth("你好世界", 4)).toBe("…界"); }); test("truncates CJK from start preserving characters", () => { expect(truncateStartToWidth("你好世界", 6)).toBe("…世界"); }); }); // ─── truncateToWidthNoEllipsis ────────────────────────────────────────── describe("truncateToWidthNoEllipsis", () => { test("returns original when within limit", () => { expect(truncateToWidthNoEllipsis("hello", 10)).toBe("hello"); }); test("truncates without ellipsis", () => { const result = truncateToWidthNoEllipsis("hello world", 5); expect(result).toBe("hello"); expect(result.includes("…")).toBe(false); }); test("returns empty for maxWidth 0", () => { expect(truncateToWidthNoEllipsis("hello", 0)).toBe(""); }); test("truncates CJK without ellipsis", () => { expect(truncateToWidthNoEllipsis("你好世界", 4)).toBe("你好"); }); }); // ─── truncatePathMiddle ───────────────────────────────────────────────── describe("truncatePathMiddle", () => { test("returns original when path fits", () => { expect(truncatePathMiddle("src/index.ts", 50)).toBe("src/index.ts"); }); test("truncates middle of long path", () => { const path = "src/components/deeply/nested/folder/MyComponent.tsx"; const result = truncatePathMiddle(path, 30); expect(result).toContain("…"); expect(result.endsWith("MyComponent.tsx")).toBe(true); }); test("returns ellipsis for maxLength 0", () => { expect(truncatePathMiddle("src/index.ts", 0)).toBe("…"); }); test("handles path without slashes", () => { const result = truncatePathMiddle("verylongfilename.ts", 10); expect(result).toContain("…"); }); test("handles short maxLength < 5", () => { expect(truncatePathMiddle("src/components/foo.ts", 4)).toBe("src…"); }); test("handles very short maxLength 1", () => { expect(truncatePathMiddle("/a/b", 1)).toBe("…"); }); }); // ─── truncate ─────────────────────────────────────────────────────────── describe("truncate", () => { test("returns original when within limit", () => { expect(truncate("hello", 10)).toBe("hello"); }); test("truncates long string", () => { const result = truncate("hello world foo bar", 10); expect(result).toContain("…"); }); test("truncates at newline in singleLine mode", () => { const result = truncate("first line\nsecond line", 50, true); expect(result).toBe("first line…"); }); test("does not truncate at newline when singleLine is false", () => { const result = truncate("first\nsecond", 50, false); expect(result).toBe("first\nsecond"); }); test("truncates singleLine when first line exceeds maxWidth", () => { const result = truncate("a very long first line\nsecond", 10, true); expect(result).toContain("…"); expect(result).not.toContain("\n"); }); }); // ─── wrapText ─────────────────────────────────────────────────────────── describe("wrapText", () => { test("wraps text at specified width", () => { const result = wrapText("hello world", 6); expect(result.length).toBeGreaterThan(1); }); test("returns single line when text fits", () => { expect(wrapText("hello", 10)).toEqual(["hello"]); }); test("handles empty string", () => { expect(wrapText("", 10)).toEqual([]); }); test("wraps each character on width 1", () => { const result = wrapText("abc", 1); expect(result).toEqual(["a", "b", "c"]); }); });