use rose_squared_sdk::{PrivacyVault, MockStore, VolumeConfig};
use uuid::Uuid;
fn test_salt() -> [u8; 16] { [0xAB; 16] }
fn test_password() -> &'static str { "test-password-do-not-use-in-prod" }
fn new_vault() -> PrivacyVault {
PrivacyVault::new(test_password(), &test_salt(), VolumeConfig { n_max: 8 }).unwrap()
}
#[tokio::test]
async fn test_add_and_search_returns_doc() {
let mut vault = new_vault();
let store = MockStore::new();
let doc_id = Uuid::new_v4();
vault.add_document(&["invoice"], doc_id, &store).await.unwrap();
let results = vault.search("invoice", &store).await.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0], doc_id);
}
#[tokio::test]
async fn test_unknown_keyword_returns_empty() {
let vault = new_vault();
let store = MockStore::new();
let results = vault.search("ghost", &store).await.unwrap();
assert!(results.is_empty());
}
#[tokio::test]
async fn test_forward_security_new_doc_invisible_to_old_token() {
use rose_squared_sdk::protocol::search::SearchProtocol;
let mut vault = new_vault();
let store = MockStore::new();
let doc_a = Uuid::new_v4();
vault.add_document(&["report"], doc_a, &store).await.unwrap();
let proto = SearchProtocol::new(&vault.keys, &vault.state);
let token_a = proto.prepare_search("report").unwrap().unwrap();
let count_a = token_a.pairs.len();
let doc_b = Uuid::new_v4();
vault.add_document(&["report"], doc_b, &store).await.unwrap();
assert_eq!(count_a, 1, "old token must not see new doc (forward security)");
}
#[tokio::test]
async fn test_backward_security_delete_removes_doc() {
let mut vault = new_vault();
let store = MockStore::new();
let doc_a = Uuid::new_v4();
let doc_b = Uuid::new_v4();
vault.add_document(&["contract"], doc_a, &store).await.unwrap();
vault.add_document(&["contract"], doc_b, &store).await.unwrap();
vault.delete_document("contract", doc_a, &store).await.unwrap();
let results = vault.search("contract", &store).await.unwrap();
assert_eq!(results.len(), 1, "only doc_b should remain");
assert_eq!(results[0], doc_b);
assert!(!results.contains(&doc_a), "deleted doc must not appear");
}
#[tokio::test]
async fn test_delete_all_leaves_empty_results() {
let mut vault = new_vault();
let store = MockStore::new();
let doc = Uuid::new_v4();
vault.add_document(&["memo"], doc, &store).await.unwrap();
vault.delete_document("memo", doc, &store).await.unwrap();
let results = vault.search("memo", &store).await.unwrap();
assert!(results.is_empty());
}
#[tokio::test]
async fn test_state_round_trips_correctly() {
let mut vault = new_vault();
let store = MockStore::new();
let doc = Uuid::new_v4();
vault.add_document(&["budget"], doc, &store).await.unwrap();
let blob = vault.export_state().unwrap();
let vault2 = PrivacyVault::from_exported(
test_password(), &test_salt(), &blob, VolumeConfig { n_max: 8 }
).unwrap();
let results = vault2.search("budget", &store).await.unwrap();
assert_eq!(results, vec![doc], "restored vault must find the same doc");
}
#[tokio::test]
async fn test_multi_keyword_indexes_all() {
let mut vault = new_vault();
let store = MockStore::new();
let doc = Uuid::new_v4();
vault.add_document(&["alpha", "beta", "gamma"], doc, &store).await.unwrap();
for kw in &["alpha", "beta", "gamma"] {
let r = vault.search(kw, &store).await.unwrap();
assert_eq!(r, vec![doc], "keyword '{kw}' should find the doc");
}
}