Files
zzet--gortex/internal/indexer/multi_case_identity_test.go
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

115 lines
3.6 KiB
Go

package indexer
import (
"context"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zzet/gortex/internal/config"
"github.com/zzet/gortex/internal/pathkey"
)
// forceCaseInsensitive flips the process-global pathkey.CaseInsensitivePaths
// for the test and restores it afterwards. Tests using it must not run in
// parallel because the flag is process-global.
func forceCaseInsensitive(t *testing.T, v bool) {
t.Helper()
prev := pathkey.CaseInsensitivePaths
pathkey.CaseInsensitivePaths = v
t.Cleanup(func() { pathkey.CaseInsensitivePaths = prev })
}
// caseVariantOf returns p with the case of its final path component
// toggled, so it names the same directory on a case-insensitive
// filesystem while differing byte-wise.
func caseVariantOf(p string) string {
return filepath.Join(filepath.Dir(p), swapCaseASCII(filepath.Base(p)))
}
func swapCaseASCII(s string) string {
b := []byte(s)
for i := range b {
switch {
case b[i] >= 'a' && b[i] <= 'z':
b[i] -= 32
case b[i] >= 'A' && b[i] <= 'Z':
b[i] += 32
}
}
return string(b)
}
// Tracking a case-only variant of an already-tracked directory must be a
// no-op: no second entry, the repo count stays 1, and the daemon stays in
// single-repo (unprefixed) mode. This is the #270 macOS regression.
func TestTrackRepoCtx_CaseVariantIsNoOp(t *testing.T) {
forceCaseInsensitive(t, true)
mi, dir := indexSingleRepoForTest(t)
require.False(t, mi.IsMultiRepo())
variant := caseVariantOf(dir)
if _, err := os.Stat(variant); err != nil {
t.Skipf("host filesystem is case-sensitive; %q does not resolve", variant)
}
res, err := mi.TrackRepoCtx(context.Background(), config.RepoEntry{Path: variant})
require.NoError(t, err)
require.Nil(t, res, "tracking a case variant of an already-tracked dir must be a no-op")
assert.Len(t, mi.AllMetadata(), 1, "repo count must stay 1")
assert.False(t, mi.IsMultiRepo(), "mode must stay single-repo")
}
// ScopeForCWD is pure string folding (no stat), so a case-mismatched cwd
// resolves to the tracked repo on any platform once folding is forced on.
// This is the #277 Windows 0-tools scenario at the workspace layer.
func TestScopeForCWD_CaseMismatchedCwd(t *testing.T) {
forceCaseInsensitive(t, true)
mi, dir := indexSingleRepoForTest(t)
variant := caseVariantOf(dir)
_, _, prefix, ok := mi.ScopeForCWD(variant)
require.True(t, ok, "case-variant cwd must resolve to the tracked repo")
assert.Equal(t, "myrepo", prefix)
// A sub-path with mismatched case resolves too.
_, _, prefix, ok = mi.ScopeForCWD(filepath.Join(variant, "pkg", "file.go"))
require.True(t, ok)
assert.Equal(t, "myrepo", prefix)
}
// ScopeForCWD must NOT resolve a genuinely unrelated cwd.
func TestScopeForCWD_UnrelatedCwdMisses(t *testing.T) {
forceCaseInsensitive(t, true)
mi, dir := indexSingleRepoForTest(t)
_, _, _, ok := mi.ScopeForCWD(filepath.Join(filepath.Dir(dir), "somewhere-else"))
assert.False(t, ok)
}
func TestFoldDistinctRepoCount(t *testing.T) {
forceCaseInsensitive(t, true)
repos := []config.RepoEntry{
{Path: "/Users/me/Repo"},
{Path: "/Users/me/repo"}, // case variant of the first
{Path: "/Users/me/other"},
}
if got := foldDistinctRepoCount(repos); got != 2 {
t.Fatalf("foldDistinctRepoCount = %d, want 2 (case variants fold to one)", got)
}
}
func TestFoldDistinctRepoCount_CaseSensitive(t *testing.T) {
forceCaseInsensitive(t, false)
repos := []config.RepoEntry{
{Path: "/Users/me/Repo"},
{Path: "/Users/me/repo"},
}
if got := foldDistinctRepoCount(repos); got != 2 {
t.Fatalf("case-sensitive foldDistinctRepoCount = %d, want 2", got)
}
}