use codelore_lib::analyses::dashboard::{
run_clone_summary, run_daily_commits, run_imports_for_arch_graph, run_kamei_risk, run_trends,
run_xray,
};
use codelore_lib::facts::FactsDb;
use codelore_lib::repo::GixRepo;
use codelore_lib::test_support::permissive_coupling_opts;
#[test]
fn dashboard_queries_run_over_ingested_fixture() {
let fixture = codelore_lib::test_support::differential_repo::build();
let repo = GixRepo::open(fixture.dir.path()).expect("open");
let db = FactsDb::new_in_memory().expect("db");
let opts = permissive_coupling_opts(fixture.dir.path().to_path_buf());
db.ingest(&repo, &opts).expect("ingest");
let daily = run_daily_commits(&db).expect("run_daily_commits");
assert!(!daily.is_empty(), "fixture has commits → daily rows");
for d in &daily {
assert!(!d.date.is_empty(), "daily row has a date");
assert!(d.count >= 1, "an active day has ≥1 commit, got {}", d.count);
}
let xray = run_xray(&db, 100).expect("run_xray");
for x in &xray {
assert!(!x.function.is_empty(), "xray entry has a function name");
assert!(
x.start_line <= x.end_line,
"xray line range {}..{} inverted for {}",
x.start_line,
x.end_line,
x.path
);
}
let clones = run_clone_summary(&db).expect("run_clone_summary");
for c in &clones {
assert!(c.groups >= 1, "clone-summary groups ≥1, got {}", c.groups);
}
let mut paths: Vec<String> = xray.iter().map(|x| x.path.clone()).collect();
paths.sort();
paths.dedup();
let trends = run_trends(&db, &opts, &paths).expect("run_trends");
for t in &trends {
assert!(!t.month.is_empty(), "trend point has a month");
}
let _kamei = run_kamei_risk(&db, 100).expect("run_kamei_risk");
let _imports = run_imports_for_arch_graph(&db).expect("run_imports_for_arch_graph");
}
#[test]
fn trends_sparkline_covers_pre_rename_history_under_lineage() {
use codelore_lib::Options;
use codelore_lib::analyses::revisions::run_revisions;
let fixture = codelore_lib::test_support::differential_repo::build();
let repo = GixRepo::open(fixture.dir.path()).expect("open");
let opts_on = Options {
repo_path: fixture.dir.path().to_path_buf(),
min_revs: 1,
use_canonical_lineage: true,
..Options::default()
};
let db_on = FactsDb::new_in_memory().expect("db");
db_on.ingest(&repo, &opts_on).expect("ingest");
let head_path = run_revisions(&db_on, &opts_on)
.expect("revisions")
.into_iter()
.find(|(p, _)| p.contains("new_name"))
.map(|(p, _)| p)
.expect("fixture has a renamed new_name path");
let paths = vec![head_path];
let on_sum: f64 = run_trends(&db_on, &opts_on, &paths)
.expect("trends lineage-on")
.iter()
.map(|t| t.hotspot_score)
.sum();
let opts_off = Options {
use_canonical_lineage: false,
..opts_on.clone()
};
let db_off = FactsDb::new_in_memory().expect("db");
db_off.ingest(&repo, &opts_off).expect("ingest");
let off_sum: f64 = run_trends(&db_off, &opts_off, &paths)
.expect("trends lineage-off")
.iter()
.map(|t| t.hotspot_score)
.sum();
assert!(
on_sum > off_sum,
"lineage must fold pre-rename revisions into the head-path sparkline: on={on_sum} off={off_sum}"
);
assert!(
on_sum >= 2.0,
"head path should aggregate ≥2 revisions (pre-rename + post-rename); got {on_sum}"
);
}