package project import ( "os" "path/filepath" "testing" ) // Every test here strips CLAUDE_PROJECT_DIR: it is the first anchor of the // walk, so the harness's own value would point every fixture at whatever // repository the suite happens to run in. func fixture(t *testing.T) string { t.Helper() t.Setenv("CLAUDE_PROJECT_DIR", "") dir := t.TempDir() // macOS hands out /var/… , a symlink to /private/var, and the walk works // in resolved paths. real, err := filepath.EvalSymlinks(dir) if err != nil { t.Fatal(err) } return real } func chdir(t *testing.T, dir string) { t.Helper() t.Chdir(dir) } func TestRootFindsTheNearestMarkerUpFromTheWorkingDirectory(t *testing.T) { root := fixture(t) deep := filepath.Join(root, "a", "b", "c") if err := os.MkdirAll(deep, 0o755); err != nil { t.Fatal(err) } if err := os.MkdirAll(filepath.Join(root, Marker), 0o755); err != nil { t.Fatal(err) } chdir(t, deep) if got := Root(""); got != root { t.Errorf("Root() = %q, want %q", got, root) } if got := StoreRoot(""); got != filepath.Join(root, Marker, "issues") { t.Errorf("StoreRoot() = %q", got) } // The scratchpad is a sibling of the store, never inside it: a call that // touches no issue must not materialize the issue directory. if got := PayloadRoot(""); got != filepath.Join(root, Marker, "payload") { t.Errorf("PayloadRoot() = %q", got) } } func TestNoMarkerIsAnAnswerNotAFallback(t *testing.T) { dir := fixture(t) chdir(t, dir) if got := Root(""); got != "" { t.Errorf("Root() = %q, want empty — a plausible-looking directory is the failure this replaces", got) } if got := StoreRoot(""); got != "" { t.Errorf("StoreRoot() = %q, want empty", got) } if err := NotFoundError(""); err == nil { t.Fatal("NotFoundError must explain itself") } } func TestTheNearestMarkerWinsOverAnAncestorOne(t *testing.T) { outer := fixture(t) inner := filepath.Join(outer, "vendored") for _, d := range []string{filepath.Join(outer, Marker), filepath.Join(inner, Marker)} { if err := os.MkdirAll(d, 0o755); err != nil { t.Fatal(err) } } chdir(t, inner) if got := Root(""); got != inner { t.Errorf("Root() = %q, want the nearest marker %q", got, inner) } } // A linked worktree is a SIBLING of the main checkout, so the gitignored // marker is never on its parent chain. The whole sync layer once died there // while the tracker CLI in the same directory worked. func TestALinkedWorktreeResolvesToTheMainCheckout(t *testing.T) { base := fixture(t) main := filepath.Join(base, "repo") wt := filepath.Join(base, "repo-feat") gitdir := filepath.Join(main, ".git", "worktrees", "feat") for _, d := range []string{filepath.Join(main, Marker), gitdir, wt} { if err := os.MkdirAll(d, 0o755); err != nil { t.Fatal(err) } } // /.git points at the private dir; commondir points back at //
/.git, whose parent is the main working tree. write(t, filepath.Join(wt, ".git"), "gitdir: "+gitdir+"\n") write(t, filepath.Join(gitdir, "commondir"), "../..\n") chdir(t, wt) if got := Root(""); got != main { t.Errorf("Root() = %q, want the main checkout %q", got, main) } } // A submodule's .git is a pointer too, but it points into // /.git/modules/…, and the tree it belongs to is already on the parent // chain. Following it would be a hop to nowhere. func TestASubmoduleIsNotAWorktree(t *testing.T) { base := fixture(t) sub := filepath.Join(base, "super", "sub") gitdir := filepath.Join(base, "super", ".git", "modules", "sub") for _, d := range []string{sub, gitdir} { if err := os.MkdirAll(d, 0o755); err != nil { t.Fatal(err) } } write(t, filepath.Join(sub, ".git"), "gitdir: "+gitdir+"\n") if got := MainWorktree(sub); got != "" { t.Errorf("MainWorktree() = %q, want empty", got) } } func TestAnOrdinaryCloneHasNothingToFollow(t *testing.T) { dir := fixture(t) if err := os.MkdirAll(filepath.Join(dir, ".git"), 0o755); err != nil { t.Fatal(err) } if got := GitDirOf(dir); got != "" { t.Errorf("GitDirOf() = %q — only a .git FILE is a pointer", got) } } func TestClaudeProjectDirIsTheFirstAnchor(t *testing.T) { base := fixture(t) opened := filepath.Join(base, "opened") elsewhere := filepath.Join(base, "elsewhere") for _, d := range []string{filepath.Join(opened, Marker), filepath.Join(elsewhere, Marker)} { if err := os.MkdirAll(d, 0o755); err != nil { t.Fatal(err) } } t.Setenv("CLAUDE_PROJECT_DIR", opened) chdir(t, elsewhere) if got := Root(""); got != opened { t.Errorf("Root() = %q, want the opened project %q", got, opened) } } func write(t *testing.T, path, content string) { t.Helper() if err := os.WriteFile(path, []byte(content), 0o644); err != nil { t.Fatal(err) } }