use std::fs;
use std::path::PathBuf;
use aft::search_index::project_cache_key;
use serde_json::json;
use tempfile::tempdir;
use crate::test_helpers::AftProcess;
fn write_fake_cache_for_project(
storage_root: &std::path::Path,
project_root: &std::path::Path,
trigram_bytes: usize,
semantic_bytes: usize,
) {
let key = project_cache_key(project_root);
let trigram_dir = storage_root.join("index").join(&key);
fs::create_dir_all(&trigram_dir).expect("create trigram dir");
fs::write(trigram_dir.join("postings.bin"), vec![0u8; trigram_bytes])
.expect("write fake postings");
let semantic_dir = storage_root.join("semantic").join(&key);
fs::create_dir_all(&semantic_dir).expect("create semantic dir");
fs::write(semantic_dir.join("semantic.bin"), vec![0u8; semantic_bytes])
.expect("write fake semantic");
}
#[test]
fn status_disk_bytes_only_count_current_project() {
let storage_root_dir = tempdir().expect("storage root");
let storage_root = storage_root_dir.path().to_path_buf();
let project_a_dir = tempdir().expect("project a");
let project_a = project_a_dir.path().to_path_buf();
fs::create_dir_all(project_a.join("src")).expect("project a src");
fs::write(project_a.join("src/lib.rs"), "pub fn a() {}\n").expect("project a file");
let project_b_dir = tempdir().expect("project b");
let project_b = project_b_dir.path().to_path_buf();
let key_a = project_cache_key(&project_a);
let key_b = project_cache_key(&project_b);
assert_ne!(
key_a, key_b,
"projects {project_a:?} and {project_b:?} unexpectedly share cache key {key_a}"
);
write_fake_cache_for_project(&storage_root, &project_a, 1024, 512);
write_fake_cache_for_project(&storage_root, &project_b, 10 * 1024 * 1024, 5 * 1024 * 1024);
let mut aft = AftProcess::spawn();
let configure = json!({
"id": "1",
"command": "configure",
"harness": "opencode",
"project_root": project_a.to_str().expect("project a utf-8"),
"storage_dir": storage_root.to_str().expect("storage utf-8"),
});
let response = aft.send(&configure.to_string());
assert_eq!(response["success"], true, "configure failed: {response}");
let _ = aft.try_read_next_timeout(std::time::Duration::from_secs(2));
let status = aft.send(r#"{"id":"2","command":"status"}"#);
assert_eq!(status["success"], true, "status failed: {status}");
let trigram = status["disk"]["trigram_disk_bytes"]
.as_u64()
.expect("trigram_disk_bytes is u64");
let semantic = status["disk"]["semantic_disk_bytes"]
.as_u64()
.expect("semantic_disk_bytes is u64");
assert_eq!(
trigram, 1024,
"trigram_disk_bytes should reflect only project A's slice; \
got {trigram} (sibling B has 10 MB which would be visible without scoping)"
);
assert_eq!(
semantic, 512,
"semantic_disk_bytes should reflect only project A's slice; \
got {semantic} (sibling B has 5 MB which would be visible without scoping)"
);
assert_eq!(
status["disk"]["project_cache_key"].as_str(),
Some(key_a.as_str()),
"status should include project_cache_key for the configured project"
);
}
#[test]
fn status_disk_bytes_zero_when_no_cache_for_project() {
let storage_root_dir = tempdir().expect("storage root");
let storage_root = storage_root_dir.path().to_path_buf();
let project_dir = tempdir().expect("project");
let project_root = project_dir.path().to_path_buf();
fs::create_dir_all(project_root.join("src")).expect("project src");
fs::write(project_root.join("src/lib.rs"), "pub fn x() {}\n").expect("project file");
let sibling_dir = tempdir().expect("sibling project");
write_fake_cache_for_project(&storage_root, sibling_dir.path(), 4096, 2048);
let mut aft = AftProcess::spawn();
let configure = json!({
"id": "1",
"command": "configure",
"harness": "opencode",
"project_root": project_root.to_str().expect("utf-8"),
"storage_dir": storage_root.to_str().expect("utf-8"),
});
let response = aft.send(&configure.to_string());
assert_eq!(response["success"], true);
let _ = aft.try_read_next_timeout(std::time::Duration::from_secs(2));
let status = aft.send(r#"{"id":"2","command":"status"}"#);
assert_eq!(status["disk"]["trigram_disk_bytes"], 0);
assert_eq!(status["disk"]["semantic_disk_bytes"], 0);
}
#[allow(dead_code)]
fn _api_compile_check() -> String {
project_cache_key(&PathBuf::from("/tmp/whatever"))
}