diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a1d0f880..0870d8df4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -102,12 +102,18 @@ jobs: - name: Test store path separator handling run: go test -timeout=5m -count=1 ./internal/graphpath + # The same asymmetry reaches the other direction too: a test that spells + # an expected path with '/' passes on POSIX whatever the code does, and + # only this runner can tell whether the value under test is a native + # filesystem path (filepath.Join / filepath.Clean) or a '/'-keyed store + # path. ParseDiffGitPaths, ParseDiffLinesNewSide and FeedbackDir all + # assert on native paths, so they belong here rather than nowhere. - name: Test native-separator store path comparisons run: > go test -timeout=10m -count=1 - -run 'NativeSeparator|MixedSeparator|ImportAdjacency' + -run 'NativeSeparator|MixedSeparator|ImportAdjacency|ParseDiffGitPaths|ParseDiffLinesNewSide|FeedbackDir' ./internal/analysis ./internal/graph/store_sqlite - ./internal/mcp ./internal/resolver + ./internal/mcp ./internal/resolver ./internal/persistence build-linux-static: # The linux release ships a statically linked binary so it runs on any diff --git a/internal/analysis/diffmap_test.go b/internal/analysis/diffmap_test.go index 32a77a632..bcf2cb4da 100644 --- a/internal/analysis/diffmap_test.go +++ b/internal/analysis/diffmap_test.go @@ -55,10 +55,16 @@ func TestParseDiffHunksEqualsInternal(t *testing.T) { } } +// diffKey spells a repo-relative path the way parseDiffLines keys its map and +// DiffHunk.FilePath is cleaned: filepath.Clean, so the key carries the running +// platform's separators. Writing the '/' form directly reads fine on POSIX and +// misses on Windows, where the map key is `pkg\foo.go`. +func diffKey(p string) string { return filepath.Clean(p) } + func TestParseDiffLinesNewSide(t *testing.T) { lines := parseDiffLines(sampleDiff) - foo := lines["pkg/foo.go"] + foo := lines[diffKey("pkg/foo.go")] if len(foo) == 0 { t.Fatalf("expected new-side lines for pkg/foo.go") } @@ -86,7 +92,7 @@ func TestParseDiffLinesNewSide(t *testing.T) { } // New-file lines all carry "+", numbered 1..3. - baz := lines["pkg/baz.go"] + baz := lines[diffKey("pkg/baz.go")] if len(baz) != 3 { t.Fatalf("expected 3 new-side lines for pkg/baz.go, got %d (%#v)", len(baz), baz) } @@ -682,8 +688,14 @@ func TestParseDiffGitPaths(t *testing.T) { {`diff --git "a/od\td.go" "b/od\td.go"`, ""}, {"diff --git nonsense", ""}, } { - if got := parseDiffGitPaths(tc.line); got != tc.want { - t.Fatalf("parseDiffGitPaths(%q) = %q, want %q", tc.line, got, tc.want) + // The recovered path is cleaned, so it carries native separators; + // the '/' spelling above is the diff's, not the result's. + want := tc.want + if want != "" { + want = filepath.Clean(want) + } + if got := parseDiffGitPaths(tc.line); got != want { + t.Fatalf("parseDiffGitPaths(%q) = %q, want %q", tc.line, got, want) } } } diff --git a/internal/persistence/feedback_test.go b/internal/persistence/feedback_test.go index 02a139b07..478a509ee 100644 --- a/internal/persistence/feedback_test.go +++ b/internal/persistence/feedback_test.go @@ -1,6 +1,7 @@ package persistence import ( + "path/filepath" "testing" "time" @@ -102,5 +103,8 @@ func TestRepoCacheKey_DifferentRepos(t *testing.T) { func TestFeedbackDir(t *testing.T) { dir := FeedbackDir("/home/user/.cache/gortex", "/tmp/my-repo") assert.Contains(t, dir, "_latest") - assert.Contains(t, dir, ".cache/gortex") + // FeedbackDir filepath.Joins, so the result carries native separators and + // feeds os.Open directly. The '/' spelling is the caller's input, not the + // result's: on Windows this reads `\home\user\.cache\gortex\`. + assert.Contains(t, dir, filepath.Join(".cache", "gortex")) }