use codelens_engine::{ProjectRoot, search_symbols_hybrid_with_semantic};
use std::collections::HashMap;
use std::path::PathBuf;
fn temp_project(prefix: &str) -> (tempfile::TempDir, PathBuf, ProjectRoot) {
let td =
tempfile::TempDir::with_prefix(format!("codelens_pr_test_{prefix}_")).expect("tempfile");
let root = td.path().to_path_buf();
std::fs::write(root.join("hello.txt"), "hello").unwrap();
let project = ProjectRoot::new(root.to_str().unwrap()).unwrap();
(td, root, project)
}
fn seed_two_file_index(project: &ProjectRoot) {
use codelens_engine::db::{IndexDb, NewSymbol, index_db_path};
let db = IndexDb::open(&index_db_path(project.as_path())).unwrap();
let popular = db
.upsert_file("popular.py", 100, "h1", 10, Some("py"))
.unwrap();
let obscure = db
.upsert_file("obscure.py", 100, "h2", 10, Some("py"))
.unwrap();
db.insert_symbols(
popular,
&[NewSymbol {
name: "shared_helper",
kind: "function",
line: 1,
column_num: 0,
start_byte: 0,
end_byte: 50,
signature: "def shared_helper():",
name_path: "shared_helper",
parent_id: None,
}],
)
.unwrap();
db.insert_symbols(
obscure,
&[NewSymbol {
name: "shared_helper",
kind: "function",
line: 1,
column_num: 0,
start_byte: 0,
end_byte: 50,
signature: "def shared_helper():",
name_path: "shared_helper",
parent_id: None,
}],
)
.unwrap();
}
#[test]
fn pagerank_boost_changes_result_score() {
let (_temp, _root, project) = temp_project("changes_score");
seed_two_file_index(&project);
let baseline =
search_symbols_hybrid_with_semantic(&project, "shared_helper", 20, 0.5, None, None)
.expect("baseline search");
assert_eq!(baseline.len(), 2, "expected one hit per file");
let baseline_popular = baseline
.iter()
.find(|r| r.file == "popular.py")
.expect("popular hit");
let baseline_obscure = baseline
.iter()
.find(|r| r.file == "obscure.py")
.expect("obscure hit");
assert_eq!(
baseline_popular.score, baseline_obscure.score,
"exact-match path should give identical scores absent PageRank"
);
let mut pr = HashMap::new();
pr.insert("popular.py".to_owned(), 0.4);
pr.insert("obscure.py".to_owned(), 0.05);
let boosted =
search_symbols_hybrid_with_semantic(&project, "shared_helper", 20, 0.5, None, Some(&pr))
.expect("boosted search");
let boosted_popular = boosted
.iter()
.find(|r| r.file == "popular.py")
.expect("popular hit");
let boosted_obscure = boosted
.iter()
.find(|r| r.file == "obscure.py")
.expect("obscure hit");
assert!(
boosted_popular.score > baseline_popular.score,
"popular.py score should rise with PageRank: {} → {}",
baseline_popular.score,
boosted_popular.score
);
assert!(
boosted_popular.score > boosted_obscure.score,
"popular.py should outrank obscure.py once PageRank is applied: {} > {}",
boosted_popular.score,
boosted_obscure.score
);
}
#[test]
fn empty_pagerank_map_is_indistinguishable_from_none() {
let (_temp, _root, project) = temp_project("empty_map");
seed_two_file_index(&project);
let none_result =
search_symbols_hybrid_with_semantic(&project, "shared_helper", 20, 0.5, None, None)
.expect("none search");
let empty_result = search_symbols_hybrid_with_semantic(
&project,
"shared_helper",
20,
0.5,
None,
Some(&HashMap::new()),
)
.expect("empty search");
assert_eq!(none_result.len(), empty_result.len());
for (n, e) in none_result.iter().zip(empty_result.iter()) {
assert_eq!(n.file, e.file);
assert!(
(n.score - e.score).abs() < 1e-9,
"empty PR map must not perturb scores: {} vs {}",
n.score,
e.score
);
}
}