use anyhow::Result;
use chrono::Utc;
use smugmug_cli::cache::hash_store::{HashStore, UploadedFile};
use smugmug_cli::uploader::calculate_file_hash;
use std::fs::File;
use std::io::Write;
#[test]
fn test_hash_calculation() -> Result<()> {
let test_file = std::env::temp_dir().join("test_hash_calc.txt");
let mut file = File::create(&test_file)?;
file.write_all(b"Test content for hashing")?;
drop(file);
let hash = calculate_file_hash(&test_file)?;
assert_eq!(hash.len(), 64);
assert!(hash.chars().all(|c: char| c.is_ascii_hexdigit()));
let hash2 = calculate_file_hash(&test_file)?;
assert_eq!(hash, hash2);
std::fs::remove_file(&test_file).ok();
Ok(())
}
#[test]
fn test_hash_store_operations() -> Result<()> {
let cache_dir = std::env::temp_dir().join(format!("smugmug_test_{}", std::process::id()));
std::fs::create_dir_all(&cache_dir)?;
let store = HashStore::new(cache_dir.to_str().unwrap())?;
let test_hash = "a".repeat(64);
let result = store.get(&test_hash)?;
assert!(result.is_none());
let uploaded_file = UploadedFile {
smugmug_uri: "https://api.smugmug.com/api/v2/image/12345".to_string(),
album_key: "TEST123".to_string(),
image_key: "IMG456".to_string(),
uploaded_at: Utc::now(),
file_size: 1024,
original_path: "/tmp/test.jpg".to_string(),
};
store.insert(&test_hash, uploaded_file.clone())?;
let retrieved = store.get(&test_hash)?;
assert!(retrieved.is_some());
let retrieved = retrieved.unwrap();
assert_eq!(retrieved.smugmug_uri, uploaded_file.smugmug_uri);
assert_eq!(retrieved.album_key, uploaded_file.album_key);
assert_eq!(retrieved.image_key, uploaded_file.image_key);
assert_eq!(retrieved.file_size, uploaded_file.file_size);
std::fs::remove_dir_all(&cache_dir).ok();
Ok(())
}
#[test]
fn test_cache_stats() -> Result<()> {
let cache_dir = std::env::temp_dir().join(format!("smugmug_test_stats_{}", std::process::id()));
std::fs::create_dir_all(&cache_dir)?;
let store = HashStore::new(cache_dir.to_str().unwrap())?;
let stats = store.stats()?;
assert_eq!(stats.total_entries, 0);
assert_eq!(stats.total_size, 0);
for i in 0..5 {
let hash = format!("{:0>64}", i); let file = UploadedFile {
smugmug_uri: format!("https://api.smugmug.com/api/v2/image/{}", i),
album_key: format!("ALBUM{}", i),
image_key: format!("IMG{}", i),
uploaded_at: Utc::now(),
file_size: (i + 1) * 100,
original_path: format!("/tmp/test{}.jpg", i),
};
store.insert(&hash, file)?;
}
let stats = store.stats()?;
assert_eq!(stats.total_entries, 5);
assert_eq!(stats.total_size, 100 + 200 + 300 + 400 + 500);
std::fs::remove_dir_all(&cache_dir).ok();
Ok(())
}
#[test]
fn test_cache_clear() -> Result<()> {
let cache_dir = std::env::temp_dir().join(format!("smugmug_test_clear_{}", std::process::id()));
std::fs::create_dir_all(&cache_dir)?;
let store = HashStore::new(cache_dir.to_str().unwrap())?;
let hash = "b".repeat(64);
let file = UploadedFile {
smugmug_uri: "https://api.smugmug.com/api/v2/image/test".to_string(),
album_key: "CLEAR".to_string(),
image_key: "TEST".to_string(),
uploaded_at: Utc::now(),
file_size: 500,
original_path: "/tmp/clear_test.jpg".to_string(),
};
store.insert(&hash, file)?;
let stats = store.stats()?;
assert_eq!(stats.total_entries, 1);
store.clear()?;
let stats = store.stats()?;
assert_eq!(stats.total_entries, 0);
let result = store.get(&hash)?;
assert!(result.is_none());
std::fs::remove_dir_all(&cache_dir).ok();
Ok(())
}
#[test]
fn test_thread_safety() -> Result<()> {
use std::sync::Arc;
use std::thread;
let cache_dir =
std::env::temp_dir().join(format!("smugmug_test_threads_{}", std::process::id()));
std::fs::create_dir_all(&cache_dir)?;
let store = Arc::new(HashStore::new(cache_dir.to_str().unwrap())?);
let mut handles = vec![];
for i in 0..5 {
let store_clone = Arc::clone(&store);
let handle = thread::spawn(move || -> Result<()> {
let hash = format!("{:0>64}", i);
let file = UploadedFile {
smugmug_uri: format!("https://api.smugmug.com/api/v2/image/{}", i),
album_key: format!("THREAD{}", i),
image_key: format!("IMG{}", i),
uploaded_at: Utc::now(),
file_size: (i + 1) * 100,
original_path: format!("/tmp/thread{}.jpg", i),
};
store_clone.insert(&hash, file)?;
Ok(())
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap()?;
}
let stats = store.stats()?;
assert_eq!(stats.total_entries, 5);
std::fs::remove_dir_all(&cache_dir).ok();
Ok(())
}