use cached_context::{CacheConfig, CacheStore, FileReadResult};
async fn create_test_store(temp_dir: &tempfile::TempDir, session_id: &str) -> CacheStore {
let config = CacheConfig {
db_path: temp_dir.path().join("test.db"),
session_id: session_id.to_string(),
workdir: temp_dir.path().to_path_buf(),
};
let store = CacheStore::new(config).expect("Failed to create cache");
store.init().await.expect("Failed to init cache");
store
}
#[tokio::test]
async fn test_smoke_first_read_full_content() {
let temp_dir = tempfile::tempdir().expect("Failed to create temp dir");
let test_file = temp_dir.path().join("example.ts");
std::fs::write(
&test_file,
"function hello() {\n console.log(\"hello world\");\n}\n",
)
.expect("Failed to write test file");
let store = create_test_store(&temp_dir, "test-session-1").await;
let result: FileReadResult = store
.read_file(test_file.to_str().unwrap(), None, None, false)
.await
.expect("Failed to read file");
assert!(!result.cached, "First read should not be cached");
assert_eq!(result.total_lines, 3, "Should have 3 lines");
assert!(
result.content.contains("function hello()"),
"Should contain function definition"
);
assert!(
result.content.contains("hello world"),
"Should contain console.log"
);
}
#[tokio::test]
async fn test_smoke_second_read_cached() {
let temp_dir = tempfile::tempdir().expect("Failed to create temp dir");
let test_file = temp_dir.path().join("example.ts");
std::fs::write(
&test_file,
"function hello() {\n console.log(\"hello world\");\n}\n",
)
.expect("Failed to write test file");
let store = create_test_store(&temp_dir, "test-session-1").await;
let _ = store
.read_file(test_file.to_str().unwrap(), None, None, false)
.await
.expect("Failed to read file");
let result: FileReadResult = store
.read_file(test_file.to_str().unwrap(), None, None, false)
.await
.expect("Failed to read file");
assert!(result.cached, "Second read should be cached");
assert_eq!(result.lines_changed, None, "No lines should have changed");
assert!(
result.content.contains("unchanged"),
"Should indicate unchanged: {}",
result.content
);
}
#[tokio::test]
async fn test_smoke_modified_file_returns_diff() {
let temp_dir = tempfile::tempdir().expect("Failed to create temp dir");
let test_file = temp_dir.path().join("example.ts");
std::fs::write(
&test_file,
"function hello() {\n console.log(\"hello world\");\n}\n",
)
.expect("Failed to write test file");
let store = create_test_store(&temp_dir, "test-session-1").await;
let _ = store
.read_file(test_file.to_str().unwrap(), None, None, false)
.await
.expect("Failed to read file");
std::fs::write(
&test_file,
"function hello() {\n console.log(\"hello cachebro!\");\n return true;\n}\n",
)
.expect("Failed to modify test file");
let result: FileReadResult = store
.read_file(test_file.to_str().unwrap(), None, None, false)
.await
.expect("Failed to read file");
assert!(result.cached, "Should be cached (returning diff)");
assert!(
result.lines_changed.unwrap() > 0,
"Should have changed lines"
);
assert!(result.diff.is_some(), "Should have diff content");
let diff = result.diff.unwrap();
assert!(
diff.contains("---") || diff.contains("+++") || diff.contains("@@"),
"Diff should contain markers: {}",
diff
);
}
#[tokio::test]
async fn test_smoke_stats_tracking() {
let temp_dir = tempfile::tempdir().expect("Failed to create temp dir");
let test_file = temp_dir.path().join("example.ts");
std::fs::write(&test_file, "function hello() {}\n").expect("Failed to write test file");
let store = create_test_store(&temp_dir, "test-session-1").await;
let _ = store
.read_file(test_file.to_str().unwrap(), None, None, false)
.await
.expect("Failed to read file");
let _ = store
.read_file(test_file.to_str().unwrap(), None, None, false)
.await
.expect("Failed to read file");
let stats = store.get_stats().await.expect("Failed to get stats");
assert_eq!(stats.files_tracked, 1, "Should track 1 file");
assert!(
stats.session_tokens_saved > 0,
"Should have saved tokens in session"
);
assert!(stats.tokens_saved > 0, "Should have saved tokens total");
}
#[tokio::test]
async fn test_smoke_multi_session_isolation() {
let temp_dir = tempfile::tempdir().expect("Failed to create temp dir");
let test_file = temp_dir.path().join("example.ts");
std::fs::write(&test_file, "function hello() {}\n").expect("Failed to write test file");
let db_path = temp_dir.path().join("test.db");
let config1 = CacheConfig {
db_path: db_path.clone(),
session_id: "test-session-1".to_string(),
workdir: temp_dir.path().to_path_buf(),
};
let store1 = CacheStore::new(config1).expect("Failed to create cache");
store1.init().await.expect("Failed to init cache");
let _ = store1
.read_file(test_file.to_str().unwrap(), None, None, false)
.await
.expect("Failed to read file");
let config2 = CacheConfig {
db_path,
session_id: "test-session-2".to_string(),
workdir: temp_dir.path().to_path_buf(),
};
let store2 = CacheStore::new(config2).expect("Failed to create cache");
store2.init().await.expect("Failed to init cache");
let result2 = store2
.read_file(test_file.to_str().unwrap(), None, None, false)
.await
.expect("Failed to read file");
assert!(!result2.cached, "Session 2 first read should NOT be cached");
let result2b = store2
.read_file(test_file.to_str().unwrap(), None, None, false)
.await
.expect("Failed to read file");
assert!(result2b.cached, "Session 2 second read should be cached");
assert_eq!(
result2b.lines_changed, None,
"No lines should have changed for session 2"
);
}
#[tokio::test]
async fn test_smoke_partial_read_first_time() {
let temp_dir = tempfile::tempdir().expect("Failed to create temp dir");
let test_file = temp_dir.path().join("long.ts");
let content: String = (0..20)
.map(|i| format!("line {}: const x{} = {};", i + 1, i, i))
.collect::<Vec<_>>()
.join("\n");
std::fs::write(&test_file, content).expect("Failed to write test file");
let store = create_test_store(&temp_dir, "test-session-1").await;
let result: FileReadResult = store
.read_file(test_file.to_str().unwrap(), Some(5), Some(3), false)
.await
.expect("Failed to read file");
assert!(!result.cached, "First partial read should not be cached");
assert!(result.content.contains("line 5"), "Should include line 5");
assert!(result.content.contains("line 7"), "Should include line 7");
assert!(
!result.content.contains("line 8"),
"Should NOT include line 8"
);
}
#[tokio::test]
async fn test_smoke_partial_read_unchanged() {
let temp_dir = tempfile::tempdir().expect("Failed to create temp dir");
let test_file = temp_dir.path().join("long.ts");
let content: String = (0..20)
.map(|i| format!("line {}: const x{} = {};", i + 1, i, i))
.collect::<Vec<_>>()
.join("\n");
std::fs::write(&test_file, content).expect("Failed to write test file");
let store = create_test_store(&temp_dir, "test-session-1").await;
let _ = store
.read_file(test_file.to_str().unwrap(), Some(5), Some(3), false)
.await
.expect("Failed to read file");
let result: FileReadResult = store
.read_file(test_file.to_str().unwrap(), Some(5), Some(3), false)
.await
.expect("Failed to read file");
assert!(result.cached, "Second partial read should be cached");
assert_eq!(result.lines_changed, None, "No lines should have changed");
assert!(
result.content.contains("unchanged"),
"Should say unchanged: {}",
result.content
);
}
#[tokio::test]
async fn test_smoke_partial_read_changes_outside_range() {
let temp_dir = tempfile::tempdir().expect("Failed to create temp dir");
let test_file = temp_dir.path().join("long.ts");
let mut lines: Vec<String> = (0..20)
.map(|i| format!("line {}: const x{} = {};", i + 1, i, i))
.collect();
let content = lines.join("\n");
std::fs::write(&test_file, &content).expect("Failed to write test file");
let store = create_test_store(&temp_dir, "test-session-1").await;
let _ = store
.read_file(test_file.to_str().unwrap(), Some(5), Some(3), false)
.await
.expect("Failed to read file");
lines[0] = "line 1: MODIFIED".to_string();
lines[18] = "line 19: MODIFIED".to_string();
let modified_content = lines.join("\n");
std::fs::write(&test_file, modified_content).expect("Failed to modify test file");
let result: FileReadResult = store
.read_file(test_file.to_str().unwrap(), Some(5), Some(3), false)
.await
.expect("Failed to read file");
assert!(
result.cached,
"Should be cached — changes outside requested range"
);
assert_eq!(
result.lines_changed,
Some(0),
"Should report 0 lines changed in range"
);
assert!(
result.content.contains("unchanged"),
"Should say unchanged: {}",
result.content
);
}
#[tokio::test]
async fn test_smoke_partial_read_changes_inside_range() {
let temp_dir = tempfile::tempdir().expect("Failed to create temp dir");
let test_file = temp_dir.path().join("long.ts");
let mut lines: Vec<String> = (0..20)
.map(|i| format!("line {}: const x{} = {};", i + 1, i, i))
.collect();
let content = lines.join("\n");
std::fs::write(&test_file, &content).expect("Failed to write test file");
let store = create_test_store(&temp_dir, "test-session-1").await;
let _ = store
.read_file(test_file.to_str().unwrap(), Some(5), Some(3), false)
.await
.expect("Failed to read file");
lines[5] = "line 6: MODIFIED_IN_RANGE".to_string();
let modified_content = lines.join("\n");
std::fs::write(&test_file, modified_content).expect("Failed to modify test file");
let result: FileReadResult = store
.read_file(test_file.to_str().unwrap(), Some(5), Some(3), false)
.await
.expect("Failed to read file");
assert!(
!result.cached,
"Should NOT be cached — changes inside requested range"
);
assert!(
result.content.contains("MODIFIED_IN_RANGE"),
"Should include modified content: {}",
result.content
);
}