use crate::config::Config;
use crate::memory::MemoryStore;
use crate::memory::store::MAX_INPUT_LENGTH;
use crate::memory_types::IngestPolicy;
use tempfile::TempDir;
#[ignore]
#[test]
fn test_ingest_at_max_input_length_minus_one_succeeds() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.db");
std::mem::forget(dir);
let mut store = MemoryStore::new(&path, "BAAI/bge-small-en-v1.5", Config::default()).unwrap();
let text = "x".repeat(MAX_INPUT_LENGTH - 1);
let result = store.ingest("test-project", &text, None, IngestPolicy::Force);
assert!(
result.is_ok(),
"Should accept input at MAX_INPUT_LENGTH - 1"
);
}
#[ignore]
#[test]
fn test_ingest_at_max_input_length_succeeds() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.db");
std::mem::forget(dir);
let mut store = MemoryStore::new(&path, "BAAI/bge-small-en-v1.5", Config::default()).unwrap();
let text = "x".repeat(MAX_INPUT_LENGTH);
let result = store.ingest("test-project", &text, None, IngestPolicy::Force);
assert!(
result.is_ok(),
"Should accept input at exactly MAX_INPUT_LENGTH"
);
}
#[test]
fn test_ingest_at_max_input_length_plus_one_fails() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.db");
std::mem::forget(dir);
let db = crate::sqlite::Database::open(&path).unwrap();
let mut store = MemoryStore::from_db(db, Config::default());
let text = "x".repeat(MAX_INPUT_LENGTH + 1);
let result = store.ingest("test-project", &text, None, IngestPolicy::Force);
assert!(
result.is_err(),
"Should reject input at MAX_INPUT_LENGTH + 1"
);
}
#[test]
fn test_ingest_whitespace_only_rejected_with_explicit_error() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.db");
std::mem::forget(dir);
let db = crate::sqlite::Database::open(&path).unwrap();
let mut store = MemoryStore::from_db(db, Config::default());
let whitespace_inputs = vec![" ", "\t\n", " \t \n "];
for input in whitespace_inputs {
let result = store.ingest("test-project", input, None, IngestPolicy::Force);
assert!(
result.is_err(),
"Should reject whitespace-only input: {:?}",
input
);
if let Err(e) = result {
assert!(
matches!(e, crate::errors::Error::EmptyInput),
"Should return EmptyInput error, got: {:?}",
e
);
}
}
}
#[ignore]
#[test]
fn test_ingest_metadata_with_special_json_characters_succeeds() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.db");
std::mem::forget(dir);
let mut store = MemoryStore::new(&path, "BAAI/bge-small-en-v1.5", Config::default()).unwrap();
let metadata_cases = vec![
r#"{"key": "value with \"quotes\""}"#,
r#"{"key": "value with 'apostrophes'"}"#,
r#"{"key": "value with \t tabs \n and \r\n newlines"}"#,
r#"{"key": "value with \\ backslashes"}"#,
r#"{"nested": {"deeply": {"key": "value"}}}"#,
r#"{"array": ["item1", "item2"]}"#,
];
for metadata in metadata_cases {
let result = store.ingest(
"test-project",
"test content",
Some(metadata),
IngestPolicy::Force,
);
assert!(
result.is_ok(),
"Should accept valid JSON metadata with special characters: {}",
metadata
);
if let Ok(crate::memory_types::AddResult::Added { id }) = result {
let memory = store.get(&id).unwrap().unwrap();
assert_eq!(memory.metadata, Some(metadata.to_string()));
}
}
}
#[ignore]
#[test]
fn test_ingest_metadata_with_unicode_succeeds() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.db");
std::mem::forget(dir);
let mut store = MemoryStore::new(&path, "BAAI/bge-small-en-v1.5", Config::default()).unwrap();
let metadata_cases = vec![
r#"{"emoji": "๐โจ๐ฏ"}"#,
r#"{"chinese": "ไฝ ๅฅฝไธ็"}"#,
r#"{"japanese": "ใใใซใกใฏ"}"#,
r#"{"arabic": "ู
ุฑุญุจุง"}"#,
r#"{"emoji_text": "Test with ๐ emojis and ไธญๆ characters"}"#,
];
for metadata in metadata_cases {
let result = store.ingest(
"test-project",
"test content",
Some(metadata),
IngestPolicy::Force,
);
assert!(
result.is_ok(),
"Should accept valid JSON metadata with Unicode: {}",
metadata
);
if let Ok(crate::memory_types::AddResult::Added { id }) = result {
let memory = store.get(&id).unwrap().unwrap();
assert_eq!(memory.metadata, Some(metadata.to_string()));
}
}
}
#[ignore]
#[test]
fn test_ingest_content_with_combining_characters_succeeds() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.db");
std::mem::forget(dir);
let mut store = MemoryStore::new(&path, "BAAI/bge-small-en-v1.5", Config::default()).unwrap();
let content_cases = vec![
"cafรฉ", "c\u{0065}\u{0301}fe", "e\u{0301}", "ๆฅๆฌ\u{0301}่ช", ];
for content in content_cases {
let result = store.ingest("test-project", content, None, IngestPolicy::Force);
assert!(
result.is_ok(),
"Should accept content with combining characters: {}",
content
);
if let Ok(crate::memory_types::AddResult::Added { id }) = result {
let memory = store.get(&id).unwrap().unwrap();
assert_eq!(
memory.content, content,
"Content should be stored exactly as provided"
);
}
}
}
#[ignore]
#[test]
fn test_ingest_content_with_emoji_succeeds() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.db");
std::mem::forget(dir);
let mut store = MemoryStore::new(&path, "BAAI/bge-small-en-v1.5", Config::default()).unwrap();
let content_cases = vec![
"Test with ๐ emoji",
"Emojis: ๐๐๐",
"Unicode: โจ๐๐ซ",
"Face emojis: ๐๐๐ฅณ",
];
for content in content_cases {
let result = store.ingest("test-project", content, None, IngestPolicy::Force);
assert!(
result.is_ok(),
"Should accept content with emoji: {}",
content
);
if let Ok(crate::memory_types::AddResult::Added { id }) = result {
let memory = store.get(&id).unwrap().unwrap();
assert_eq!(memory.content, content);
}
}
}
#[ignore]
#[test]
fn test_ingest_content_with_bom_succeeds() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.db");
std::mem::forget(dir);
let mut store = MemoryStore::new(&path, "BAAI/bge-small-en-v1.5", Config::default()).unwrap();
let bom = "\u{feff}";
let content_with_bom = format!("{}Normal content", bom);
let result = store.ingest("test-project", &content_with_bom, None, IngestPolicy::Force);
assert!(result.is_ok(), "Should accept content with BOM");
if let Ok(crate::memory_types::AddResult::Added { id }) = result {
let memory = store.get(&id).unwrap().unwrap();
assert_eq!(
memory.content, content_with_bom,
"BOM should be preserved in storage"
);
}
}
#[ignore]
#[test]
fn test_ingest_accepts_any_project_id_string() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.db");
std::mem::forget(dir);
let mut store = MemoryStore::new(&path, "BAAI/bge-small-en-v1.5", Config::default()).unwrap();
let project_id_cases = vec![
"simple-project",
"https://github.com/user/repo.git",
"project_with_123",
"Project-With.dots",
"้กน็ฎ-ID", "user/repo/branch",
];
for project_id in project_id_cases {
let result = store.ingest(project_id, "test content", None, IngestPolicy::Force);
assert!(
result.is_ok(),
"Should accept any string as project_id: {}",
project_id
);
if let Ok(crate::memory_types::AddResult::Added { id }) = result {
let memory = store.get(&id).unwrap().unwrap();
assert_eq!(memory.project_id, project_id);
}
}
}