use codelore_lib::Options;
use codelore_lib::analyses::code_familiarity::run_code_familiarity;
use codelore_lib::facts::FactsDb;
use codelore_lib::repo::GixRepo;
#[test]
fn delivery_repo_familiarity_row_shape() {
let fixture = codelore_lib::test_support::delivery_repo::build();
let repo = GixRepo::open(fixture.dir.path()).expect("open repo");
let db = FactsDb::new_in_memory().expect("new_in_memory");
let opts = Options {
repo_path: fixture.dir.path().to_path_buf(),
min_revs: 1,
..Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let rows = run_code_familiarity(&db, &opts).expect("run_code_familiarity");
assert_eq!(rows.len(), 1, "should return exactly one repo-scope row");
let row = &rows[0];
assert_eq!(row.scope, "repo");
assert!(
row.familiarity_pct >= 0.0 && row.familiarity_pct <= 100.0,
"familiarity_pct out of range: {}",
row.familiarity_pct
);
assert!(
row.islands_pct >= 0.0 && row.islands_pct <= 100.0,
"islands_pct out of range: {}",
row.islands_pct
);
assert!(
row.active_authors <= row.total_authors,
"active_authors ({}) > total_authors ({})",
row.active_authors,
row.total_authors
);
assert!(
row.verdict == "good" || row.verdict == "risky",
"verdict must be 'good' or 'risky', got '{}'",
row.verdict
);
}
#[test]
fn delivery_repo_familiarity_is_100_pct_all_authors_active() {
let fixture = codelore_lib::test_support::delivery_repo::build();
let repo = GixRepo::open(fixture.dir.path()).expect("open repo");
let db = FactsDb::new_in_memory().expect("new_in_memory");
let opts = Options {
repo_path: fixture.dir.path().to_path_buf(),
min_revs: 1,
..Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let rows = run_code_familiarity(&db, &opts).expect("run_code_familiarity");
assert_eq!(rows.len(), 1, "should return one row");
let row = &rows[0];
assert_eq!(
row.active_authors, 3,
"all 3 authors must be active within 90 days"
);
assert_eq!(row.total_authors, 3, "delivery_repo has exactly 3 authors");
assert!(
(row.familiarity_pct - 100.0).abs() < 0.5,
"expected familiarity ≈ 100.0 (all authors active), got {:.4}",
row.familiarity_pct
);
}
#[test]
fn delivery_repo_islands_pct_in_range() {
let fixture = codelore_lib::test_support::delivery_repo::build();
let repo = GixRepo::open(fixture.dir.path()).expect("open repo");
let db = FactsDb::new_in_memory().expect("new_in_memory");
let opts = Options {
repo_path: fixture.dir.path().to_path_buf(),
min_revs: 1,
..Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let rows = run_code_familiarity(&db, &opts).expect("run_code_familiarity");
assert_eq!(rows.len(), 1, "should return one row");
let row = &rows[0];
assert!(
row.islands_pct >= 0.0 && row.islands_pct <= 100.0,
"islands_pct must be in [0,100]: {}",
row.islands_pct
);
}
#[test]
fn tiny_repo_single_author_no_error() {
let fixture = codelore_lib::test_support::tiny_repo::build();
let repo = GixRepo::open(fixture.dir.path()).expect("open repo");
let db = FactsDb::new_in_memory().expect("new_in_memory");
let opts = Options {
repo_path: fixture.dir.path().to_path_buf(),
min_revs: 1,
..Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let rows = run_code_familiarity(&db, &opts).expect("run_code_familiarity");
assert!(
rows.len() <= 1,
"should return 0 or 1 rows, got {}",
rows.len()
);
if let Some(row) = rows.first() {
assert_eq!(row.scope, "repo");
assert!(
(row.familiarity_pct - 100.0).abs() < 0.5,
"single-author repo should have ~100% familiarity: {}",
row.familiarity_pct
);
assert_eq!(row.active_authors, 1);
assert_eq!(row.total_authors, 1);
}
}
#[test]
fn delivery_repo_idempotent() {
let fixture = codelore_lib::test_support::delivery_repo::build();
let repo = GixRepo::open(fixture.dir.path()).expect("open repo");
let db = FactsDb::new_in_memory().expect("new_in_memory");
let opts = Options {
repo_path: fixture.dir.path().to_path_buf(),
min_revs: 1,
..Options::default()
};
db.ingest(&repo, &opts).expect("ingest");
let rows1 = run_code_familiarity(&db, &opts).expect("first call");
let rows2 = run_code_familiarity(&db, &opts).expect("second call");
assert_eq!(rows1.len(), rows2.len(), "idempotent: row count must match");
if let (Some(r1), Some(r2)) = (rows1.first(), rows2.first()) {
assert!(
(r1.familiarity_pct - r2.familiarity_pct).abs() < 1e-9,
"idempotent: familiarity_pct must match: {} vs {}",
r1.familiarity_pct,
r2.familiarity_pct
);
}
}