Skip to main content

git_gardener/commands/
list.rs

1use crate::error::Result;
2use crate::git::GitWorktree;
3use colored::*;
4
5pub struct ListCommand {
6    pub names_only: bool,
7}
8
9impl ListCommand {
10    pub fn new(names_only: bool) -> Self {
11        Self { names_only }
12    }
13    
14    pub fn execute(&self) -> Result<()> {
15        let git_worktree = GitWorktree::new()?;
16        let worktrees = git_worktree.list_worktrees()?;
17        
18        if worktrees.is_empty() {
19            if !self.names_only {
20                println!("No worktrees found.");
21            }
22            return Ok(());
23        }
24        
25        if self.names_only {
26            // Shell completion用にworktree名のみを出力
27            for worktree in worktrees {
28                println!("{}", worktree.branch);
29            }
30        } else {
31            // 通常の表形式表示
32            println!(
33                "{:<30} {:<50}",
34                "BRANCH".blue().bold(),
35                "PATH".blue().bold()
36            );
37            println!("{}", "-".repeat(80).bright_black());
38
39            for worktree in worktrees {
40                println!(
41                    "{:<30} {:<50}",
42                    worktree.branch.green(),
43                    worktree.path.display().to_string().yellow()
44                );
45            }
46        }
47        
48        Ok(())
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55    use tempfile::tempdir;
56    use std::fs;
57    use std::process::Command;
58
59    fn setup_git_repo_with_worktree() -> tempfile::TempDir {
60        let temp_dir = tempdir().unwrap();
61        let repo_path = temp_dir.path();
62        
63        // Git リポジトリを初期化
64        Command::new("git")
65            .args(&["init"])
66            .current_dir(repo_path)
67            .output()
68            .expect("Failed to init git repo");
69        
70        // 設定
71        Command::new("git")
72            .args(&["config", "user.name", "Test User"])
73            .current_dir(repo_path)
74            .output()
75            .unwrap();
76        
77        Command::new("git")
78            .args(&["config", "user.email", "test@example.com"])
79            .current_dir(repo_path)
80            .output()
81            .unwrap();
82        
83        // 初期ファイルとコミットを作成
84        fs::write(repo_path.join("README.md"), "# Test Repo").unwrap();
85        
86        Command::new("git")
87            .args(&["add", "."])
88            .current_dir(repo_path)
89            .output()
90            .unwrap();
91        
92        Command::new("git")
93            .args(&["commit", "-m", "Initial commit"])
94            .current_dir(repo_path)
95            .output()
96            .unwrap();
97        
98        // テスト用のworktreeを作成
99        let worktree_path = repo_path.join("feature-test");
100        Command::new("git")
101            .args(&["worktree", "add", "-b", "feature-test", &worktree_path.to_string_lossy()])
102            .current_dir(repo_path)
103            .output()
104            .unwrap();
105        
106        temp_dir
107    }
108
109    #[test]
110    fn test_list_command_new_creates_instance() {
111        // What: ListCommand::newが正しくインスタンスを作成するかテスト
112        let cmd = ListCommand::new(true);
113        assert_eq!(cmd.names_only, true);
114        
115        let cmd = ListCommand::new(false);
116        assert_eq!(cmd.names_only, false);
117    }
118
119    #[test]
120    fn test_list_command_fails_without_git_repo() {
121        // What: Gitリポジトリでない場所でListCommandが失敗するかテスト
122        let temp_dir = tempdir().unwrap();
123        std::env::set_current_dir(temp_dir.path()).unwrap();
124        
125        let cmd = ListCommand::new(false);
126        let result = cmd.execute();
127        
128        assert!(result.is_err());
129    }
130
131    #[test]  
132    fn test_list_command_empty_repo_shows_no_worktrees() {
133        // What: worktreeがない場合に適切なメッセージを表示するかテスト
134        let temp_dir = tempdir().unwrap();
135        let repo_path = temp_dir.path();
136        
137        // Git リポジトリを初期化(worktreeなし)
138        Command::new("git")
139            .args(&["init"])
140            .current_dir(repo_path)
141            .output()
142            .expect("Failed to init git repo");
143        
144        std::env::set_current_dir(repo_path).unwrap();
145        
146        let cmd = ListCommand::new(false);
147        let result = cmd.execute();
148        
149        // worktreeが見つからない場合は成功するが出力は空
150        assert!(result.is_ok());
151    }
152
153    #[test]
154    fn test_list_command_names_only_flag() {
155        // What: names_onlyフラグの動作をテスト
156        let temp_dir = setup_git_repo_with_worktree();
157        std::env::set_current_dir(temp_dir.path()).unwrap();
158        
159        // names_only = true の場合
160        let cmd = ListCommand::new(true);
161        let result = cmd.execute();
162        assert!(result.is_ok());
163        
164        // names_only = false の場合
165        let cmd = ListCommand::new(false);
166        let result = cmd.execute();
167        assert!(result.is_ok());
168    }
169}