use engram::embedding::MockEmbeddingProvider;
use engram::memory::{Memory, RecallQuery};
use engram::scope::Scope;
fn scope(org: &str) -> Scope {
Scope::org(org)
}
fn user_scope(org: &str, user: &str) -> Scope {
Scope::user(org, user)
}
#[tokio::test]
async fn add_and_recall_fact() {
let mem = Memory::in_memory(Box::new(MockEmbeddingProvider::new(64)))
.await
.expect("in_memory");
mem.add_fact("The sky is blue", scope("acme"))
.await
.expect("add fact 1");
mem.add_fact("Rust is a systems programming language", scope("acme"))
.await
.expect("add fact 2");
let query = RecallQuery {
query: "blue sky".to_string(),
max_results: 5,
..Default::default()
};
let results = mem.recall(&query).await.expect("recall");
assert!(
!results.is_empty(),
"recall should return at least one fact"
);
}
#[tokio::test]
async fn add_fact_stores_in_all_three_stores() {
let mem = Memory::in_memory(Box::new(MockEmbeddingProvider::new(64)))
.await
.expect("in_memory");
mem.add_fact("Alice works at Acme Corp", scope("acme"))
.await
.expect("add fact");
let listed = mem
.list_facts(Some(scope("acme")))
.await
.expect("list_facts");
assert_eq!(listed.len(), 1, "fact should appear in fact store");
let results = mem
.recall(&RecallQuery {
query: "Alice".to_string(),
max_results: 5,
..Default::default()
})
.await
.expect("recall");
assert!(!results.is_empty(), "fact should appear in vector store");
}
#[tokio::test]
async fn forget_invalidates_fact() {
let mem = Memory::in_memory(Box::new(MockEmbeddingProvider::new(64)))
.await
.expect("in_memory");
let id = mem
.add_fact("Temporary note", scope("acme"))
.await
.expect("add fact");
let before = mem
.list_facts(Some(scope("acme")))
.await
.expect("list before");
assert_eq!(before.len(), 1);
mem.forget(id, Some("no longer needed"))
.await
.expect("forget");
let after = mem
.list_facts(Some(scope("acme")))
.await
.expect("list after");
assert_eq!(after.len(), 0, "invalidated fact should not appear in list");
}
#[tokio::test]
async fn delete_user_removes_all_data() {
let mem = Memory::in_memory(Box::new(MockEmbeddingProvider::new(64)))
.await
.expect("in_memory");
let u1 = user_scope("acme", "user-1");
let u2 = user_scope("acme", "user-2");
mem.add_fact("User 1 fact A", u1.clone())
.await
.expect("u1 a");
mem.add_fact("User 1 fact B", u1.clone())
.await
.expect("u1 b");
mem.add_fact("User 2 fact A", u2.clone())
.await
.expect("u2 a");
let deleted = mem.delete_user_data(u1.clone()).await.expect("delete u1");
assert_eq!(
deleted, 2,
"two facts belonging to user-1 should be deleted"
);
let u2_facts = mem
.list_facts(Some(u2.clone()))
.await
.expect("list u2 after delete");
assert_eq!(u2_facts.len(), 1, "user-2 fact should still exist");
let u1_facts = mem
.list_facts(Some(u1.clone()))
.await
.expect("list u1 after delete");
assert_eq!(u1_facts.len(), 0, "user-1 facts should be deleted");
}
#[tokio::test]
async fn stats_works() {
let mem = Memory::in_memory(Box::new(MockEmbeddingProvider::new(64)))
.await
.expect("in_memory");
mem.add_fact("Fact one", scope("acme"))
.await
.expect("add fact 1");
mem.add_fact("Fact two", scope("acme"))
.await
.expect("add fact 2");
let stats = mem.stats(Some(scope("acme"))).await.expect("stats");
assert_eq!(stats.total_facts, 2, "total_facts should be 2");
assert_eq!(stats.valid_facts, 2, "valid_facts should be 2");
}