use crate::common::fixtures::{generate_unique_content, TestMemory};
use crate::common::TestDatabaseManager;
use anyhow::Result;
use codex_memory::{Storage, StorageInterface};
use serial_test::serial;
use std::sync::Arc;
#[tokio::test]
#[serial]
async fn test_store_with_full_fields() -> Result<()> {
let mut manager = TestDatabaseManager::new()?;
let pool = manager.setup_test_database().await?;
let storage = Arc::new(Storage::new(pool));
let test_data = TestMemory::full();
let id = storage
.store(
&test_data.content,
test_data.context.clone(),
test_data.summary.clone(),
Some(test_data.tags.clone()),
)
.await?;
let retrieved = storage.get(id).await?.expect("Memory should exist");
assert_eq!(retrieved.content, test_data.content);
assert_eq!(retrieved.context, test_data.context);
assert_eq!(retrieved.summary, test_data.summary);
assert_eq!(retrieved.tags, test_data.tags);
manager.cleanup().await?;
Ok(())
}
#[tokio::test]
#[serial]
async fn test_store_minimal_content_only() -> Result<()> {
let mut manager = TestDatabaseManager::new()?;
let pool = manager.setup_test_database().await?;
let storage = Arc::new(Storage::new(pool));
let content = "Just plain content, nothing else";
let id = storage
.store(
content,
"Test context".to_string(),
"Test summary".to_string(),
None,
)
.await?;
let retrieved = storage.get(id).await?.expect("Memory should exist");
assert_eq!(retrieved.content, content);
assert_eq!(retrieved.context, "Test context");
assert_eq!(retrieved.summary, "Test summary");
assert!(retrieved.tags.is_empty());
manager.cleanup().await?;
Ok(())
}
#[tokio::test]
#[serial]
async fn test_store_with_context_only() -> Result<()> {
let mut manager = TestDatabaseManager::new()?;
let pool = manager.setup_test_database().await?;
let storage = Arc::new(Storage::new(pool));
let test_data = TestMemory::with_context_only();
let id = storage
.store(
&test_data.content,
test_data.context.clone(),
test_data.summary.clone(),
Some(test_data.tags.clone()),
)
.await?;
let retrieved = storage.get(id).await?.expect("Memory should exist");
assert_eq!(retrieved.content, test_data.content);
assert_eq!(retrieved.context, test_data.context);
assert_eq!(retrieved.summary, test_data.summary);
assert_eq!(retrieved.tags, test_data.tags);
manager.cleanup().await?;
Ok(())
}
#[tokio::test]
#[serial]
async fn test_store_with_summary_only() -> Result<()> {
let mut manager = TestDatabaseManager::new()?;
let pool = manager.setup_test_database().await?;
let storage = Arc::new(Storage::new(pool));
let test_data = TestMemory::with_summary_only();
let id = storage
.store(
&test_data.content,
test_data.context.clone(),
test_data.summary.clone(),
Some(test_data.tags.clone()),
)
.await?;
let retrieved = storage.get(id).await?.expect("Memory should exist");
assert_eq!(retrieved.content, test_data.content);
assert_eq!(retrieved.context, test_data.context);
assert_eq!(retrieved.summary, test_data.summary);
assert_eq!(retrieved.tags, test_data.tags);
manager.cleanup().await?;
Ok(())
}
#[tokio::test]
#[serial]
async fn test_content_stored_without_modification() -> Result<()> {
let mut manager = TestDatabaseManager::new()?;
let pool = manager.setup_test_database().await?;
let storage = Arc::new(Storage::new(pool));
let test_cases = vec![
"Simple text",
"Text with 'quotes' and \"double quotes\"",
"Text with special chars: @#$%^&*()",
"Multi-line\ntext\nwith\nbreaks",
"Text with emoji 🎉 🚀 💾",
" Text with leading/trailing spaces ",
"Text\twith\ttabs",
];
for content in test_cases {
let id = storage
.store(
content,
"Test context".to_string(),
"Test summary".to_string(),
None,
)
.await?;
let retrieved = storage.get(id).await?.expect("Memory should exist");
assert_eq!(
retrieved.content, content,
"Content should be stored without modification"
);
}
manager.cleanup().await?;
Ok(())
}
#[tokio::test]
#[serial]
async fn test_deduplication_with_different_context_summary() -> Result<()> {
let mut manager = TestDatabaseManager::new()?;
let pool = manager.setup_test_database().await?;
let storage = Arc::new(Storage::new(pool));
let content = "Duplicate content test";
let id1 = storage
.store(
content,
"Context 1".to_string(),
"Summary 1".to_string(),
None,
)
.await?;
let id2 = storage
.store(
content,
"Context 2".to_string(),
"Summary 2".to_string(),
None,
)
.await?;
assert_eq!(id1, id2);
let retrieved = storage.get(id1).await?.expect("Memory should exist");
assert_eq!(retrieved.context, "Context 2".to_string());
assert_eq!(retrieved.summary, "Summary 2".to_string());
manager.cleanup().await?;
Ok(())
}
#[tokio::test]
#[serial]
async fn test_tag_operations() -> Result<()> {
let mut manager = TestDatabaseManager::new()?;
let pool = manager.setup_test_database().await?;
let storage = Arc::new(Storage::new(pool));
let id1 = storage
.store(
"Content 1",
"Test context".to_string(),
"Test summary".to_string(),
Some(vec![]),
)
.await?;
let mem1 = storage.get(id1).await?.expect("Memory should exist");
assert!(mem1.tags.is_empty());
let id2 = storage
.store(
"Content 2",
"Test context".to_string(),
"Test summary".to_string(),
Some(vec!["single".to_string()]),
)
.await?;
let mem2 = storage.get(id2).await?.expect("Memory should exist");
assert_eq!(mem2.tags, vec!["single"]);
let tags = vec!["tag1".to_string(), "tag2".to_string(), "tag3".to_string()];
let id3 = storage
.store(
"Content 3",
"Test context".to_string(),
"Test summary".to_string(),
Some(tags.clone()),
)
.await?;
let mem3 = storage.get(id3).await?.expect("Memory should exist");
assert_eq!(mem3.tags, tags);
let special_tags = TestMemory::with_special_tags();
let id4 = storage
.store(
&special_tags.content,
special_tags.context.clone(),
special_tags.summary.clone(),
Some(special_tags.tags.clone()),
)
.await?;
let mem4 = storage.get(id4).await?.expect("Memory should exist");
assert_eq!(mem4.tags, special_tags.tags);
manager.cleanup().await?;
Ok(())
}
#[tokio::test]
#[serial]
async fn test_delete_memory() -> Result<()> {
let mut manager = TestDatabaseManager::new()?;
let pool = manager.setup_test_database().await?;
let storage = Arc::new(Storage::new(pool));
let content = "Content to be deleted";
let id = storage
.store(
content,
"Test context".to_string(),
"Test summary".to_string(),
None,
)
.await?;
assert!(storage.get(id).await?.is_some());
let deleted = storage.delete(id).await?;
assert!(deleted);
assert!(storage.get(id).await?.is_none());
let deleted_again = storage.delete(id).await?;
assert!(!deleted_again);
manager.cleanup().await?;
Ok(())
}
#[tokio::test]
#[serial]
async fn test_storage_stats() -> Result<()> {
let mut manager = TestDatabaseManager::new()?;
let pool = manager.setup_test_database().await?;
let storage = Arc::new(Storage::new(pool));
let stats = storage.stats().await?;
assert_eq!(stats.total_memories, 0);
for i in 0..5 {
let content = format!("Memory #{} - {}", i, generate_unique_content());
storage
.store(
&content,
"Test context".to_string(),
"Test summary".to_string(),
None,
)
.await?;
}
let stats = storage.stats().await?;
assert_eq!(stats.total_memories, 5);
assert!(stats.last_memory_created.is_some());
manager.cleanup().await?;
Ok(())
}
#[tokio::test]
#[serial]
async fn test_list_recent() -> Result<()> {
let mut manager = TestDatabaseManager::new()?;
let pool = manager.setup_test_database().await?;
let storage = Arc::new(Storage::new(pool));
for i in 0..10 {
let content = format!("Memory #{} - {}", i, generate_unique_content());
storage
.store(
&content,
"Test context".to_string(),
"Test summary".to_string(),
None,
)
.await?;
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
}
let recent = storage.list_recent(5).await?;
assert_eq!(recent.len(), 5);
for i in 0..recent.len() - 1 {
assert!(recent[i].created_at >= recent[i + 1].created_at);
}
manager.cleanup().await?;
Ok(())
}
#[tokio::test]
#[serial]
async fn test_storage_interface_trait() -> Result<()> {
let mut manager = TestDatabaseManager::new()?;
let pool = manager.setup_test_database().await?;
let storage: Arc<dyn StorageInterface> = Arc::new(Storage::new(pool));
let test_data = TestMemory::full();
let id = storage
.store(
&test_data.content,
test_data.context.clone(),
test_data.summary.clone(),
Some(test_data.tags.clone()),
)
.await?;
let retrieved = storage.get(id).await?.expect("Memory should exist");
assert_eq!(retrieved.content, test_data.content);
let stats = storage.stats().await?;
assert!(stats.total_memories > 0);
let deleted = storage.delete(id).await?;
assert!(deleted);
let not_found = storage.get(id).await?;
assert!(not_found.is_none());
manager.cleanup().await?;
Ok(())
}
#[tokio::test]
#[serial]
async fn test_storage_error_handling() -> Result<()> {
let mut manager = TestDatabaseManager::new()?;
let pool = manager.setup_test_database().await?;
let storage = Arc::new(Storage::new(pool));
let invalid_uuid = uuid::Uuid::parse_str("invalid-uuid");
assert!(invalid_uuid.is_err());
let fake_id = uuid::Uuid::new_v4();
let result = storage.get(fake_id).await?;
assert!(result.is_none());
let deleted = storage.delete(fake_id).await?;
assert!(!deleted);
manager.cleanup().await?;
Ok(())
}