ricecoder_execution/
step_creator.rs1use crate::error::{ExecutionError, ExecutionResult};
4use crate::models::{ExecutionStep, RollbackAction, RollbackType, StepAction};
5use ricecoder_storage::PathResolver;
6use serde_json::json;
7use std::path::Path;
8
9pub struct StepCreator;
11
12impl StepCreator {
13 pub fn create_file(path: String, content: String) -> ExecutionResult<ExecutionStep> {
25 let _resolved = PathResolver::expand_home(Path::new(&path))
27 .map_err(|e| ExecutionError::ValidationError(format!("Invalid path: {}", e)))?;
28
29 let mut step = ExecutionStep::new(
30 format!("Create file: {}", path),
31 StepAction::CreateFile {
32 path: path.clone(),
33 content,
34 },
35 );
36
37 step.rollback_action = Some(RollbackAction {
39 action_type: RollbackType::DeleteFile,
40 data: json!({ "path": path }),
41 });
42
43 Ok(step)
44 }
45
46 pub fn modify_file(path: String, diff: String) -> ExecutionResult<ExecutionStep> {
58 let _resolved = PathResolver::expand_home(Path::new(&path))
60 .map_err(|e| ExecutionError::ValidationError(format!("Invalid path: {}", e)))?;
61
62 let mut step = ExecutionStep::new(
63 format!("Modify file: {}", path),
64 StepAction::ModifyFile {
65 path: path.clone(),
66 diff,
67 },
68 );
69
70 step.rollback_action = Some(RollbackAction {
72 action_type: RollbackType::RestoreFile,
73 data: json!({ "path": path }),
74 });
75
76 Ok(step)
77 }
78
79 pub fn delete_file(path: String) -> ExecutionResult<ExecutionStep> {
90 let _resolved = PathResolver::expand_home(Path::new(&path))
92 .map_err(|e| ExecutionError::ValidationError(format!("Invalid path: {}", e)))?;
93
94 let mut step = ExecutionStep::new(
95 format!("Delete file: {}", path),
96 StepAction::DeleteFile { path: path.clone() },
97 );
98
99 step.rollback_action = Some(RollbackAction {
101 action_type: RollbackType::RestoreFile,
102 data: json!({ "path": path }),
103 });
104
105 Ok(step)
106 }
107
108 pub fn run_command(command: String, args: Vec<String>) -> ExecutionStep {
117 let mut step = ExecutionStep::new(
118 format!("Run command: {} {}", command, args.join(" ")),
119 StepAction::RunCommand {
120 command: command.clone(),
121 args: args.clone(),
122 },
123 );
124
125 step.rollback_action = Some(RollbackAction {
127 action_type: RollbackType::RunCommand,
128 data: json!({
129 "command": command,
130 "args": args,
131 "reverse": true
132 }),
133 });
134
135 step
136 }
137
138 pub fn run_tests(pattern: Option<String>) -> ExecutionStep {
146 let description = if let Some(ref p) = pattern {
147 format!("Run tests matching: {}", p)
148 } else {
149 "Run all tests".to_string()
150 };
151
152 ExecutionStep::new(description, StepAction::RunTests { pattern })
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159
160 #[test]
161 fn test_create_file_step() {
162 let result = StepCreator::create_file("test.txt".to_string(), "content".to_string());
163 assert!(result.is_ok());
164 let step = result.unwrap();
165 assert!(matches!(step.action, StepAction::CreateFile { .. }));
166 assert!(step.rollback_action.is_some());
167 }
168
169 #[test]
170 fn test_modify_file_step() {
171 let result = StepCreator::modify_file("test.txt".to_string(), "diff".to_string());
172 assert!(result.is_ok());
173 let step = result.unwrap();
174 assert!(matches!(step.action, StepAction::ModifyFile { .. }));
175 assert!(step.rollback_action.is_some());
176 }
177
178 #[test]
179 fn test_delete_file_step() {
180 let result = StepCreator::delete_file("test.txt".to_string());
181 assert!(result.is_ok());
182 let step = result.unwrap();
183 assert!(matches!(step.action, StepAction::DeleteFile { .. }));
184 assert!(step.rollback_action.is_some());
185 }
186
187 #[test]
188 fn test_run_command_step() {
189 let step = StepCreator::run_command("echo".to_string(), vec!["hello".to_string()]);
190 assert!(matches!(step.action, StepAction::RunCommand { .. }));
191 assert!(step.rollback_action.is_some());
192 }
193
194 #[test]
195 fn test_run_tests_step() {
196 let step = StepCreator::run_tests(Some("*.rs".to_string()));
197 assert!(matches!(step.action, StepAction::RunTests { .. }));
198 }
199
200 #[test]
201 fn test_rollback_action_for_create() {
202 let step = StepCreator::create_file("test.txt".to_string(), "content".to_string()).unwrap();
203 let rollback = step.rollback_action.unwrap();
204 assert_eq!(rollback.action_type, RollbackType::DeleteFile);
205 }
206
207 #[test]
208 fn test_rollback_action_for_modify() {
209 let step = StepCreator::modify_file("test.txt".to_string(), "diff".to_string()).unwrap();
210 let rollback = step.rollback_action.unwrap();
211 assert_eq!(rollback.action_type, RollbackType::RestoreFile);
212 }
213
214 #[test]
215 fn test_rollback_action_for_delete() {
216 let step = StepCreator::delete_file("test.txt".to_string()).unwrap();
217 let rollback = step.rollback_action.unwrap();
218 assert_eq!(rollback.action_type, RollbackType::RestoreFile);
219 }
220
221 #[test]
222 fn test_rollback_action_for_command() {
223 let step = StepCreator::run_command("echo".to_string(), vec!["hello".to_string()]);
224 let rollback = step.rollback_action.unwrap();
225 assert_eq!(rollback.action_type, RollbackType::RunCommand);
226 }
227}