1use std::path::Path;
2
3use anyhow::Result;
4use mana_core::ops::delete as ops_delete;
5
6pub fn cmd_delete(mana_dir: &Path, id: &str) -> Result<()> {
13 let result = ops_delete::delete(mana_dir, id)?;
14 println!("Deleted unit {}: {}", result.id, result.title);
15 Ok(())
16}
17
18#[cfg(test)]
19mod tests {
20 use super::*;
21 use std::fs;
22
23 use crate::index::Index;
24 use crate::unit::Unit;
25 use crate::util::title_to_slug;
26 use tempfile::TempDir;
27
28 fn setup_test_mana_dir() -> (TempDir, std::path::PathBuf) {
29 let dir = TempDir::new().unwrap();
30 let mana_dir = dir.path().join(".mana");
31 fs::create_dir(&mana_dir).unwrap();
32 (dir, mana_dir)
33 }
34
35 #[test]
36 fn test_delete_unit() {
37 let (_dir, mana_dir) = setup_test_mana_dir();
38 let unit = Unit::new("1", "Task to delete");
39 let slug = title_to_slug(&unit.title);
40 let unit_path = mana_dir.join(format!("1-{}.md", slug));
41 unit.to_file(&unit_path).unwrap();
42
43 assert!(unit_path.exists());
44
45 cmd_delete(&mana_dir, "1").unwrap();
46
47 assert!(!unit_path.exists());
48 }
49
50 #[test]
51 fn test_delete_nonexistent_unit() {
52 let (_dir, mana_dir) = setup_test_mana_dir();
53 let result = cmd_delete(&mana_dir, "99");
54 assert!(result.is_err());
55 }
56
57 #[test]
58 fn test_delete_cleans_dependencies() {
59 let (_dir, mana_dir) = setup_test_mana_dir();
60
61 let unit1 = Unit::new("1", "Task 1");
63 let mut unit2 = Unit::new("2", "Task 2");
64 let mut unit3 = Unit::new("3", "Task 3");
65
66 unit2.dependencies = vec!["1".to_string()];
67 unit3.dependencies = vec!["1".to_string(), "2".to_string()];
68
69 let slug1 = title_to_slug(&unit1.title);
70 let slug2 = title_to_slug(&unit2.title);
71 let slug3 = title_to_slug(&unit3.title);
72
73 unit1
74 .to_file(mana_dir.join(format!("1-{}.md", slug1)))
75 .unwrap();
76 unit2
77 .to_file(mana_dir.join(format!("2-{}.md", slug2)))
78 .unwrap();
79 unit3
80 .to_file(mana_dir.join(format!("3-{}.md", slug3)))
81 .unwrap();
82
83 cmd_delete(&mana_dir, "1").unwrap();
85
86 let unit2_updated =
88 Unit::from_file(crate::discovery::find_unit_file(&mana_dir, "2").unwrap()).unwrap();
89 assert!(!unit2_updated.dependencies.contains(&"1".to_string()));
90
91 let unit3_updated =
93 Unit::from_file(crate::discovery::find_unit_file(&mana_dir, "3").unwrap()).unwrap();
94 assert!(!unit3_updated.dependencies.contains(&"1".to_string()));
95 assert!(unit3_updated.dependencies.contains(&"2".to_string()));
96 }
97
98 #[test]
99 fn test_delete_rebuilds_index() {
100 let (_dir, mana_dir) = setup_test_mana_dir();
101 let unit1 = Unit::new("1", "Task 1");
102 let unit2 = Unit::new("2", "Task 2");
103 let slug1 = title_to_slug(&unit1.title);
104 let slug2 = title_to_slug(&unit2.title);
105 unit1
106 .to_file(mana_dir.join(format!("1-{}.md", slug1)))
107 .unwrap();
108 unit2
109 .to_file(mana_dir.join(format!("2-{}.md", slug2)))
110 .unwrap();
111
112 cmd_delete(&mana_dir, "1").unwrap();
113
114 let index = Index::load(&mana_dir).unwrap();
115 assert_eq!(index.units.len(), 1);
116 assert_eq!(index.units[0].id, "2");
117 }
118
119 #[test]
120 fn test_cleanup_does_not_modify_unrelated_units() {
121 let (_dir, mana_dir) = setup_test_mana_dir();
122
123 let unit1 = Unit::new("1", "Task 1");
125 let mut unit2 = Unit::new("2", "Task 2");
126 let unit3 = Unit::new("3", "Task 3"); unit2.dependencies = vec!["1".to_string()];
129
130 let slug1 = title_to_slug(&unit1.title);
131 let slug2 = title_to_slug(&unit2.title);
132 let slug3 = title_to_slug(&unit3.title);
133
134 unit1
135 .to_file(mana_dir.join(format!("1-{}.md", slug1)))
136 .unwrap();
137 unit2
138 .to_file(mana_dir.join(format!("2-{}.md", slug2)))
139 .unwrap();
140 unit3
141 .to_file(mana_dir.join(format!("3-{}.md", slug3)))
142 .unwrap();
143
144 cmd_delete(&mana_dir, "1").unwrap();
145
146 let unit3_check =
147 Unit::from_file(crate::discovery::find_unit_file(&mana_dir, "3").unwrap()).unwrap();
148 assert!(unit3_check.dependencies.is_empty());
149 }
150
151 #[test]
152 fn test_delete_with_complex_dependency_graph() {
153 let (_dir, mana_dir) = setup_test_mana_dir();
154
155 let unit1 = Unit::new("1", "Root");
157 let mut unit2 = Unit::new("2", "Middle left");
158 let mut unit3 = Unit::new("3", "Middle right");
159 let mut unit4 = Unit::new("4", "Bottom");
160
161 unit2.dependencies = vec!["1".to_string()];
162 unit3.dependencies = vec!["1".to_string()];
163 unit4.dependencies = vec!["2".to_string(), "3".to_string()];
164
165 let slug1 = title_to_slug(&unit1.title);
166 let slug2 = title_to_slug(&unit2.title);
167 let slug3 = title_to_slug(&unit3.title);
168 let slug4 = title_to_slug(&unit4.title);
169
170 unit1
171 .to_file(mana_dir.join(format!("1-{}.md", slug1)))
172 .unwrap();
173 unit2
174 .to_file(mana_dir.join(format!("2-{}.md", slug2)))
175 .unwrap();
176 unit3
177 .to_file(mana_dir.join(format!("3-{}.md", slug3)))
178 .unwrap();
179 unit4
180 .to_file(mana_dir.join(format!("4-{}.md", slug4)))
181 .unwrap();
182
183 cmd_delete(&mana_dir, "1").unwrap();
185
186 let unit2_updated =
188 Unit::from_file(crate::discovery::find_unit_file(&mana_dir, "2").unwrap()).unwrap();
189 let unit3_updated =
190 Unit::from_file(crate::discovery::find_unit_file(&mana_dir, "3").unwrap()).unwrap();
191 let unit4_updated =
192 Unit::from_file(crate::discovery::find_unit_file(&mana_dir, "4").unwrap()).unwrap();
193
194 assert!(!unit2_updated.dependencies.contains(&"1".to_string()));
195 assert!(!unit3_updated.dependencies.contains(&"1".to_string()));
196 assert!(!unit4_updated.dependencies.contains(&"1".to_string()));
197 assert!(unit4_updated.dependencies.contains(&"2".to_string()));
198 assert!(unit4_updated.dependencies.contains(&"3".to_string()));
199 }
200
201 #[test]
202 fn test_delete_ignores_excluded_files() {
203 let (_dir, mana_dir) = setup_test_mana_dir();
204
205 let unit1 = Unit::new("1", "Task 1");
206 let slug1 = title_to_slug(&unit1.title);
207 unit1
208 .to_file(mana_dir.join(format!("1-{}.md", slug1)))
209 .unwrap();
210
211 fs::write(
213 mana_dir.join("config.yaml"),
214 "next_id: 2\nproject_name: test\n",
215 )
216 .unwrap();
217
218 cmd_delete(&mana_dir, "1").unwrap();
220 assert!(!mana_dir.join(format!("1-{}.md", slug1)).exists());
221 }
222}