Test plan for verifying the correctness and effectiveness of the hashline plugin
integration with OpenCode. Covers 31 scenarios across 8 test files.
A. Basic Edit Operations (6 scenarios)
#
Scenario
Operation
Expected Result
Verified
A1
Replace single line
SWAP 2.=2: with 1 body line
Line 2 replaced, others unchanged
✅
A2
Replace multiple lines
SWAP 2.=4: with 3 body lines
Lines 2-4 replaced by 3 lines
✅
A3
Delete line range
DEL 3.=5
Lines 3-5 deleted, no body
✅
A4
Insert before anchor
INS.PRE 3: with body
Body inserted before line 3
✅
A5
Insert after anchor
INS.POST 2: with body
Body inserted after line 2
✅
A6
Insert head and tail
INS.HEAD: + INS.TAIL:
Lines inserted at file start and end
✅
B. Tag Validation & Security (5 scenarios)
#
Scenario
Operation
Expected Result
Verified
B1
Correct tag
read → edit with returned tag
Edit succeeds, new tag returned
✅
B2
Stale tag
read → external modification → edit with old tag
MismatchError, re-read prompt
✅
B3
Fabricated tag
Edit with random 4-hex tag
Rejected: hash not from this session
✅
B4
Chained edits
edit → use returned new tag → edit again
Second edit succeeds
✅
B5
Missing tag
[foo.ts] without #TAG suffix
Rejected: missing snapshot tag
✅
C. Read Hook Injection (2 scenarios)
#
Scenario
Operation
Expected Result
Verified
C1
Normal file read
Read an existing file
Output has [path#XXXX] header
✅
C2
Non-existent file
Read a missing path
No tag injected
✅
D. Multi-hunk & Multi-file (3 scenarios)
#
Scenario
Operation
Expected Result
Verified
D1
Single file, multiple hunks
3 non-adjacent hunks in one section
All applied using original line numbers
✅
D2
Multiple file sections
2 [path#TAG] sections for different files
Both files edited, all-or-nothing
✅
D3
Same-path merge
Consecutive sections targeting same file
Merged into one section
✅
E. Error Handling (6 scenarios)
#
Scenario
Operation
Expected Result
Verified
E1
Line out of bounds
SWAP 100.=200: (file has 5 lines)
Error: line does not exist
✅
E2
Empty insert body
INS.POST 3: with no body
Error: empty insert
✅
E3
Delete with body
DEL 3.=5 followed by +text
Error: delete takes no body
✅
E4
Minus rows rejected
Body contains -old content
Error: minus row rejected
✅
E5
Unified diff contamination
First line @@ -1,3 +1,3 @@
Error: unified-diff hunk header
✅
E6
apply_patch contamination
*** Update File:foo.ts
Error or auto-strip
✅
F. Recovery & Drift (3 scenarios)
#
Scenario
Operation
Expected Result
Verified
F1
External write recovery
read → external change → edit unchanged line
3-way merge succeeds, warning emitted
✅
F2
Unrecoverable drift
read → external rewrite → edit missing anchor
MismatchError, re-read prompt
✅
F3
Head/tail + stale tag
read → external change → INS.HEAD: / INS.TAIL:
Succeeds with drift warning
✅
G. Line Endings & Encoding (3 scenarios)
#
Scenario
Operation
Expected Result
Verified
G1
CRLF file preserve
Read CRLF file → edit
CRLF preserved after edit
✅
G2
BOM file preserve
Read UTF-8 BOM file → edit
BOM preserved after edit
✅
G3
Trailing newline handling
File with trailing \n → delete last content line
Only content line deleted, format preserved
✅
H. Real-world Workflows (3 scenarios)
#
Scenario
Operation
Expected Result
Verified
H1
Chained refactoring
read → edit → edit → edit (3 rounds)
Each round tag refreshes, lines correct
✅
H2
Concurrent conflict
Agent A read → Agent B edit → Agent A edit
Agent A rejected, re-read prompt
✅
H3
Multi-file batch
One patch with 3 file sections
All succeed or all fail (atomic)
✅
Test File
Scenarios
Focus
tests/core-patch.test.ts
A1-A6, D1-D3, E1-E6
Core patch operations, multi-hunk, error handling
tests/core-tag.test.ts
B1-B5
Tag validation and security
tests/core-recovery.test.ts
F1-F3
3-way merge recovery from file drift
tests/core-format.test.ts
G1-G3
Line endings, BOM, encoding
tests/hook-read.test.ts
C1-C2
Read output snapshot injection
tests/tool-edit.test.ts
B1, B2, B4, E1-E6
Edit tool integration via ToolContext
tests/workflow.test.ts
H1-H3
End-to-end agent workflows