2026-02-16 15:59:12 +09:00
|
|
|
import { describe, it, expect } from "bun:test"
|
2026-02-19 18:19:16 +09:00
|
|
|
import { computeLineHash } from "./hash-computation"
|
2026-02-16 15:59:12 +09:00
|
|
|
import { parseLineRef, validateLineRef } from "./validation"
|
|
|
|
|
|
|
|
|
|
describe("parseLineRef", () => {
|
2026-02-20 11:02:07 +09:00
|
|
|
it("parses valid LINE#ID reference", () => {
|
2026-02-16 15:59:12 +09:00
|
|
|
//#given
|
2026-02-20 11:02:07 +09:00
|
|
|
const ref = "42#VK"
|
2026-02-16 15:59:12 +09:00
|
|
|
|
|
|
|
|
//#when
|
|
|
|
|
const result = parseLineRef(ref)
|
|
|
|
|
|
|
|
|
|
//#then
|
2026-02-20 11:02:07 +09:00
|
|
|
expect(result).toEqual({ line: 42, hash: "VK" })
|
2026-02-16 15:59:12 +09:00
|
|
|
})
|
|
|
|
|
|
2026-02-20 11:02:07 +09:00
|
|
|
it("throws on invalid format", () => {
|
2026-02-16 15:59:12 +09:00
|
|
|
//#given
|
2026-02-20 11:02:07 +09:00
|
|
|
const ref = "42:VK"
|
2026-02-16 15:59:12 +09:00
|
|
|
|
2026-02-20 11:02:07 +09:00
|
|
|
//#when / #then
|
|
|
|
|
expect(() => parseLineRef(ref)).toThrow("LINE#ID")
|
2026-02-16 15:59:12 +09:00
|
|
|
})
|
|
|
|
|
|
2026-02-20 11:02:07 +09:00
|
|
|
it("accepts refs copied with markers and trailing content", () => {
|
2026-02-16 15:59:12 +09:00
|
|
|
//#given
|
2026-02-20 11:02:07 +09:00
|
|
|
const ref = ">>> 42#VK:const value = 1"
|
2026-02-16 15:59:12 +09:00
|
|
|
|
2026-02-20 11:02:07 +09:00
|
|
|
//#when
|
|
|
|
|
const result = parseLineRef(ref)
|
2026-02-16 15:59:12 +09:00
|
|
|
|
2026-02-20 11:02:07 +09:00
|
|
|
//#then
|
|
|
|
|
expect(result).toEqual({ line: 42, hash: "VK" })
|
2026-02-16 15:59:12 +09:00
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
describe("validateLineRef", () => {
|
2026-02-20 11:02:07 +09:00
|
|
|
it("accepts matching reference", () => {
|
2026-02-16 15:59:12 +09:00
|
|
|
//#given
|
|
|
|
|
const lines = ["function hello() {", " return 42", "}"]
|
2026-02-20 11:02:07 +09:00
|
|
|
const hash = computeLineHash(1, lines[0])
|
2026-02-16 15:59:12 +09:00
|
|
|
|
2026-02-20 11:02:07 +09:00
|
|
|
//#when / #then
|
|
|
|
|
expect(() => validateLineRef(lines, `1#${hash}`)).not.toThrow()
|
2026-02-16 15:59:12 +09:00
|
|
|
})
|
|
|
|
|
|
2026-02-20 11:02:07 +09:00
|
|
|
it("throws on mismatch and includes current hash", () => {
|
2026-02-16 15:59:12 +09:00
|
|
|
//#given
|
|
|
|
|
const lines = ["function hello() {"]
|
|
|
|
|
|
2026-02-20 11:02:07 +09:00
|
|
|
//#when / #then
|
|
|
|
|
expect(() => validateLineRef(lines, "1#ZZ")).toThrow(/current hash/)
|
2026-02-16 15:59:12 +09:00
|
|
|
})
|
|
|
|
|
})
|
2026-02-21 05:59:30 +09:00
|
|
|
|
|
|
|
|
describe("legacy LINE:HEX backward compatibility", () => {
|
|
|
|
|
it("parses legacy LINE:HEX ref", () => {
|
|
|
|
|
//#given
|
|
|
|
|
const ref = "42:ab"
|
|
|
|
|
|
|
|
|
|
//#when
|
|
|
|
|
const result = parseLineRef(ref)
|
|
|
|
|
|
|
|
|
|
//#then
|
|
|
|
|
expect(result).toEqual({ line: 42, hash: "ab" })
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it("parses legacy LINE:HEX ref with uppercase hex", () => {
|
|
|
|
|
//#given
|
|
|
|
|
const ref = "10:FF"
|
|
|
|
|
|
|
|
|
|
//#when
|
|
|
|
|
const result = parseLineRef(ref)
|
|
|
|
|
|
|
|
|
|
//#then
|
|
|
|
|
expect(result).toEqual({ line: 10, hash: "FF" })
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it("legacy ref fails validation with hash mismatch, not parse error", () => {
|
|
|
|
|
//#given
|
|
|
|
|
const lines = ["function hello() {"]
|
|
|
|
|
|
|
|
|
|
//#when / #then
|
|
|
|
|
expect(() => validateLineRef(lines, "1:ab")).toThrow(/Hash mismatch|current hash/)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it("extracts legacy ref from content with markers", () => {
|
|
|
|
|
//#given
|
|
|
|
|
const ref = ">>> 42:ab|const x = 1"
|
|
|
|
|
|
|
|
|
|
//#when
|
|
|
|
|
const result = parseLineRef(ref)
|
|
|
|
|
|
|
|
|
|
//#then
|
|
|
|
|
expect(result).toEqual({ line: 42, hash: "ab" })
|
|
|
|
|
})
|
|
|
|
|
})
|