use leann_core::sync::{FileSynchronizer, MerkleTree, hash_data};
#[test]
fn test_merkle_tree_no_changes() {
let mut tree1 = MerkleTree::new();
let root1 = tree1.add_node("root_data_abc", None, None);
tree1.add_node("file_a", Some(&root1), Some("file_a.txt"));
tree1.add_node("file_b", Some(&root1), Some("file_b.txt"));
let mut tree2 = MerkleTree::new();
let root2 = tree2.add_node("root_data_abc", None, None);
tree2.add_node("file_a", Some(&root2), Some("file_a.txt"));
tree2.add_node("file_b", Some(&root2), Some("file_b.txt"));
let (added, removed, modified) = tree1.compare_with(&tree2);
assert!(added.is_empty(), "Expected no added files");
assert!(removed.is_empty(), "Expected no removed files");
assert!(modified.is_empty(), "Expected no modified files");
}
#[test]
fn test_merkle_tree_detects_added_file() {
let mut tree1 = MerkleTree::new();
let root1 = tree1.add_node("root_old", None, None);
tree1.add_node("file_a", Some(&root1), Some("file_a.txt"));
let mut tree2 = MerkleTree::new();
let root2 = tree2.add_node("root_new", None, None);
tree2.add_node("file_a", Some(&root2), Some("file_a.txt"));
tree2.add_node("file_b", Some(&root2), Some("file_b.txt"));
let (added, _removed, _modified) = tree1.compare_with(&tree2);
assert!(
added.contains(&"file_b".to_string()),
"Should detect file_b as added, got: {:?}",
added
);
}
#[test]
fn test_merkle_tree_detects_removed_file() {
let mut tree1 = MerkleTree::new();
let root1 = tree1.add_node("root_old", None, None);
tree1.add_node("file_a", Some(&root1), Some("file_a.txt"));
tree1.add_node("file_b", Some(&root1), Some("file_b.txt"));
let mut tree2 = MerkleTree::new();
let root2 = tree2.add_node("root_new", None, None);
tree2.add_node("file_a", Some(&root2), Some("file_a.txt"));
let (_added, removed, _modified) = tree1.compare_with(&tree2);
assert!(
removed.contains(&"file_b".to_string()),
"Should detect file_b as removed, got: {:?}",
removed
);
}
#[test]
fn test_hash_data_consistent() {
let h1 = hash_data(b"hello world");
let h2 = hash_data(b"hello world");
assert_eq!(h1, h2, "Same input should produce same hash");
let h3 = hash_data(b"different data");
assert_ne!(h1, h3, "Different input should produce different hash");
assert_eq!(h1.len(), 64, "SHA-256 hex should be 64 chars");
}
#[test]
fn test_file_synchronizer_no_changes() {
let dir = tempfile::tempdir().unwrap();
std::fs::write(dir.path().join("a.txt"), "content a").unwrap();
std::fs::write(dir.path().join("b.txt"), "content b").unwrap();
let mut sync = FileSynchronizer::new(
dir.path(),
vec![".git".to_string()],
vec![".txt".to_string()],
)
.unwrap();
let (added, removed, _modified) = sync.check_for_changes().unwrap();
assert!(added.is_empty(), "No files should be added");
assert!(removed.is_empty(), "No files should be removed");
}
#[test]
fn test_file_synchronizer_detects_added_file() {
let dir = tempfile::tempdir().unwrap();
std::fs::write(dir.path().join("a.txt"), "content a").unwrap();
let mut sync = FileSynchronizer::new(
dir.path(),
vec![".git".to_string()],
vec![".txt".to_string()],
)
.unwrap();
std::fs::write(dir.path().join("b.txt"), "content b").unwrap();
let (added, removed, _modified) = sync.check_for_changes().unwrap();
assert!(
!added.is_empty() || !removed.is_empty(),
"Should detect some change after adding a file"
);
}
#[test]
fn test_file_synchronizer_detects_modified_file() {
let dir = tempfile::tempdir().unwrap();
std::fs::write(dir.path().join("a.txt"), "original content").unwrap();
let mut sync = FileSynchronizer::new(
dir.path(),
vec![".git".to_string()],
vec![".txt".to_string()],
)
.unwrap();
std::fs::write(dir.path().join("a.txt"), "modified content").unwrap();
let (added, removed, modified) = sync.check_for_changes().unwrap();
let has_changes = !added.is_empty() || !removed.is_empty() || !modified.is_empty();
assert!(has_changes, "Should detect change after modifying a file");
}
#[test]
fn test_merkle_tree_detects_modified_file() {
let mut tree1 = MerkleTree::new();
let root1 = tree1.add_node("root_v1", None, None);
tree1.add_node("file_a", Some(&root1), Some("hash_old_content"));
let mut tree2 = MerkleTree::new();
let root2 = tree2.add_node("root_v2", None, None);
tree2.add_node("file_a", Some(&root2), Some("hash_new_content"));
let (added, removed, modified) = tree1.compare_with(&tree2);
assert!(added.is_empty(), "No files should be added: {:?}", added);
assert!(
removed.is_empty(),
"No files should be removed: {:?}",
removed
);
assert!(
modified.contains(&"file_a".to_string()),
"Should detect file_a as modified, got: {:?}",
modified
);
}
#[test]
fn test_merkle_tree_combined_changes() {
let mut tree1 = MerkleTree::new();
let root1 = tree1.add_node("root_old", None, None);
tree1.add_node("file_a", Some(&root1), Some("hash_a_v1"));
tree1.add_node("file_b", Some(&root1), Some("hash_b_v1"));
tree1.add_node("file_c", Some(&root1), Some("hash_c_old"));
let mut tree2 = MerkleTree::new();
let root2 = tree2.add_node("root_new", None, None);
tree2.add_node("file_a", Some(&root2), Some("hash_a_v1"));
tree2.add_node("file_c", Some(&root2), Some("hash_c_new"));
tree2.add_node("file_d", Some(&root2), Some("hash_d_v1"));
let (added, removed, modified) = tree1.compare_with(&tree2);
assert!(
added.contains(&"file_d".to_string()),
"file_d should be added, got added: {:?}",
added
);
assert!(
removed.contains(&"file_b".to_string()),
"file_b should be removed, got removed: {:?}",
removed
);
assert!(
modified.contains(&"file_a".to_string()),
"file_a should be in modified (exists in both): {:?}",
modified
);
assert!(
modified.contains(&"file_c".to_string()),
"file_c should be in modified (exists in both): {:?}",
modified
);
}