package gitea import ( "testing" ) func TestBuildPositionToLineMap_SingleHunk(t *testing.T) { // @@ -16,4 +16,5 @@ ← position 1 // context ← position 2, new line 16 //-deleted ← position 3, no new line //+added ← position 4, new line 17 // context ← position 5, new line 18 diff := `diff --git a/file.go b/file.go index abc..def 100644 --- a/file.go +++ b/file.go @@ -16,4 +16,5 @@ func example() { context line -deleted line +added line context after ` pm := BuildPositionToLineMap(diff) tests := []struct { pos int wantLine int }{ {2, 16}, // context line -> new line 16 {4, 17}, // added line -> new line 17 {5, 18}, // context after -> new line 18 } for _, tt := range tests { got, err := pm.Translate("file.go", tt.pos) if err != nil { t.Errorf("Translate(file.go, %d): unexpected error: %v", tt.pos, err) continue } if got != tt.wantLine { t.Errorf("Translate(file.go, %d) = %d, want %d", tt.pos, got, tt.wantLine) } } } func TestBuildPositionToLineMap_MultipleHunks(t *testing.T) { diff := `diff --git a/file.go b/file.go --- a/file.go +++ b/file.go @@ -1,3 +1,3 @@ package main line1 -old +new @@ -10,3 +10,4 @@ func foo() { func foo() { + // added return } ` pm := BuildPositionToLineMap(diff) tests := []struct { pos int wantLine int }{ // First hunk: @@ is pos 1 {2, 1}, // " line1" -> new line 1 {4, 2}, // "+new" -> new line 2 // Second hunk: @@ is pos 5 (continues from 4) // Wait: first hunk has pos 1(@@ hdr), 2(" line1"), 3("-old"), 4("+new") // Second hunk @@ is pos 5 {6, 10}, // " func foo() {" -> new line 10 {7, 11}, // "+\t// added" -> new line 11 {8, 12}, // " \treturn" -> new line 12 {9, 13}, // " }" -> new line 13 } for _, tt := range tests { got, err := pm.Translate("file.go", tt.pos) if err != nil { t.Errorf("Translate(file.go, %d): unexpected error: %v", tt.pos, err) continue } if got != tt.wantLine { t.Errorf("Translate(file.go, %d) = %d, want %d", tt.pos, got, tt.wantLine) } } } func TestBuildPositionToLineMap_DeletionTargeted(t *testing.T) { diff := `diff --git a/file.go b/file.go --- a/file.go +++ b/file.go @@ -1,4 +1,3 @@ package main line1 -deleted line3 ` pm := BuildPositionToLineMap(diff) // Position 3 is the deletion line "-deleted" — should map to nearest below // Position 4 is " line3" which is new line 2 got, err := pm.Translate("file.go", 3) if err != nil { t.Fatalf("Translate(file.go, 3): unexpected error: %v", err) } if got != 2 { t.Errorf("Translate(file.go, 3) = %d, want 2 (nearest non-deletion below)", got) } } func TestBuildPositionToLineMap_DeletionAtEnd(t *testing.T) { // If a deletion line is at the end with no subsequent non-deletion line, error diff := `diff --git a/file.go b/file.go --- a/file.go +++ b/file.go @@ -1,3 +1,2 @@ package main line1 line2 -deleted at end ` pm := BuildPositionToLineMap(diff) _, err := pm.Translate("file.go", 4) if err == nil { t.Error("expected error for deletion at end with no subsequent line") } } func TestBuildPositionToLineMap_NewFile(t *testing.T) { diff := `diff --git a/new.go b/new.go new file mode 100644 --- /dev/null +++ b/new.go @@ -0,0 +1,3 @@ +package main + +func init() {} ` pm := BuildPositionToLineMap(diff) tests := []struct { pos int wantLine int }{ {2, 1}, // "+package main" -> line 1 {3, 2}, // "+" (empty line) -> line 2 {4, 3}, // "+func init() {}" -> line 3 } for _, tt := range tests { got, err := pm.Translate("new.go", tt.pos) if err != nil { t.Errorf("Translate(new.go, %d): unexpected error: %v", tt.pos, err) continue } if got != tt.wantLine { t.Errorf("Translate(new.go, %d) = %d, want %d", tt.pos, got, tt.wantLine) } } } func TestBuildPositionToLineMap_DeletedFile(t *testing.T) { diff := `diff --git a/old.go b/old.go deleted file mode 100644 --- a/old.go +++ /dev/null @@ -1,3 +0,0 @@ -package main - -func old() {} ` pm := BuildPositionToLineMap(diff) // Deleted file has no new-file lines; positions should error _, err := pm.Translate("old.go", 2) if err == nil { t.Error("expected error for deleted file position") } } func TestBuildPositionToLineMap_BinaryFile(t *testing.T) { diff := `diff --git a/image.png b/image.png Binary files /dev/null and b/image.png differ diff --git a/code.go b/code.go --- a/code.go +++ b/code.go @@ -1,2 +1,3 @@ package main +// added func main() {} ` pm := BuildPositionToLineMap(diff) // Binary file should not be in the map _, err := pm.Translate("image.png", 1) if err == nil { t.Error("expected error for binary file") } // code.go should still work got, err := pm.Translate("code.go", 3) if err != nil { t.Fatalf("Translate(code.go, 3): unexpected error: %v", err) } if got != 2 { t.Errorf("Translate(code.go, 3) = %d, want 2", got) } } func TestBuildPositionToLineMap_OutOfRange(t *testing.T) { diff := `diff --git a/file.go b/file.go --- a/file.go +++ b/file.go @@ -1,2 +1,2 @@ line1 -old +new ` pm := BuildPositionToLineMap(diff) // Position 0 is invalid _, err := pm.Translate("file.go", 0) if err == nil { t.Error("expected error for position 0") } // Position 5 is out of range (only positions 1-4 exist) _, err = pm.Translate("file.go", 5) if err == nil { t.Error("expected error for position 5 (out of range)") } // Unknown file _, err = pm.Translate("unknown.go", 1) if err == nil { t.Error("expected error for unknown file") } } func TestBuildPositionToLineMap_MultipleFiles(t *testing.T) { diff := `diff --git a/a.go b/a.go --- a/a.go +++ b/a.go @@ -1,2 +1,3 @@ package a +// file a func aFunc() {} diff --git a/b.go b/b.go --- a/b.go +++ b/b.go @@ -1,2 +1,3 @@ package b +// file b func bFunc() {} ` pm := BuildPositionToLineMap(diff) // a.go: pos 3 is "+// file a" -> new line 2 got, err := pm.Translate("a.go", 3) if err != nil { t.Fatalf("Translate(a.go, 3): %v", err) } if got != 2 { t.Errorf("Translate(a.go, 3) = %d, want 2", got) } // b.go: pos 3 is "+// file b" -> new line 2 // Note: position resets per file got, err = pm.Translate("b.go", 3) if err != nil { t.Fatalf("Translate(b.go, 3): %v", err) } if got != 2 { t.Errorf("Translate(b.go, 3) = %d, want 2", got) } } func TestTranslate_HunkHeaderPosition_SingleHunk(t *testing.T) { // Position 1 is the @@ hunk-header line. // It should resolve to the first context/addition line below (new line 16). diff := `diff --git a/file.go b/file.go index abc..def 100644 --- a/file.go +++ b/file.go @@ -16,4 +16,5 @@ func example() { context line -deleted line +added line context after ` pm := BuildPositionToLineMap(diff) got, err := pm.Translate("file.go", 1) if err != nil { t.Fatalf("Translate(file.go, 1): unexpected error: %v", err) } if got != 16 { t.Errorf("Translate(file.go, 1) = %d, want 16 (first context/addition line in hunk)", got) } } func TestTranslate_HunkHeaderPosition_MultiHunk(t *testing.T) { // First hunk: @@ is pos 1, then " line1" (pos 2), "-old" (pos 3), "+new" (pos 4) // Second hunk: @@ is pos 5, then " func foo() {" (pos 6), "+// added" (pos 7), etc. // Translating position 5 (second @@) should resolve to new line 10. diff := `diff --git a/file.go b/file.go --- a/file.go +++ b/file.go @@ -1,3 +1,3 @@ package main line1 -old +new @@ -10,3 +10,4 @@ func foo() { func foo() { + // added return } ` pm := BuildPositionToLineMap(diff) // Position 5 is the second @@ hunk-header — should resolve to new line 10 got, err := pm.Translate("file.go", 5) if err != nil { t.Fatalf("Translate(file.go, 5): unexpected error: %v", err) } if got != 10 { t.Errorf("Translate(file.go, 5) = %d, want 10 (first context/addition line in second hunk)", got) } // Also verify first hunk header at position 1 resolves to new line 1 got, err = pm.Translate("file.go", 1) if err != nil { t.Fatalf("Translate(file.go, 1): unexpected error: %v", err) } if got != 1 { t.Errorf("Translate(file.go, 1) = %d, want 1 (first context/addition line in first hunk)", got) } } func TestTranslate_HunkHeaderPosition_NewFile(t *testing.T) { // New file: @@ -0,0 +1,3 @@ is position 1. // Should resolve to new line 1 (the first addition). diff := `diff --git a/new.go b/new.go new file mode 100644 --- /dev/null +++ b/new.go @@ -0,0 +1,3 @@ +package main + +func init() {} ` pm := BuildPositionToLineMap(diff) got, err := pm.Translate("new.go", 1) if err != nil { t.Fatalf("Translate(new.go, 1): unexpected error: %v", err) } if got != 1 { t.Errorf("Translate(new.go, 1) = %d, want 1 (first addition line)", got) } }