use chrono::{Duration, Timelike, Utc};
use tempfile::TempDir;
use uuid::Uuid;
use shodh_memory::embeddings::ner::{NerConfig, NeuralNer};
use shodh_memory::memory::{
compression::{ConsolidationResult, FactType, SemanticConsolidator, SemanticFact},
retrieval::{
AnticipatoryPrefetch, PrefetchContext, PrefetchReason, PrefetchResult, ReinforcementStats,
RetrievalOutcome,
},
types::{
CodeContext, ContextId, ConversationContext, DocumentContext, EnvironmentContext,
Experience, ExperienceType, ProjectContext, Query, RetrievalMode, RichContext,
SemanticContext, TemporalContext, UserContext,
},
Memory, MemoryConfig, MemoryId, MemorySystem,
};
fn setup_fallback_ner() -> NeuralNer {
let config = NerConfig::default();
NeuralNer::new_fallback(config)
}
fn create_experience_with_ner(
content: &str,
exp_type: ExperienceType,
ner: &NeuralNer,
) -> Experience {
let entities = ner.extract(content).unwrap_or_default();
let entity_names: Vec<String> = entities.iter().map(|e| e.text.clone()).collect();
Experience {
experience_type: exp_type,
content: content.to_string(),
entities: entity_names,
..Default::default()
}
}
fn create_test_system() -> (MemorySystem, TempDir) {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let config = MemoryConfig {
storage_path: temp_dir.path().to_path_buf(),
working_memory_size: 100,
session_memory_size_mb: 50,
max_heap_per_user_mb: 500,
auto_compress: false,
compression_age_days: 7,
importance_threshold: 0.3,
};
let system = MemorySystem::new(config, None).expect("Failed to create memory system");
(system, temp_dir)
}
fn create_experience(content: &str, exp_type: ExperienceType, entities: Vec<&str>) -> Experience {
Experience {
experience_type: exp_type,
content: content.to_string(),
entities: entities.into_iter().map(|s| s.to_string()).collect(),
..Default::default()
}
}
fn create_learning_experience(content: &str, entities: Vec<&str>) -> Experience {
create_experience(content, ExperienceType::Learning, entities)
}
fn create_decision_experience(content: &str, entities: Vec<&str>) -> Experience {
create_experience(content, ExperienceType::Decision, entities)
}
fn create_error_experience(content: &str, entities: Vec<&str>) -> Experience {
create_experience(content, ExperienceType::Error, entities)
}
fn create_conversation_experience(content: &str, entities: Vec<&str>) -> Experience {
create_experience(content, ExperienceType::Conversation, entities)
}
fn create_memory(
content: &str,
exp_type: ExperienceType,
entities: Vec<&str>,
importance: f32,
) -> Memory {
let exp = create_experience(content, exp_type, entities);
Memory::new(
MemoryId(Uuid::new_v4()),
exp,
importance,
None,
None,
None,
None,
)
}
fn create_rich_context(project_id: Option<String>, code_ctx: Option<CodeContext>) -> RichContext {
let now = Utc::now();
RichContext {
id: ContextId(Uuid::new_v4()),
conversation: ConversationContext::default(),
user: UserContext::default(),
project: ProjectContext {
project_id,
..Default::default()
},
temporal: TemporalContext::default(),
semantic: SemanticContext::default(),
code: code_ctx.unwrap_or_default(),
document: DocumentContext::default(),
environment: EnvironmentContext::default(),
emotional: Default::default(),
source: Default::default(),
episode: Default::default(),
parent: None,
embeddings: None,
decay_rate: 0.1,
created_at: now,
updated_at: now,
}
}
#[test]
fn test_retrieval_outcome_enum_values() {
let helpful = RetrievalOutcome::Helpful;
let misleading = RetrievalOutcome::Misleading;
let neutral = RetrievalOutcome::Neutral;
assert!(helpful != misleading);
assert!(helpful != neutral);
assert!(misleading != neutral);
}
#[test]
fn test_retrieval_outcome_default() {
let default = RetrievalOutcome::default();
assert_eq!(default, RetrievalOutcome::Neutral);
}
#[test]
fn test_tracked_retrieval_creation() {
let (mut system, _temp_dir) = create_test_system();
let exp1 = create_learning_experience(
"Rust ownership prevents memory leaks",
vec!["rust", "ownership"],
);
let exp2 = create_learning_experience(
"The borrow checker enforces safety",
vec!["rust", "borrow_checker"],
);
system.remember(exp1, None).expect("Failed to record");
system.remember(exp2, None).expect("Failed to record");
let query = Query {
query_text: Some("rust memory safety".to_string()),
max_results: 5,
..Default::default()
};
let tracked = system
.recall_tracked(&query)
.expect("Failed to retrieve tracked");
assert!(!tracked.retrieval_id.is_empty());
assert!(!tracked.memories.is_empty());
assert!(tracked.query_fingerprint != 0);
}
#[test]
fn test_tracked_retrieval_memory_ids() {
let (mut system, _temp_dir) = create_test_system();
let exp = create_learning_experience("Test content", vec!["test"]);
let id = system.remember(exp, None).expect("Failed to record");
let query = Query {
query_text: Some("test content".to_string()),
max_results: 5,
..Default::default()
};
let tracked = system.recall_tracked(&query).expect("Failed");
let ids = tracked.memory_ids();
assert!(ids.iter().any(|i| i == &id));
}
#[test]
fn test_reinforce_helpful_outcome() {
let (mut system, _temp_dir) = create_test_system();
let exp1 =
create_learning_experience("API endpoint for user authentication", vec!["api", "auth"]);
let exp2 = create_learning_experience("JWT token validation process", vec!["jwt", "auth"]);
let exp3 = create_learning_experience("OAuth2 flow implementation", vec!["oauth", "auth"]);
let id1 = system.remember(exp1, None).expect("Failed");
let id2 = system.remember(exp2, None).expect("Failed");
let id3 = system.remember(exp3, None).expect("Failed");
let stats = system
.reinforce_recall(
&[id1.clone(), id2.clone(), id3.clone()],
RetrievalOutcome::Helpful,
)
.expect("Failed to reinforce");
assert_eq!(stats.memories_processed, 3);
assert_eq!(stats.importance_boosts, 3);
assert_eq!(stats.importance_decays, 0);
assert_eq!(stats.associations_strengthened, 3);
assert_eq!(stats.outcome, RetrievalOutcome::Helpful);
}
#[test]
fn test_reinforce_misleading_outcome() {
let (mut system, _temp_dir) = create_test_system();
let exp = create_learning_experience("Misleading information", vec!["test"]);
let id = system.remember(exp, None).expect("Failed");
let initial_importance = {
let query = Query {
query_text: Some("misleading".to_string()),
max_results: 1,
..Default::default()
};
let results = system.recall(&query).expect("Failed");
results[0].importance()
};
for _ in 0..5 {
let stats = system
.reinforce_recall(&[id.clone()], RetrievalOutcome::Misleading)
.expect("Failed");
assert_eq!(stats.memories_processed, 1);
assert_eq!(stats.importance_decays, 1);
assert_eq!(stats.importance_boosts, 0);
assert_eq!(stats.associations_strengthened, 0);
}
let query = Query {
query_text: Some("misleading".to_string()),
max_results: 1,
..Default::default()
};
let results = system.recall(&query).expect("Failed");
let final_importance = results[0].importance();
assert!(
final_importance < initial_importance * 0.7,
"importance should decay: {} < {} * 0.7 = {}",
final_importance,
initial_importance,
initial_importance * 0.7
);
}
#[test]
fn test_reinforce_neutral_outcome() {
let (mut system, _temp_dir) = create_test_system();
let exp1 = create_learning_experience("First neutral memory", vec!["neutral"]);
let exp2 = create_learning_experience("Second neutral memory", vec!["neutral"]);
let id1 = system.remember(exp1, None).expect("Failed");
let id2 = system.remember(exp2, None).expect("Failed");
let stats = system
.reinforce_recall(&[id1, id2], RetrievalOutcome::Neutral)
.expect("Failed");
assert_eq!(stats.memories_processed, 2);
assert_eq!(stats.associations_strengthened, 1);
assert_eq!(stats.importance_boosts, 0);
assert_eq!(stats.importance_decays, 0);
}
#[test]
fn test_reinforce_empty_list() {
let (system, _temp_dir) = create_test_system();
let stats = system
.reinforce_recall(&[], RetrievalOutcome::Helpful)
.expect("Failed");
assert_eq!(stats.memories_processed, 0);
assert_eq!(stats.associations_strengthened, 0);
}
#[test]
fn test_reinforce_tracked_convenience() {
let (mut system, _temp_dir) = create_test_system();
let exp = create_learning_experience("Tracked memory test", vec!["tracked"]);
system.remember(exp, None).expect("Failed");
let query = Query {
query_text: Some("tracked memory".to_string()),
max_results: 5,
..Default::default()
};
let tracked = system.recall_tracked(&query).expect("Failed");
let stats = system
.reinforce_recall_tracked(&tracked, RetrievalOutcome::Helpful)
.expect("Failed");
assert!(stats.memories_processed > 0);
}
#[test]
fn test_importance_boost_cumulative() {
let (mut system, _temp_dir) = create_test_system();
let exp = create_learning_experience("Memory that gets boosted multiple times", vec!["boost"]);
let id = system.remember(exp, None).expect("Failed");
let mut total_boosts = 0;
for _ in 0..10 {
let stats = system
.reinforce_recall(&[id.clone()], RetrievalOutcome::Helpful)
.expect("Failed");
assert_eq!(stats.importance_boosts, 1);
total_boosts += stats.importance_boosts;
}
assert_eq!(total_boosts, 10);
}
#[test]
fn test_importance_decay_floor() {
let (mut system, _temp_dir) = create_test_system();
let exp = create_learning_experience("Memory that gets decayed to minimum", vec!["decay"]);
let id = system.remember(exp, None).expect("Failed");
let mut total_decays = 0;
for _ in 0..20 {
let stats = system
.reinforce_recall(&[id.clone()], RetrievalOutcome::Misleading)
.expect("Failed");
assert_eq!(stats.importance_decays, 1);
total_decays += 1;
}
assert_eq!(total_decays, 20);
}
#[test]
fn test_coactivation_strengthens_graph() {
let (mut system, _temp_dir) = create_test_system();
let exp1 = create_learning_experience("Database connection pooling", vec!["database"]);
let exp2 = create_learning_experience("Query optimization techniques", vec!["database"]);
let exp3 = create_learning_experience("Index design patterns", vec!["database"]);
let id1 = system.remember(exp1, None).expect("Failed");
let id2 = system.remember(exp2, None).expect("Failed");
let id3 = system.remember(exp3, None).expect("Failed");
let initial_stats = system.graph_stats();
for _ in 0..5 {
system
.reinforce_recall(
&[id1.clone(), id2.clone(), id3.clone()],
RetrievalOutcome::Helpful,
)
.expect("Failed");
}
let final_stats = system.graph_stats();
assert!(final_stats.edge_count >= initial_stats.edge_count);
}
#[test]
fn test_semantic_consolidator_creation() {
let _consolidator = SemanticConsolidator::new();
}
#[test]
fn test_semantic_consolidator_with_thresholds() {
let _consolidator = SemanticConsolidator::with_thresholds(3, 14);
}
#[test]
fn test_consolidate_empty_memories() {
let consolidator = SemanticConsolidator::new();
let result = consolidator.consolidate(&[]);
assert_eq!(result.memories_processed, 0);
assert_eq!(result.facts_extracted, 0);
}
#[test]
fn test_consolidate_young_memories() {
let consolidator = SemanticConsolidator::new();
let memories: Vec<Memory> = vec![
create_memory(
"Young memory 1",
ExperienceType::Learning,
vec!["test"],
0.5,
),
create_memory(
"Young memory 2",
ExperienceType::Learning,
vec!["test"],
0.5,
),
];
let result = consolidator.consolidate(&memories);
assert_eq!(result.memories_processed, 2);
assert_eq!(result.facts_extracted, 0);
}
#[test]
fn test_fact_type_classification() {
let pref_pattern = "preference: use tabs over spaces";
let fact_type = classify_pattern(pref_pattern);
assert_eq!(fact_type, FactType::Preference);
let cap_pattern = "the system can handle 1000 requests per second";
let fact_type = classify_pattern(cap_pattern);
assert_eq!(fact_type, FactType::Capability);
let rel_pattern = "authentication relates to user sessions";
let fact_type = classify_pattern(rel_pattern);
assert_eq!(fact_type, FactType::Relationship);
let proc_pattern = "to deploy the application run npm build";
let fact_type = classify_pattern(proc_pattern);
assert_eq!(fact_type, FactType::Procedure);
let def_pattern = "a mutex is a synchronization primitive";
let fact_type = classify_pattern(def_pattern);
assert_eq!(fact_type, FactType::Definition);
}
fn classify_pattern(pattern: &str) -> FactType {
let lower = pattern.to_lowercase();
if lower.starts_with("preference:") || lower.contains("prefer") || lower.contains("like") {
FactType::Preference
} else if lower.contains("can ") || lower.contains("able to") || lower.contains("supports") {
FactType::Capability
} else if lower.contains("relates to")
|| lower.contains("depends on")
|| lower.contains("connects")
{
FactType::Relationship
} else if lower.contains("to ")
|| lower.contains("run ")
|| lower.contains("execute")
|| lower.contains("deploy")
{
FactType::Procedure
} else if lower.contains(" is ") || lower.contains(" are ") || lower.contains("means") {
FactType::Definition
} else {
FactType::Pattern
}
}
#[test]
fn test_semantic_fact_structure() {
let fact = SemanticFact {
id: "fact_001".to_string(),
fact: "Users prefer dark mode".to_string(),
confidence: 0.85,
support_count: 3,
source_memories: vec![MemoryId(Uuid::new_v4()), MemoryId(Uuid::new_v4())],
related_entities: vec!["user".to_string(), "dark_mode".to_string()],
created_at: Utc::now(),
last_reinforced: Utc::now(),
fact_type: FactType::Preference,
};
assert_eq!(fact.id, "fact_001");
assert_eq!(fact.confidence, 0.85);
assert_eq!(fact.support_count, 3);
assert_eq!(fact.source_memories.len(), 2);
assert_eq!(fact.fact_type, FactType::Preference);
}
#[test]
fn test_reinforce_fact_increases_confidence() {
let consolidator = SemanticConsolidator::new();
let mut fact = SemanticFact {
id: "test_fact".to_string(),
fact: "Test fact".to_string(),
confidence: 0.5,
support_count: 2,
source_memories: vec![],
related_entities: vec![],
created_at: Utc::now(),
last_reinforced: Utc::now() - Duration::days(1),
fact_type: FactType::Pattern,
};
let initial_confidence = fact.confidence;
let initial_support = fact.support_count;
let memory = create_memory(
"Supporting evidence",
ExperienceType::Learning,
vec!["test"],
0.5,
);
consolidator.reinforce_fact(&mut fact, &memory);
assert!(fact.confidence > initial_confidence);
assert_eq!(fact.support_count, initial_support + 1);
}
#[test]
fn test_reinforce_fact_adds_source() {
let consolidator = SemanticConsolidator::new();
let mut fact = SemanticFact {
id: "test_fact".to_string(),
fact: "Test".to_string(),
confidence: 0.5,
support_count: 1,
source_memories: vec![],
related_entities: vec![],
created_at: Utc::now(),
last_reinforced: Utc::now(),
fact_type: FactType::Pattern,
};
let memory = create_memory("Evidence", ExperienceType::Learning, vec!["test"], 0.5);
assert!(fact.source_memories.is_empty());
consolidator.reinforce_fact(&mut fact, &memory);
assert_eq!(fact.source_memories.len(), 1);
}
#[test]
fn test_should_decay_fact_old_unreinforced() {
let consolidator = SemanticConsolidator::new();
let old_fact = SemanticFact {
id: "old_fact".to_string(),
fact: "Old unused fact".to_string(),
confidence: 0.1,
support_count: 1,
source_memories: vec![],
related_entities: vec![],
created_at: Utc::now() - Duration::days(365),
last_reinforced: Utc::now() - Duration::days(100),
fact_type: FactType::Pattern,
};
assert!(consolidator.should_decay_fact(&old_fact));
}
#[test]
fn test_should_not_decay_high_confidence_fact() {
let consolidator = SemanticConsolidator::new();
let strong_fact = SemanticFact {
id: "strong_fact".to_string(),
fact: "Well-established fact".to_string(),
confidence: 0.95,
support_count: 10,
source_memories: vec![],
related_entities: vec![],
created_at: Utc::now() - Duration::days(30),
last_reinforced: Utc::now() - Duration::days(30),
fact_type: FactType::Definition,
};
assert!(!consolidator.should_decay_fact(&strong_fact));
}
#[test]
fn test_fact_type_default() {
let default = FactType::default();
assert_eq!(default, FactType::Pattern);
}
#[test]
fn test_consolidation_result_structure() {
let result = ConsolidationResult {
memories_processed: 10,
facts_extracted: 3,
facts_reinforced: 5,
new_fact_ids: vec!["f1".to_string(), "f2".to_string(), "f3".to_string()],
new_facts: Vec::new(),
};
assert_eq!(result.memories_processed, 10);
assert_eq!(result.facts_extracted, 3);
assert_eq!(result.facts_reinforced, 5);
assert_eq!(result.new_fact_ids.len(), 3);
}
#[test]
fn test_prefetch_context_default() {
let ctx = PrefetchContext::default();
assert!(ctx.project_id.is_none());
assert!(ctx.current_file.is_none());
assert!(ctx.recent_entities.is_empty());
assert!(ctx.hour_of_day.is_none());
assert!(ctx.day_of_week.is_none());
assert!(ctx.task_type.is_none());
}
#[test]
fn test_prefetch_context_from_current_time() {
let ctx = PrefetchContext::from_current_time();
assert!(ctx.hour_of_day.is_some());
assert!(ctx.day_of_week.is_some());
let hour = ctx.hour_of_day.unwrap();
assert!(hour <= 23);
let day = ctx.day_of_week.unwrap();
assert!(day <= 6);
}
#[test]
fn test_anticipatory_prefetch_creation() {
let _prefetch = AnticipatoryPrefetch::new();
}
#[test]
fn test_anticipatory_prefetch_with_limit() {
let _prefetch = AnticipatoryPrefetch::with_limit(50);
}
#[test]
fn test_generate_prefetch_query_project() {
let prefetch = AnticipatoryPrefetch::new();
let ctx = PrefetchContext {
project_id: Some("auth-service".to_string()),
..Default::default()
};
let query = prefetch.generate_prefetch_query(&ctx);
assert!(query.is_some());
let q = query.unwrap();
assert!(q.query_text.is_some());
assert!(q.query_text.as_ref().unwrap().contains("auth-service"));
}
#[test]
fn test_generate_prefetch_query_entities() {
let prefetch = AnticipatoryPrefetch::new();
let ctx = PrefetchContext {
recent_entities: vec!["User".to_string(), "Session".to_string()],
..Default::default()
};
let query = prefetch.generate_prefetch_query(&ctx);
assert!(query.is_some());
let q = query.unwrap();
assert!(q.query_text.is_some());
let text = q.query_text.as_ref().unwrap();
assert!(text.contains("User") || text.contains("Session"));
}
#[test]
fn test_generate_prefetch_query_file() {
let prefetch = AnticipatoryPrefetch::new();
let ctx = PrefetchContext {
current_file: Some("/src/auth/login.rs".to_string()),
..Default::default()
};
let query = prefetch.generate_prefetch_query(&ctx);
assert!(query.is_some());
let q = query.unwrap();
assert!(q.query_text.is_some());
assert!(q.query_text.as_ref().unwrap().contains("login.rs"));
}
#[test]
fn test_generate_prefetch_query_temporal() {
let prefetch = AnticipatoryPrefetch::new();
let ctx = PrefetchContext {
hour_of_day: Some(14),
day_of_week: Some(1),
..Default::default()
};
let query = prefetch.generate_prefetch_query(&ctx);
assert!(query.is_some());
let q = query.unwrap();
assert!(q.time_range.is_some());
assert_eq!(q.retrieval_mode, RetrievalMode::Temporal);
}
#[test]
fn test_generate_prefetch_query_empty_context() {
let prefetch = AnticipatoryPrefetch::new();
let ctx = PrefetchContext::default();
let query = prefetch.generate_prefetch_query(&ctx);
assert!(query.is_none());
}
#[test]
fn test_prefetch_priority_order() {
let prefetch = AnticipatoryPrefetch::new();
let ctx = PrefetchContext {
project_id: Some("priority-project".to_string()),
recent_entities: vec!["Entity1".to_string()],
current_file: Some("file.rs".to_string()),
hour_of_day: Some(10),
day_of_week: Some(2),
..Default::default()
};
let query = prefetch.generate_prefetch_query(&ctx);
assert!(query.is_some());
let q = query.unwrap();
assert!(q.query_text.as_ref().unwrap().contains("priority-project"));
}
#[test]
fn test_relevance_score_project_match() {
let prefetch = AnticipatoryPrefetch::new();
let mut exp = create_learning_experience("Auth implementation", vec!["auth"]);
exp.context = Some(create_rich_context(Some("auth-project".to_string()), None));
let memory = Memory::new(MemoryId(Uuid::new_v4()), exp, 0.7, None, None, None, None);
let ctx = PrefetchContext {
project_id: Some("auth-project".to_string()),
..Default::default()
};
let score = prefetch.relevance_score(&memory, &ctx);
assert!(score >= 0.4);
}
#[test]
fn test_relevance_score_entity_overlap() {
let prefetch = AnticipatoryPrefetch::new();
let exp = create_learning_experience("User authentication", vec!["User", "Auth"]);
let memory = Memory::new(MemoryId(Uuid::new_v4()), exp, 0.7, None, None, None, None);
let ctx = PrefetchContext {
recent_entities: vec!["User".to_string(), "Session".to_string()],
..Default::default()
};
let score = prefetch.relevance_score(&memory, &ctx);
assert!(score > 0.0);
}
#[test]
fn test_relevance_score_file_mention() {
let prefetch = AnticipatoryPrefetch::new();
let exp = create_learning_experience(
"The login.rs file handles user authentication",
vec!["login", "auth"],
);
let memory = Memory::new(MemoryId(Uuid::new_v4()), exp, 0.7, None, None, None, None);
let ctx = PrefetchContext {
current_file: Some("login.rs".to_string()),
..Default::default()
};
let score = prefetch.relevance_score(&memory, &ctx);
assert!(score > 0.0);
}
#[test]
fn test_relevance_score_recency_boost() {
let prefetch = AnticipatoryPrefetch::new();
let exp = create_learning_experience("Recent memory", vec!["recent"]);
let memory = Memory::new(MemoryId(Uuid::new_v4()), exp, 0.7, None, None, None, None);
let ctx = PrefetchContext::default();
let score = prefetch.relevance_score(&memory, &ctx);
assert!(score >= 0.1);
}
#[test]
fn test_relevance_score_maximum() {
let prefetch = AnticipatoryPrefetch::new();
let mut exp =
create_learning_experience("The login.rs file is important", vec!["User", "Auth"]);
let code_ctx = CodeContext {
current_file: Some("login.rs".to_string()),
related_files: vec!["login.rs".to_string()],
..Default::default()
};
exp.context = Some(create_rich_context(
Some("test-project".to_string()),
Some(code_ctx),
));
let memory = Memory::new(MemoryId(Uuid::new_v4()), exp, 0.7, None, None, None, None);
let ctx = PrefetchContext {
project_id: Some("test-project".to_string()),
recent_entities: vec!["User".to_string(), "Auth".to_string()],
current_file: Some("login.rs".to_string()),
hour_of_day: Some(Utc::now().hour()),
..Default::default()
};
let score = prefetch.relevance_score(&memory, &ctx);
assert!(score <= 1.0);
}
#[test]
fn test_prefetch_result_structure() {
let result = PrefetchResult {
prefetched_ids: vec![MemoryId(Uuid::new_v4()), MemoryId(Uuid::new_v4())],
reason: PrefetchReason::Project("test".to_string()),
cache_hits: 1,
fetches: 1,
};
assert_eq!(result.prefetched_ids.len(), 2);
assert_eq!(result.cache_hits, 1);
assert_eq!(result.fetches, 1);
}
#[test]
fn test_prefetch_reason_variants() {
let _project = PrefetchReason::Project("test".to_string());
let _files = PrefetchReason::RelatedFiles;
let _entities = PrefetchReason::SharedEntities;
let _temporal = PrefetchReason::TemporalPattern;
let _assoc = PrefetchReason::AssociatedMemories;
let _query = PrefetchReason::QueryPrediction;
let _mixed = PrefetchReason::Mixed;
}
#[test]
fn test_prefetch_reason_default() {
let default = PrefetchReason::default();
assert!(matches!(default, PrefetchReason::Mixed));
}
#[test]
fn test_adaptive_memory_workflow() {
let (mut system, _temp_dir) = create_test_system();
let experiences = vec![
create_learning_experience(
"Rust ownership model prevents memory bugs",
vec!["rust", "ownership"],
),
create_learning_experience(
"The borrow checker validates references at compile time",
vec!["rust", "borrow_checker"],
),
create_decision_experience(
"Decided to use async/await for concurrency",
vec!["rust", "async"],
),
create_error_experience(
"Error: lifetime mismatch in function return",
vec!["rust", "lifetime"],
),
];
let mut ids = Vec::new();
for exp in experiences {
ids.push(system.remember(exp, None).expect("Failed to record"));
}
let query = Query {
query_text: Some("rust memory safety borrow".to_string()),
max_results: 5,
..Default::default()
};
let tracked = system.recall_tracked(&query).expect("Failed");
assert!(!tracked.memories.is_empty());
let stats = system
.reinforce_recall_tracked(&tracked, RetrievalOutcome::Helpful)
.expect("Failed");
assert!(stats.memories_processed > 0);
let graph_stats = system.graph_stats();
assert!(graph_stats.node_count > 0 || graph_stats.edge_count >= 0);
let prefetch = AnticipatoryPrefetch::new();
let ctx = PrefetchContext {
recent_entities: vec!["rust".to_string()],
..Default::default()
};
let prefetch_query = prefetch.generate_prefetch_query(&ctx);
assert!(prefetch_query.is_some());
}
#[test]
fn test_graph_maintenance() {
let (mut system, _temp_dir) = create_test_system();
let exp1 = create_learning_experience("First memory", vec!["test"]);
let exp2 = create_learning_experience("Second memory", vec!["test"]);
let id1 = system.remember(exp1, None).expect("Failed");
let id2 = system.remember(exp2, None).expect("Failed");
system
.reinforce_recall(&[id1, id2], RetrievalOutcome::Helpful)
.expect("Failed");
system.graph_maintenance();
let stats = system.graph_stats();
assert!(stats.node_count >= 0);
}
#[test]
fn test_reinforcement_stats_structure() {
let stats = ReinforcementStats {
memories_processed: 5,
associations_strengthened: 10,
importance_boosts: 3,
importance_decays: 2,
outcome: RetrievalOutcome::Helpful,
persist_failures: 0,
};
assert_eq!(stats.memories_processed, 5);
assert_eq!(stats.associations_strengthened, 10);
assert_eq!(stats.importance_boosts, 3);
assert_eq!(stats.importance_decays, 2);
assert_eq!(stats.outcome, RetrievalOutcome::Helpful);
assert_eq!(stats.persist_failures, 0);
}
#[test]
fn test_high_volume_reinforcement() {
let (mut system, _temp_dir) = create_test_system();
let mut ids = Vec::new();
for i in 0..50 {
let exp =
create_learning_experience(&format!("High volume memory {i}"), vec!["stress", "test"]);
ids.push(system.remember(exp, None).expect("Failed"));
}
for chunk in ids.chunks(10) {
let stats = system
.reinforce_recall(chunk, RetrievalOutcome::Helpful)
.expect("Failed");
assert!(stats.memories_processed > 0);
}
}
#[test]
fn test_rapid_feedback_cycles() {
let (mut system, _temp_dir) = create_test_system();
for i in 0..20 {
let exp = create_learning_experience(&format!("Cycle {i}"), vec!["cycle"]);
let _id = system.remember(exp, None).expect("Failed");
let query = Query {
query_text: Some(format!("cycle {i}")),
max_results: 5,
..Default::default()
};
let tracked = system.recall_tracked(&query).expect("Failed");
let outcome = if i % 3 == 0 {
RetrievalOutcome::Helpful
} else if i % 3 == 1 {
RetrievalOutcome::Misleading
} else {
RetrievalOutcome::Neutral
};
system
.reinforce_recall_tracked(&tracked, outcome)
.expect("Failed");
}
let stats = system.stats();
assert!(stats.total_memories >= 20);
}