package git import ( "context" "errors" "os" "os/exec" "path/filepath" "strings" "testing" ) func TestDiscoverRepositoryRoot(t *testing.T) { repo := newRemoteFixture(t) child := filepath.Join(repo.work, "child") if err := os.Mkdir(child, 0755); err != nil { t.Fatal(err) } alias := filepath.Join(t.TempDir(), "alias") if err := os.Symlink(repo.work, alias); err != nil { t.Fatal(err) } worktree := filepath.Join(t.TempDir(), "worktree") gitRun(t, repo.work, "worktree", "add", "--detach", worktree) for _, tc := range []struct{ dir, want string }{{repo.work, repo.work}, {child, repo.work}, {alias, repo.work}, {worktree, worktree}} { root, found, err := DiscoverRepositoryRoot(context.Background(), tc.dir) want, e := filepath.EvalSymlinks(tc.want) if e != nil { t.Fatal(e) } if err != nil || !found || root != want { t.Fatalf("Discover(%s) = %q, %t, %v; want %q", tc.dir, root, found, err, want) } } standalone := t.TempDir() if root, found, err := DiscoverRepositoryRoot(context.Background(), standalone); err != nil || found || root != "" { t.Fatalf("standalone = %q, %t, %v", root, found, err) } if _, err := RepositoryRoot(context.Background(), standalone); err == nil { t.Fatal("strict lookup accepted standalone") } broken := t.TempDir() if err := os.WriteFile(filepath.Join(broken, ".git"), []byte("gitdir: missing\n"), 0600); err != nil { t.Fatal(err) } if _, found, err := DiscoverRepositoryRoot(context.Background(), broken); err == nil || found { t.Fatalf("broken marker: found %t, error %v", found, err) } if _, found, err := DiscoverRepositoryRoot(context.Background(), filepath.Join(standalone, "missing")); err == nil || found { t.Fatalf("missing directory: found %t, error %v", found, err) } } func TestNoRepositoryDiagnostic(t *testing.T) { for _, tc := range []struct { message string want bool }{ {"fatal: not a git repository (or any of the parent directories): .git\n", true}, {"fatal: not a git repository (or any parent up to mount point /some path)\nStopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).\n", true}, {"fatal: not a git repository: '/bad'", false}, {"fatal: detected dubious ownership in repository", false}, } { if got := noRepositoryDiagnostic(tc.message); got != tc.want { t.Errorf("diagnostic %q = %t", tc.message, got) } } } func TestDiscoverRepositoryRootFailures(t *testing.T) { dir := t.TempDir() bin := t.TempDir() script := "#!/bin/sh\nprintf '%s\\n' 'fatal: detected dubious ownership in repository' >&2\nexit 128\n" if err := os.WriteFile(filepath.Join(bin, "git"), []byte(script), 0755); err != nil { t.Fatal(err) } t.Setenv("PATH", bin) _, found, err := DiscoverRepositoryRoot(context.Background(), dir) var exitErr *exec.ExitError if found || !errors.As(err, &exitErr) || exitErr.ExitCode() != 128 || !strings.Contains(err.Error(), "dubious ownership") { t.Fatalf("found %t, error %v", found, err) } ctx, cancel := context.WithCancel(context.Background()) cancel() if _, _, err := DiscoverRepositoryRoot(ctx, dir); !errors.Is(err, context.Canceled) { t.Fatalf("cancellation = %v", err) } } func TestDiscoverRepositoryRootWithoutGit(t *testing.T) { repo := newRemoteFixture(t) standalone := t.TempDir() t.Setenv("PATH", t.TempDir()) if _, found, err := DiscoverRepositoryRoot(context.Background(), standalone); found || err != nil { t.Fatalf("standalone: found %t, error %v", found, err) } if _, found, err := DiscoverRepositoryRoot(context.Background(), repo.work); found || !errors.Is(err, exec.ErrNotFound) { t.Fatalf("checkout: found %t, error %v", found, err) } broken := t.TempDir() if err := os.WriteFile(filepath.Join(broken, ".git"), []byte("broken"), 0600); err != nil { t.Fatal(err) } if _, found, err := DiscoverRepositoryRoot(context.Background(), broken); found || !errors.Is(err, exec.ErrNotFound) { t.Fatalf("broken marker: found %t, error %v", found, err) } t.Setenv("GIT_DIR", "invalid") if _, found, err := DiscoverRepositoryRoot(context.Background(), standalone); found || !errors.Is(err, exec.ErrNotFound) { t.Fatalf("explicit context: found %t, error %v", found, err) } }