kanban_persistence_json/
conflict.rs1use std::fs;
2use std::hash::{Hash, Hasher};
3use std::path::Path;
4use std::time::SystemTime;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub struct FileMetadata {
13 pub modified_time: SystemTime,
15 pub size: u64,
17 pub content_hash: u64,
19}
20
21impl FileMetadata {
22 pub fn from_file(path: &Path) -> std::io::Result<Self> {
27 let metadata = fs::metadata(path)?;
28 let modified_time = metadata.modified()?;
29 let size = metadata.len();
30
31 let content = fs::read(path)?;
33 let mut hasher = std::collections::hash_map::DefaultHasher::new();
34 content.hash(&mut hasher);
35 let content_hash = hasher.finish();
36
37 Ok(Self {
38 modified_time,
39 size,
40 content_hash,
41 })
42 }
43
44 pub fn has_changed(&self, path: &Path) -> std::io::Result<bool> {
46 let current = Self::from_file(path)?;
47 Ok(current != *self)
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54 use tempfile::tempdir;
55
56 #[test]
57 fn test_metadata_from_file() {
58 let dir = tempdir().unwrap();
59 let file_path = dir.path().join("test.json");
60 let content = b"test content";
61 fs::write(&file_path, content).unwrap();
62
63 let metadata = FileMetadata::from_file(&file_path).unwrap();
64 assert_eq!(metadata.size, content.len() as u64);
65 }
66
67 #[test]
68 fn test_has_not_changed() {
69 let dir = tempdir().unwrap();
70 let file_path = dir.path().join("test.json");
71 fs::write(&file_path, b"test content").unwrap();
72
73 let metadata = FileMetadata::from_file(&file_path).unwrap();
74 assert!(!metadata.has_changed(&file_path).unwrap());
75 }
76
77 #[test]
78 fn test_has_changed_on_content_modification() {
79 let dir = tempdir().unwrap();
80 let file_path = dir.path().join("test.json");
81 fs::write(&file_path, b"test content").unwrap();
82
83 let metadata = FileMetadata::from_file(&file_path).unwrap();
84 fs::write(&file_path, b"modified content").unwrap();
85
86 assert!(metadata.has_changed(&file_path).unwrap());
87 }
88
89 #[test]
90 fn test_size_change_detected() {
91 let dir = tempdir().unwrap();
92 let file_path = dir.path().join("test.json");
93 fs::write(&file_path, b"content1").unwrap();
94
95 let metadata = FileMetadata::from_file(&file_path).unwrap();
96 assert_eq!(metadata.size, 8);
97
98 fs::write(&file_path, b"content1_longer").unwrap();
99 assert!(metadata.has_changed(&file_path).unwrap());
100 }
101}