use std::fs;
use std::hash::{Hash, Hasher};
use std::path::Path;
use std::time::SystemTime;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FileMetadata {
pub modified_time: SystemTime,
pub size: u64,
pub content_hash: u64,
}
impl FileMetadata {
pub fn from_file(path: &Path) -> std::io::Result<Self> {
let metadata = fs::metadata(path)?;
let modified_time = metadata.modified()?;
let size = metadata.len();
let content = fs::read(path)?;
let mut hasher = std::collections::hash_map::DefaultHasher::new();
content.hash(&mut hasher);
let content_hash = hasher.finish();
Ok(Self {
modified_time,
size,
content_hash,
})
}
pub fn has_changed(&self, path: &Path) -> std::io::Result<bool> {
let current = Self::from_file(path)?;
Ok(current != *self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;
#[test]
fn test_metadata_from_file() {
let dir = tempdir().unwrap();
let file_path = dir.path().join("test.json");
let content = b"test content";
fs::write(&file_path, content).unwrap();
let metadata = FileMetadata::from_file(&file_path).unwrap();
assert_eq!(metadata.size, content.len() as u64);
}
#[test]
fn test_has_not_changed() {
let dir = tempdir().unwrap();
let file_path = dir.path().join("test.json");
fs::write(&file_path, b"test content").unwrap();
let metadata = FileMetadata::from_file(&file_path).unwrap();
assert!(!metadata.has_changed(&file_path).unwrap());
}
#[test]
fn test_has_changed_on_content_modification() {
let dir = tempdir().unwrap();
let file_path = dir.path().join("test.json");
fs::write(&file_path, b"test content").unwrap();
let metadata = FileMetadata::from_file(&file_path).unwrap();
fs::write(&file_path, b"modified content").unwrap();
assert!(metadata.has_changed(&file_path).unwrap());
}
#[test]
fn test_size_change_detected() {
let dir = tempdir().unwrap();
let file_path = dir.path().join("test.json");
fs::write(&file_path, b"content1").unwrap();
let metadata = FileMetadata::from_file(&file_path).unwrap();
assert_eq!(metadata.size, 8);
fs::write(&file_path, b"content1_longer").unwrap();
assert!(metadata.has_changed(&file_path).unwrap());
}
}