ricecoder_refactoring/safety/
rollback.rs1use crate::error::{RefactoringError, Result};
4use crate::types::BackupInfo;
5use chrono::Utc;
6use std::collections::HashMap;
7use std::path::PathBuf;
8use uuid::Uuid;
9
10pub struct RollbackHandler;
12
13impl RollbackHandler {
14 pub fn create_backup(files: &[(PathBuf, String)]) -> Result<BackupInfo> {
16 let mut backup_files = HashMap::new();
17
18 for (path, content) in files {
19 backup_files.insert(path.clone(), content.clone());
20 }
21
22 Ok(BackupInfo {
23 id: Uuid::new_v4().to_string(),
24 timestamp: Utc::now().to_string(),
25 files: backup_files,
26 })
27 }
28
29 pub fn restore_from_backup(backup: &BackupInfo) -> Result<()> {
31 for (path, content) in &backup.files {
32 std::fs::write(path, content).map_err(|e| {
33 RefactoringError::RollbackFailed(format!("Failed to restore {}: {}", path.display(), e))
34 })?;
35 }
36
37 Ok(())
38 }
39
40 pub fn verify_backup(backup: &BackupInfo) -> Result<bool> {
42 if backup.files.is_empty() {
43 return Err(RefactoringError::RollbackFailed(
44 "Backup contains no files".to_string(),
45 ));
46 }
47
48 Ok(true)
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use tempfile::NamedTempFile;
56 use std::io::Write;
57
58 #[test]
59 fn test_create_backup() -> Result<()> {
60 let files = vec![
61 (PathBuf::from("file1.rs"), "content1".to_string()),
62 (PathBuf::from("file2.rs"), "content2".to_string()),
63 ];
64
65 let backup = RollbackHandler::create_backup(&files)?;
66 assert_eq!(backup.files.len(), 2);
67 assert!(!backup.id.is_empty());
68
69 Ok(())
70 }
71
72 #[test]
73 fn test_verify_backup() -> Result<()> {
74 let files = vec![(PathBuf::from("file1.rs"), "content1".to_string())];
75 let backup = RollbackHandler::create_backup(&files)?;
76
77 assert!(RollbackHandler::verify_backup(&backup)?);
78
79 Ok(())
80 }
81
82 #[test]
83 fn test_verify_backup_empty() -> Result<()> {
84 let backup = BackupInfo {
85 id: "test".to_string(),
86 timestamp: Utc::now().to_string(),
87 files: HashMap::new(),
88 };
89
90 assert!(RollbackHandler::verify_backup(&backup).is_err());
91
92 Ok(())
93 }
94
95 #[test]
96 fn test_restore_from_backup() -> Result<()> {
97 let mut file = NamedTempFile::new()?;
98 file.write_all(b"original")?;
99 file.flush()?;
100
101 let path = file.path().to_path_buf();
102 let mut backup_files = HashMap::new();
103 backup_files.insert(path.clone(), "restored".to_string());
104
105 let backup = BackupInfo {
106 id: "test".to_string(),
107 timestamp: Utc::now().to_string(),
108 files: backup_files,
109 };
110
111 RollbackHandler::restore_from_backup(&backup)?;
112
113 let content = std::fs::read_to_string(&path)?;
114 assert_eq!(content, "restored");
115
116 Ok(())
117 }
118}