package git_test import ( "context" "os" "os/exec" "path/filepath" "strings" "testing" "superwork-tui/internal/git" ) // initRepo creates a bare git repo with one commit so worktree operations work. func initRepo(t *testing.T) string { t.Helper() dir := t.TempDir() run := func(args ...string) { t.Helper() cmd := exec.Command("git", args...) cmd.Dir = dir out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("git %v: %v\n%s", args, err, out) } } run("init") run("config", "user.email", "test@test.com") run("config", "user.name", "test") // Need at least one commit for worktree add -b to work. f := filepath.Join(dir, "README") if err := os.WriteFile(f, []byte("init"), 0o644); err != nil { t.Fatal(err) } run("add", ".") run("commit", "-m", "init") return dir } func TestCreateWorktree(t *testing.T) { root := initRepo(t) wtPath := filepath.Join(t.TempDir(), "feature-wt") err := git.CreateWorktree(context.Background(), git.CreateWorktreeOpts{ WorkspaceRoot: root, WorktreePath: wtPath, Branch: "feature/test-branch", }) if err != nil { t.Fatalf("CreateWorktree: %v", err) } // Directory must exist. if _, err := os.Stat(wtPath); err != nil { t.Fatalf("worktree dir not created: %v", err) } // The new branch must exist in the main repo. out, err := exec.Command("git", "-C", root, "branch", "--list", "feature/test-branch").Output() if err != nil { t.Fatalf("git branch --list: %v", err) } if !strings.Contains(string(out), "feature/test-branch") { t.Errorf("branch not created; git branch output: %q", string(out)) } } func TestCreateWorktree_BadBranch(t *testing.T) { root := initRepo(t) wtPath := filepath.Join(t.TempDir(), "bad-wt") // Using a branch name with ".." is invalid for git. err := git.CreateWorktree(context.Background(), git.CreateWorktreeOpts{ WorkspaceRoot: root, WorktreePath: wtPath, Branch: "bad..branch", }) if err == nil { t.Fatal("expected error for invalid branch name, got nil") } // Error must mention something useful (stderr wrapped in). t.Logf("got expected error: %v", err) } func TestRemoveWorktree(t *testing.T) { root := initRepo(t) wtPath := filepath.Join(t.TempDir(), "rm-wt") if err := git.CreateWorktree(context.Background(), git.CreateWorktreeOpts{ WorkspaceRoot: root, WorktreePath: wtPath, Branch: "feature/rm-test", }); err != nil { t.Fatalf("setup CreateWorktree: %v", err) } err := git.RemoveWorktree(context.Background(), git.RemoveWorktreeOpts{ WorkspaceRoot: root, WorktreePath: wtPath, Force: false, }) if err != nil { t.Fatalf("RemoveWorktree: %v", err) } // Directory must be gone. if _, err := os.Stat(wtPath); !os.IsNotExist(err) { t.Errorf("worktree dir still exists after remove") } } func TestRemoveWorktree_Force(t *testing.T) { root := initRepo(t) wtPath := filepath.Join(t.TempDir(), "force-wt") if err := git.CreateWorktree(context.Background(), git.CreateWorktreeOpts{ WorkspaceRoot: root, WorktreePath: wtPath, Branch: "feature/force-test", }); err != nil { t.Fatalf("setup: %v", err) } // Write an uncommitted change to make the worktree "dirty". if err := os.WriteFile(filepath.Join(wtPath, "dirty"), []byte("x"), 0o644); err != nil { t.Fatal(err) } cmd := exec.Command("git", "add", ".") cmd.Dir = wtPath cmd.Run() //nolint — best effort for test setup // Without force this might fail; with force it must succeed. err := git.RemoveWorktree(context.Background(), git.RemoveWorktreeOpts{ WorkspaceRoot: root, WorktreePath: wtPath, Force: true, }) if err != nil { t.Fatalf("RemoveWorktree --force: %v", err) } if _, err := os.Stat(wtPath); !os.IsNotExist(err) { t.Errorf("worktree dir still exists after force remove") } }