check-safety/changedlines_test.go
Alex Dunmow c4d01de82c feat: concise output + diff-scoped any check
Reporter is now a collector: checks declare a verdict (OK/Skip/Warn/Fail/
Fatal) plus findings, and a single central render() prints output. Default
output is silent on pass/skip — only FAIL/WARN/ERR checks print, followed by
one tally line, so a clean run is two lines. --verbose restores full per-check
output. All ~30 checks were converted to this API; orphaned guidance/label
helpers (printPerTargetOKLines, per-check *Help blocks, colors_format.go) were
removed.

The any-usage check (2e) now defaults to only the unstaged working-tree diff
(changed lines), via a new per-repo git-diff index in changedlines.go; --all-any
restores the full scan. Not-a-git-repo / no-diff warns on nothing.

Golden fixtures regenerated; integration tests updated to the new format; added
unit tests for the diff index.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 01:16:56 +08:00

103 lines
2.9 KiB
Go

package main
import (
"os"
"os/exec"
"path/filepath"
"testing"
)
func TestParseHunkNewRange(t *testing.T) {
cases := []struct {
header string
wantStart int
wantCount int
}{
{"@@ -1,2 +3,4 @@", 3, 4},
{"@@ -0,0 +1 @@", 1, 1}, // no ,count on the + side → count 1
{"@@ -5,0 +6,3 @@ func Foo() {", 6, 3}, // trailing context after @@
{"@@ -1 +1 @@", 1, 1},
{"not a hunk", 0, 0},
}
for _, c := range cases {
start, count := parseHunkNewRange(c.header)
if start != c.wantStart || count != c.wantCount {
t.Errorf("parseHunkNewRange(%q) = (%d,%d), want (%d,%d)", c.header, start, count, c.wantStart, c.wantCount)
}
}
}
func TestParseUnifiedDiffRecordsAddedLines(t *testing.T) {
diff := "diff --git a/foo.go b/foo.go\n" +
"--- a/foo.go\n" +
"+++ b/foo.go\n" +
"@@ -10,0 +11,2 @@\n" +
"+added one\n" +
"+added two\n"
rd := &repoDiff{changed: map[string]map[int]bool{}, untracked: map[string]bool{}}
parseUnifiedDiff(diff, rd)
lines := rd.changed["foo.go"]
if !lines[11] || !lines[12] {
t.Fatalf("expected lines 11,12 changed, got %#v", lines)
}
if lines[10] || lines[13] {
t.Fatalf("unexpected extra changed lines: %#v", lines)
}
}
func TestDiffIndexIsChangedTracksWorkingTreeEdits(t *testing.T) {
repo := t.TempDir()
runGit := func(args ...string) {
t.Helper()
cmd := exec.Command("git", append([]string{"-C", repo}, args...)...)
if out, err := cmd.CombinedOutput(); err != nil {
t.Fatalf("git %v: %v\n%s", args, err, out)
}
}
runGit("init")
runGit("config", "user.email", "test@example.com")
runGit("config", "user.name", "test")
committed := filepath.Join(repo, "committed.go")
if err := os.WriteFile(committed, []byte("package p\n\nvar a int\nvar b int\n"), 0o644); err != nil {
t.Fatal(err)
}
runGit("add", "committed.go")
runGit("commit", "-m", "init")
// Unstaged edit: append a line to the committed file.
if err := os.WriteFile(committed, []byte("package p\n\nvar a int\nvar b int\nvar c int\n"), 0o644); err != nil {
t.Fatal(err)
}
// Untracked new file.
untracked := filepath.Join(repo, "new.go")
if err := os.WriteFile(untracked, []byte("package p\n\nvar d int\n"), 0o644); err != nil {
t.Fatal(err)
}
idx := newDiffIndex()
if idx.isChanged(committed, 3) {
t.Errorf("line 3 (unchanged, committed) should not be reported as changed")
}
if !idx.isChanged(committed, 5) {
t.Errorf("line 5 (the unstaged append) should be reported as changed")
}
if !idx.isChanged(untracked, 1) || !idx.isChanged(untracked, 3) {
t.Errorf("all lines of an untracked file should be reported as changed")
}
}
func TestDiffIndexIsChangedOutsideRepoIsFalse(t *testing.T) {
dir := t.TempDir() // not a git repo
f := filepath.Join(dir, "x.go")
if err := os.WriteFile(f, []byte("package p\n"), 0o644); err != nil {
t.Fatal(err)
}
idx := newDiffIndex()
if idx.isChanged(f, 1) {
t.Errorf("files outside any git repo must not be reported as changed")
}
}