Files
oh-my-pi/packages/coding-agent/test/tools/bash-normalize.test.ts
T
can1357 db48d3270f fix(coding-agent/tools): fixed heredocs by preserving internal spacing in bash normalization
- Removed aggressive whitespace normalization that was breaking heredocs and indentation-sensitive scripts.
- Preserved internal spacing and tabs in bash command normalization to support heredocs and indentation-sensitive scripts.
- Added test cases for internal spacing preservation and heredoc indentation handling.
2026-02-13 18:49:38 +01:00

130 lines
4.2 KiB
TypeScript

import { describe, expect, it } from "bun:test";
import { applyHeadTail, normalizeBashCommand } from "../../src/tools/bash-normalize";
describe("normalizeBashCommand", () => {
describe("head/tail extraction", () => {
it("extracts | head -n N", () => {
const result = normalizeBashCommand("ls -la | head -n 50");
expect(result.command).toBe("ls -la");
expect(result.headLines).toBe(50);
expect(result.tailLines).toBeUndefined();
});
it("extracts | head -N (short form)", () => {
const result = normalizeBashCommand("cat file.txt | head -20");
expect(result.command).toBe("cat file.txt");
expect(result.headLines).toBe(20);
});
it("extracts | tail -n N", () => {
const result = normalizeBashCommand("dmesg | tail -n 100");
expect(result.command).toBe("dmesg");
expect(result.tailLines).toBe(100);
expect(result.headLines).toBeUndefined();
});
it("extracts | tail -N (short form)", () => {
const result = normalizeBashCommand("journalctl | tail -50");
expect(result.command).toBe("journalctl");
expect(result.tailLines).toBe(50);
});
it("handles multiple spaces around pipe", () => {
const result = normalizeBashCommand("git log | head -n 10");
expect(result.command).toBe("git log");
expect(result.headLines).toBe(10);
});
it("does not extract head/tail in middle of pipeline", () => {
const result = normalizeBashCommand("cat file | head -n 10 | grep foo");
expect(result.command).toBe("cat file | head -n 10 | grep foo");
expect(result.headLines).toBeUndefined();
expect(result.tailLines).toBeUndefined();
});
it("does not extract head without line count", () => {
const result = normalizeBashCommand("cat file | head");
expect(result.command).toBe("cat file | head");
expect(result.headLines).toBeUndefined();
});
it("does not extract head with other flags", () => {
const result = normalizeBashCommand("cat file | head -c 100");
expect(result.command).toBe("cat file | head -c 100");
expect(result.headLines).toBeUndefined();
});
});
describe("no patterns", () => {
it("preserves command unchanged", () => {
const result = normalizeBashCommand("git status");
expect(result.command).toBe("git status");
expect(result.headLines).toBeUndefined();
expect(result.tailLines).toBeUndefined();
});
it("preserves internal spacing and tabs", () => {
const result = normalizeBashCommand("echo 'a b\t\tc'");
expect(result.command).toBe("echo 'a b\t\tc'");
});
it("preserves heredoc indentation", () => {
const command = "python3 - <<'PY'\nfor i in [1]:\n if True:\n x = 1\nPY";
const result = normalizeBashCommand(command);
expect(result.command).toBe(command);
});
});
});
describe("applyHeadTail", () => {
const sampleText = "line1\nline2\nline3\nline4\nline5";
it("returns original when no limits", () => {
const result = applyHeadTail(sampleText);
expect(result.text).toBe(sampleText);
expect(result.applied).toBe(false);
});
it("applies head limit", () => {
const result = applyHeadTail(sampleText, 2);
expect(result.text).toBe("line1\nline2");
expect(result.applied).toBe(true);
expect(result.headApplied).toBe(2);
});
it("applies tail limit", () => {
const result = applyHeadTail(sampleText, undefined, 2);
expect(result.text).toBe("line4\nline5");
expect(result.applied).toBe(true);
expect(result.tailApplied).toBe(2);
});
it("applies head then tail", () => {
const result = applyHeadTail(sampleText, 4, 2);
// head=4 gives: line1\nline2\nline3\nline4
// tail=2 of that gives: line3\nline4
expect(result.text).toBe("line3\nline4");
expect(result.applied).toBe(true);
expect(result.headApplied).toBe(4);
expect(result.tailApplied).toBe(2);
});
it("does not apply if text is shorter than limit", () => {
const result = applyHeadTail(sampleText, 10);
expect(result.text).toBe(sampleText);
expect(result.applied).toBe(false);
});
it("handles empty text", () => {
const result = applyHeadTail("", 5);
expect(result.text).toBe("");
expect(result.applied).toBe(false);
});
it("handles single line", () => {
const result = applyHeadTail("single", 1);
expect(result.text).toBe("single");
expect(result.applied).toBe(false);
});
});