Files
oh-my-opencode/src/tools/hashline-edit/edit-operations.test.ts
T
YeonGyu-Kim 0832505e13 fix(hashline-edit): do not restore indentation for replace_lines
- applyReplaceLines: use stripped array directly instead of restoreLeadingIndent
- applySetLine: keep restoreLeadingIndent (1:1 replacement needs indent preservation)
- Added test case for replace_lines preserving new line indentation
- All 3025 tests pass

🤖 Generated with OhMyOpenCode assistance
2026-02-20 17:47:37 +09:00

142 lines
3.9 KiB
TypeScript

import { describe, expect, it } from "bun:test"
import { applyHashlineEdits, applyInsertAfter, applyReplace, applyReplaceLines, applySetLine } from "./edit-operations"
import { computeLineHash } from "./hash-computation"
import type { HashlineEdit } from "./types"
function anchorFor(lines: string[], line: number): string {
return `${line}#${computeLineHash(line, lines[line - 1])}`
}
describe("hashline edit operations", () => {
it("applies set_line with LINE#ID anchor", () => {
//#given
const lines = ["line 1", "line 2", "line 3"]
//#when
const result = applySetLine(lines, anchorFor(lines, 2), "new line 2")
//#then
expect(result).toEqual(["line 1", "new line 2", "line 3"])
})
it("applies replace_lines with LINE#ID anchors", () => {
//#given
const lines = ["line 1", "line 2", "line 3", "line 4"]
//#when
const result = applyReplaceLines(lines, anchorFor(lines, 2), anchorFor(lines, 3), "replaced")
//#then
expect(result).toEqual(["line 1", "replaced", "line 4"])
})
it("applies insert_after with LINE#ID anchor", () => {
//#given
const lines = ["line 1", "line 2", "line 3"]
//#when
const result = applyInsertAfter(lines, anchorFor(lines, 2), "inserted")
//#then
expect(result).toEqual(["line 1", "line 2", "inserted", "line 3"])
})
it("applies replace operation", () => {
//#given
const content = "hello world foo"
//#when
const result = applyReplace(content, "world", "universe")
//#then
expect(result).toEqual("hello universe foo")
})
it("applies mixed edits in one pass", () => {
//#given
const content = "line 1\nline 2\nline 3"
const lines = content.split("\n")
const edits: HashlineEdit[] = [
{ type: "insert_after", line: anchorFor(lines, 1), text: "inserted" },
{ type: "set_line", line: anchorFor(lines, 3), text: "modified" },
]
//#when
const result = applyHashlineEdits(content, edits)
//#then
expect(result).toEqual("line 1\ninserted\nline 2\nmodified")
})
it("keeps literal backslash-n in plain string text", () => {
//#given
const lines = ["line 1", "line 2", "line 3"]
//#when
const result = applySetLine(lines, anchorFor(lines, 2), "join(\\n)")
//#then
expect(result).toEqual(["line 1", "join(\\n)", "line 3"])
})
it("strips copied hashline prefixes from multiline text", () => {
//#given
const lines = ["line 1", "line 2", "line 3"]
//#when
const result = applySetLine(lines, anchorFor(lines, 2), "1#VK:first\n2#NP:second")
//#then
expect(result).toEqual(["line 1", "first", "second", "line 3"])
})
it("autocorrects anchor echo for insert_after payload", () => {
//#given
const lines = ["line 1", "line 2"]
//#when
const result = applyInsertAfter(lines, anchorFor(lines, 1), ["line 1", "inserted"])
//#then
expect(result).toEqual(["line 1", "inserted", "line 2"])
})
it("restores indentation for paired single-line replacement", () => {
//#given
const lines = ["if (x) {", " return 1", "}"]
//#when
const result = applySetLine(lines, anchorFor(lines, 2), "return 2")
//#then
expect(result).toEqual(["if (x) {", " return 2", "}"])
})
it("strips boundary echo around replace_lines content", () => {
//#given
const lines = ["before", "old 1", "old 2", "after"]
//#when
const result = applyReplaceLines(
lines,
anchorFor(lines, 2),
anchorFor(lines, 3),
["before", "new 1", "new 2", "after"]
)
//#then
expect(result).toEqual(["before", "new 1", "new 2", "after"])
})
it("does not restore indentation for replace_lines", () => {
//#given
const lines = ["if (x) {", " return 1", " return 2", "}"]
//#when
const result = applyReplaceLines(lines, anchorFor(lines, 2), anchorFor(lines, 3), ["return 3", "return 4"])
//#then
expect(result).toEqual(["if (x) {", "return 3", "return 4", "}"])
})
})