git_gardener/commands/
cd.rs1use crate::error::{GitGardenerError, Result};
2use crate::git::GitWorktree;
3
4pub struct CdCommand {
5 pub worktree: String,
6}
7
8impl CdCommand {
9 pub fn new(worktree: String) -> Self {
10 Self { worktree }
11 }
12
13 pub fn execute(&self) -> Result<String> {
14 let git_worktree = GitWorktree::new()?;
15 let repo_root = git_worktree.get_repository_root()?;
16
17 if self.worktree == "@" {
19 return Ok(repo_root.to_string_lossy().to_string());
20 }
21
22 let worktrees = git_worktree.list_worktrees()?;
24
25 let target_worktree = worktrees.iter()
27 .find(|w| w.name == self.worktree || w.branch == self.worktree)
28 .ok_or_else(|| GitGardenerError::Custom(
29 format!("Worktree '{}' not found", self.worktree)
30 ))?;
31
32 Ok(target_worktree.path.to_string_lossy().to_string())
34 }
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40 use tempfile::tempdir;
41 use std::fs;
42 use std::process::Command;
43
44 fn setup_git_repo_with_worktree() -> tempfile::TempDir {
45 let temp_dir = tempdir().unwrap();
46 let repo_path = temp_dir.path();
47
48 Command::new("git")
50 .args(&["init"])
51 .current_dir(repo_path)
52 .output()
53 .expect("Failed to init git repo");
54
55 Command::new("git")
57 .args(&["config", "user.name", "Test User"])
58 .current_dir(repo_path)
59 .output()
60 .unwrap();
61
62 Command::new("git")
63 .args(&["config", "user.email", "test@example.com"])
64 .current_dir(repo_path)
65 .output()
66 .unwrap();
67
68 fs::write(repo_path.join("README.md"), "# Test Repo").unwrap();
70
71 Command::new("git")
72 .args(&["add", "."])
73 .current_dir(repo_path)
74 .output()
75 .unwrap();
76
77 Command::new("git")
78 .args(&["commit", "-m", "Initial commit"])
79 .current_dir(repo_path)
80 .output()
81 .unwrap();
82
83 let worktree_path = repo_path.join("feature-test");
85 Command::new("git")
86 .args(&["worktree", "add", "-b", "feature-test", &worktree_path.to_string_lossy()])
87 .current_dir(repo_path)
88 .output()
89 .unwrap();
90
91 temp_dir
92 }
93
94 #[test]
95 fn test_cd_command_new_creates_instance() {
96 let cmd = CdCommand::new("test-branch".to_string());
98 assert_eq!(cmd.worktree, "test-branch");
99 }
100
101 #[test]
102 fn test_cd_command_fails_without_git_repo() {
103 let temp_dir = tempdir().unwrap();
105 std::env::set_current_dir(temp_dir.path()).unwrap();
106
107 let cmd = CdCommand::new("test".to_string());
108 let result = cmd.execute();
109
110 assert!(result.is_err());
111 assert!(matches!(result.unwrap_err(), GitGardenerError::NotInRepository));
112 }
113
114 #[test]
115 fn test_cd_command_returns_main_worktree_for_at_symbol() {
116 let temp_dir = setup_git_repo_with_worktree();
118 std::env::set_current_dir(temp_dir.path()).unwrap();
119
120 let cmd = CdCommand::new("@".to_string());
121 let result = cmd.execute();
122
123 assert!(result.is_ok());
124 let path = result.unwrap();
125 assert!(path.contains(temp_dir.path().to_str().unwrap()));
127 }
128
129 #[test]
130 fn test_cd_command_finds_worktree_by_branch_name() {
131 let temp_dir = setup_git_repo_with_worktree();
133 std::env::set_current_dir(temp_dir.path()).unwrap();
134
135 let cmd = CdCommand::new("feature-test".to_string());
136 let result = cmd.execute();
137
138 assert!(result.is_ok());
139 let path = result.unwrap();
140 assert!(path.contains("feature-test"));
141 }
142
143 #[test]
144 fn test_cd_command_fails_for_nonexistent_worktree() {
145 let temp_dir = setup_git_repo_with_worktree();
147 std::env::set_current_dir(temp_dir.path()).unwrap();
148
149 let cmd = CdCommand::new("nonexistent-worktree".to_string());
150 let result = cmd.execute();
151
152 assert!(result.is_err());
153 let error_msg = format!("{}", result.unwrap_err());
154 assert!(error_msg.contains("not found"));
155 }
156}