use super::*;
#[cfg(feature = "bundled-embedder")]
use crate::{StatedClaim, STATED_CLAIM_EXTRACTOR};
fn test_key() -> [u8; 32] {
let mut key = [0u8; 32];
for (i, b) in key.iter_mut().enumerate() {
*b = (i as u8).wrapping_mul(7).wrapping_add(42);
}
key
}
fn record_plain(db: &YantrikDB, text: &str, meta: serde_json::Value) -> String {
db.record(
text,
"episodic",
0.5,
0.0,
604800.0,
&meta,
&vec_seed(1.0, 8),
"default",
0.8,
"general",
"user",
None,
)
.unwrap()
}
#[test]
fn revision_history_lists_prior_states_oldest_first() {
let db = YantrikDB::new(":memory:", 8).unwrap();
let rid = record_plain(&db, "original text", serde_json::json!({"k": "v"}));
assert!(db.revision_history(&rid).unwrap().is_empty());
db.correct(&rid, None, None, Some(0.9), None, "first")
.unwrap();
db.correct(&rid, None, None, Some(0.7), None, "second")
.unwrap();
let revs = db.revision_history(&rid).unwrap();
assert_eq!(revs.len(), 2);
assert_eq!(revs[0].revision_num, 1);
assert_eq!(revs[0].reason, "first");
assert_eq!(revs[0].rid, rid);
assert_eq!(revs[0].prior_text, "original text");
assert!(
(revs[0].prior_importance - 0.5).abs() < 1e-9,
"revision 1 archives the ORIGINAL importance"
);
assert_eq!(
revs[0].prior_metadata["k"], "v",
"prior metadata is parsed, not a string"
);
assert_eq!(revs[1].revision_num, 2);
assert_eq!(revs[1].reason, "second");
assert!(
(revs[1].prior_importance - 0.9).abs() < 1e-9,
"revision 2 archives the state revision 1 produced"
);
assert!(revs[0].applied_at <= revs[1].applied_at);
assert!(!revs[0].revision_id.is_empty());
}
#[test]
fn revision_history_is_empty_for_unknown_rids() {
let db = YantrikDB::new(":memory:", 8).unwrap();
assert!(db.revision_history("no-such-rid").unwrap().is_empty());
}
#[test]
fn revision_history_decrypts_prior_state_on_encrypted_stores() {
let key = test_key();
let db = YantrikDB::new_encrypted(":memory:", 8, &key).unwrap();
assert!(db.is_encrypted());
let rid = record_plain(&db, "secret original", serde_json::json!({"topic": "enc"}));
db.correct(&rid, None, None, Some(0.95), None, "bump")
.unwrap();
let stored: String = db
.conn()
.query_row(
"SELECT prior_text FROM record_revisions WHERE rid = ?1",
rusqlite::params![rid],
|r| r.get(0),
)
.unwrap();
assert_ne!(
stored, "secret original",
"revision rows are archived encrypted"
);
let revs = db.revision_history(&rid).unwrap();
assert_eq!(revs.len(), 1);
assert_eq!(revs[0].prior_text, "secret original");
assert_eq!(revs[0].prior_metadata["topic"], "enc");
}
#[cfg(feature = "bundled-embedder")]
fn claim(src: &str, rel: &str, dst: &str) -> StatedClaim {
StatedClaim {
src: src.into(),
rel_type: rel.into(),
dst: dst.into(),
polarity: 1,
valid_from: None,
valid_to: None,
}
}
#[cfg(feature = "bundled-embedder")]
#[test]
fn claims_for_memory_returns_the_memory_s_stated_claims_with_status() {
let db = YantrikDB::with_default(":memory:").unwrap();
let rid = db
.record_text(
"Pranab prefers Vim for editing Rust and reviews with Maria.",
"semantic",
0.5,
0.0,
604800.0,
&serde_json::json!({}),
"default",
0.8,
"general",
"user",
None,
)
.unwrap();
let other = db
.record_text(
"Unrelated note about the weather in Lisbon.",
"semantic",
0.5,
0.0,
604800.0,
&serde_json::json!({}),
"default",
0.8,
"general",
"user",
None,
)
.unwrap();
let report = db
.attach_claims(
&rid,
&[
claim("Pranab", "prefers", "Vim"),
claim("Pranab", "reviews with", "Maria"),
],
)
.unwrap();
assert_eq!(
report.accepted.len(),
2,
"both claims are grounded in the text"
);
let claims = db.claims_for_memory(&rid).unwrap();
assert_eq!(claims.len(), 2);
for c in &claims {
assert_eq!(c["source_memory_rid"], rid);
assert_eq!(c["status_suggestion"], "active");
assert_eq!(c["extractor"], STATED_CLAIM_EXTRACTOR);
assert_eq!(c["polarity"], 1);
}
let dsts: std::collections::HashSet<String> = claims
.iter()
.map(|c| c["dst"].as_str().unwrap().to_string())
.collect();
assert!(dsts.contains("Vim") && dsts.contains("Maria"));
assert!(db.claims_for_memory(&other).unwrap().is_empty());
assert!(db.claims_for_memory("no-such-rid").unwrap().is_empty());
}
#[cfg(feature = "bundled-embedder")]
#[test]
fn claims_for_memory_marks_a_denied_claim_negative() {
let db = YantrikDB::with_default(":memory:").unwrap();
let rid = db
.record_text(
"Pranab does not use Emacs for Rust.",
"semantic",
0.5,
0.0,
604800.0,
&serde_json::json!({}),
"default",
0.8,
"general",
"user",
None,
)
.unwrap();
let mut denied = claim("Pranab", "use", "Emacs");
denied.polarity = -1;
let report = db.attach_claims(&rid, &[denied]).unwrap();
assert_eq!(report.accepted.len(), 1);
let claims = db.claims_for_memory(&rid).unwrap();
assert_eq!(claims.len(), 1);
assert_eq!(claims[0]["polarity"], -1);
assert_eq!(claims[0]["status_suggestion"], "negative");
}
#[test]
fn memory_entities_lists_linked_names_sorted() {
let db = YantrikDB::new(":memory:", 8).unwrap();
let rid = record_plain(&db, "plain record", serde_json::json!({}));
assert!(db.memory_entities(&rid).unwrap().is_empty());
db.link_memory_entity(&rid, "Zeta Corp").unwrap();
db.link_memory_entity(&rid, "Acme").unwrap();
db.link_memory_entity(&rid, "Acme").unwrap(); assert_eq!(db.memory_entities(&rid).unwrap(), vec!["Acme", "Zeta Corp"]);
assert!(db.memory_entities("no-such-rid").unwrap().is_empty());
}