@@ -4,6 +4,7 @@ import (
44 "io"
55 "log/slog"
66 "os"
7+ "os/exec"
78 "path/filepath"
89 "testing"
910
@@ -111,6 +112,68 @@ func TestConfig_setDefaults(t *testing.T) {
111112
112113 require.Equal(t, filepath.Join(workingDir, "state"), cfg.Options.DataDirectory)
113114 })
115+
116+ t.Run("does not adopt .crush from a parent project", func(t *testing.T) {
117+ parent := t.TempDir()
118+
119+ // .crush in the parent: it should not be reused by the child
120+ // because there is no git context joining them.
121+ require.NoError(t, os.Mkdir(filepath.Join(parent, defaultDataDirectory), 0o755))
122+
123+ child := filepath.Join(parent, "child")
124+ require.NoError(t, os.Mkdir(child, 0o755))
125+
126+ cfg := &Config{}
127+ cfg.setDefaults(child, "")
128+
129+ require.Equal(t,
130+ filepath.Clean(filepath.Join(child, defaultDataDirectory)),
131+ filepath.Clean(cfg.Options.DataDirectory),
132+ )
133+ })
134+
135+ t.Run("does not climb out of git worktree to find .crush", func(t *testing.T) {
136+ if _, err := exec.LookPath("git"); err != nil {
137+ t.Skip("git not available")
138+ }
139+
140+ parent := t.TempDir()
141+
142+ // Stray .crush above the worktree root.
143+ require.NoError(t, os.Mkdir(filepath.Join(parent, defaultDataDirectory), 0o755))
144+
145+ worktree := filepath.Join(parent, "worktree")
146+ require.NoError(t, os.Mkdir(worktree, 0o755))
147+
148+ sub := filepath.Join(worktree, "pkg")
149+ require.NoError(t, os.Mkdir(sub, 0o755))
150+
151+ // Make worktree a real git repo so the boundary detection
152+ // resolves to it, mirroring what happens with linked worktrees
153+ // in real usage.
154+ gitInit := exec.CommandContext(t.Context(), "git", "init", "-q")
155+ gitInit.Dir = worktree
156+ require.NoError(t, gitInit.Run())
157+
158+ cfg := &Config{}
159+ cfg.setDefaults(sub, "")
160+
161+ // Resolve symlinks because TempDir on macOS sits under /var
162+ // which is a symlink to /private/var. The data directory has
163+ // not been created yet, so resolve its parent and join.
164+ gotDir, gotName := filepath.Split(cfg.Options.DataDirectory)
165+ gotEvalDir, err := filepath.EvalSymlinks(filepath.Clean(gotDir))
166+ require.NoError(t, err)
167+ gotEval := filepath.Join(gotEvalDir, gotName)
168+
169+ strayEval, err := filepath.EvalSymlinks(filepath.Join(parent, defaultDataDirectory))
170+ require.NoError(t, err)
171+ require.NotEqual(t, strayEval, gotEval, "must not adopt parent .crush")
172+
173+ subEval, err := filepath.EvalSymlinks(sub)
174+ require.NoError(t, err)
175+ require.Equal(t, filepath.Join(subEval, defaultDataDirectory), gotEval)
176+ })
114177}
115178
116179func TestConfig_configureProviders(t *testing.T) {