mod consolidation_tests;
mod episodic_memory_tests;
mod memory_integration_tests;
mod semantic_memory_tests;
mod working_memory_tests;
use ronn_core::Tensor;
use ronn_core::types::{DataType, TensorLayout};
use ronn_memory::{ConsolidationResult, Episode, MultiTierMemory};
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
#[test]
fn test_memory_creation() {
let memory = MultiTierMemory::new();
let stats = memory.stats();
assert_eq!(stats.working_items, 0);
assert_eq!(stats.episodic_episodes, 0);
assert_eq!(stats.semantic_concepts, 0);
}
#[test]
fn test_store_and_retrieve_low_importance() -> Result<()> {
let mut memory = MultiTierMemory::new();
let data = vec![1.0f32, 2.0, 3.0, 4.0];
let tensor = Tensor::from_data(data, vec![1, 4], DataType::F32, TensorLayout::RowMajor)?;
let id = memory.store(tensor.clone(), 0.3)?;
let retrieved = memory.retrieve(id)?;
assert!(retrieved.is_some());
let stats = memory.stats();
assert_eq!(stats.working_items, 1);
assert_eq!(stats.episodic_episodes, 0);
Ok(())
}
#[test]
fn test_store_and_retrieve_high_importance() -> Result<()> {
let mut memory = MultiTierMemory::new();
let data = vec![1.0f32, 2.0, 3.0, 4.0];
let tensor = Tensor::from_data(data, vec![1, 4], DataType::F32, TensorLayout::RowMajor)?;
let id = memory.store(tensor, 0.9)?;
let stats = memory.stats();
assert_eq!(stats.working_items, 1);
assert_eq!(stats.episodic_episodes, 1);
Ok(())
}
#[test]
fn test_multiple_stores() -> Result<()> {
let mut memory = MultiTierMemory::new();
for i in 0..10 {
let data = vec![i as f32; 4];
let tensor = Tensor::from_data(data, vec![1, 4], DataType::F32, TensorLayout::RowMajor)?;
let importance = (i as f64) / 10.0; memory.store(tensor, importance)?;
}
let stats = memory.stats();
assert!(stats.working_items <= 10); assert!(stats.episodic_episodes > 0);
Ok(())
}
#[tokio::test]
async fn test_consolidation_empty_memory() -> Result<()> {
let mut memory = MultiTierMemory::new();
let result = memory.consolidate().await?;
assert_eq!(result.episodes_consolidated, 0);
assert_eq!(result.patterns_extracted, 0);
Ok(())
}
#[tokio::test]
async fn test_consolidation_with_episodes() -> Result<()> {
let mut memory = MultiTierMemory::new();
for i in 0..5 {
let data = vec![i as f32; 4];
let tensor = Tensor::from_data(data, vec![1, 4], DataType::F32, TensorLayout::RowMajor)?;
memory.store(tensor, 0.8)?;
}
let result = memory.consolidate().await?;
assert!(result.episodes_consolidated >= 0);
assert!(result.patterns_extracted >= 0);
Ok(())
}
#[tokio::test]
async fn test_multiple_consolidations() -> Result<()> {
let mut memory = MultiTierMemory::new();
for i in 0..10 {
let data = vec![i as f32; 4];
let tensor = Tensor::from_data(data, vec![1, 4], DataType::F32, TensorLayout::RowMajor)?;
memory.store(tensor, 0.7)?;
}
for _ in 0..3 {
memory.consolidate().await?;
}
Ok(())
}
#[test]
fn test_working_to_episodic_promotion() -> Result<()> {
let mut memory = MultiTierMemory::new();
let data = vec![1.0f32; 4];
let tensor = Tensor::from_data(
data.clone(),
vec![1, 4],
DataType::F32,
TensorLayout::RowMajor,
)?;
memory.store(tensor.clone(), 0.5)?;
let tensor2 = Tensor::from_data(data, vec![1, 4], DataType::F32, TensorLayout::RowMajor)?;
memory.store(tensor2, 0.9)?;
let stats = memory.stats();
assert!(stats.episodic_episodes > 0);
Ok(())
}
#[tokio::test]
async fn test_episodic_to_semantic_consolidation() -> Result<()> {
let mut memory = MultiTierMemory::new();
for i in 0..5 {
let data = vec![i as f32; 4];
let tensor = Tensor::from_data(data, vec![1, 4], DataType::F32, TensorLayout::RowMajor)?;
memory.store(tensor, 0.9)?;
}
let stats_before = memory.stats();
let _episodic_before = stats_before.episodic_episodes;
memory.consolidate().await?;
let stats_after = memory.stats();
assert!(stats_after.semantic_concepts >= 0);
Ok(())
}
#[test]
fn test_store_performance() -> Result<()> {
use std::time::Instant;
let mut memory = MultiTierMemory::new();
let data = vec![1.0f32; 1000];
let tensor = Tensor::from_data(data, vec![1, 1000], DataType::F32, TensorLayout::RowMajor)?;
let start = Instant::now();
memory.store(tensor, 0.5)?;
let elapsed = start.elapsed();
assert!(elapsed.as_millis() < 1, "Store too slow: {:?}", elapsed);
Ok(())
}
#[test]
fn test_retrieve_performance() -> Result<()> {
use std::time::Instant;
let mut memory = MultiTierMemory::new();
let data = vec![1.0f32; 1000];
let tensor = Tensor::from_data(data, vec![1, 1000], DataType::F32, TensorLayout::RowMajor)?;
let id = memory.store(tensor, 0.5)?;
let start = Instant::now();
let _ = memory.retrieve(id)?;
let elapsed = start.elapsed();
assert!(
elapsed.as_micros() < 100,
"Retrieve too slow: {:?}",
elapsed
);
Ok(())
}
#[test]
fn test_many_stores_performance() -> Result<()> {
use std::time::Instant;
let mut memory = MultiTierMemory::new();
let start = Instant::now();
for i in 0..1000 {
let data = vec![(i % 100) as f32; 10];
let tensor = Tensor::from_data(data, vec![1, 10], DataType::F32, TensorLayout::RowMajor)?;
memory.store(tensor, 0.5)?;
}
let elapsed = start.elapsed();
println!("1000 stores took: {:?}", elapsed);
assert!(
elapsed.as_millis() < 100,
"Many stores too slow: {:?}",
elapsed
);
Ok(())
}
#[test]
fn test_concurrent_stores() -> Result<()> {
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
let memory = Arc::new(Mutex::new(MultiTierMemory::new()));
let mut handles = vec![];
for i in 0..10 {
let memory_clone = Arc::clone(&memory);
let handle = thread::spawn(move || {
let data = vec![i as f32; 10];
let tensor =
Tensor::from_data(data, vec![1, 10], DataType::F32, TensorLayout::RowMajor)
.unwrap();
let mut mem = memory_clone.lock().unwrap();
mem.store(tensor, 0.5).unwrap();
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let mem = memory.lock().unwrap();
let stats = mem.stats();
assert!(stats.working_items > 0);
Ok(())
}
#[test]
fn test_retrieve_nonexistent_id() -> Result<()> {
let memory = MultiTierMemory::new();
let result = memory.retrieve(99999999)?;
assert!(result.is_none());
Ok(())
}
#[test]
fn test_store_empty_tensor() -> Result<()> {
let mut memory = MultiTierMemory::new();
let tensor = Tensor::from_data(vec![], vec![0], DataType::F32, TensorLayout::RowMajor)?;
let id = memory.store(tensor, 0.5)?;
let retrieved = memory.retrieve(id)?;
assert!(retrieved.is_some());
Ok(())
}
#[test]
fn test_statistics_accuracy() -> Result<()> {
let mut memory = MultiTierMemory::new();
for i in 0..5 {
let data = vec![i as f32; 4];
let tensor = Tensor::from_data(data, vec![1, 4], DataType::F32, TensorLayout::RowMajor)?;
memory.store(tensor, 0.5)?; }
for i in 0..3 {
let data = vec![i as f32; 4];
let tensor = Tensor::from_data(data, vec![1, 4], DataType::F32, TensorLayout::RowMajor)?;
memory.store(tensor, 0.9)?; }
let stats = memory.stats();
assert!(stats.working_items > 0);
assert!(stats.episodic_episodes > 0);
Ok(())
}