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
115 lines
3.6 KiB
Go
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)
|
|
}
|
|
}
|