use std::path::PathBuf;
use cgx_engine::analyze_repo;
fn fixture_path(relative: &str) -> PathBuf {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("tests/fixtures");
path.push(relative);
path
}
#[test]
fn test_churn_scores() {
let repo_path = fixture_path("git-sample");
let file_paths: Vec<String> = vec![
"src/auth.ts".to_string(),
"src/db.ts".to_string(),
"src/router.ts".to_string(),
];
let analysis = analyze_repo(&repo_path, &file_paths).expect("analyze_repo failed");
let churn = &analysis.file_churn;
let auth_churn = churn.get("src/auth.ts").copied().unwrap_or(0.0);
let db_churn = churn.get("src/db.ts").copied().unwrap_or(0.0);
let router_churn = churn.get("src/router.ts").copied().unwrap_or(0.0);
assert!(auth_churn > 0.0, "auth.ts should have churn > 0");
assert!(db_churn > 0.0, "db.ts should have churn > 0");
assert!(
auth_churn >= router_churn,
"auth.ts should have equal or higher churn than router.ts"
);
assert!(
db_churn >= router_churn,
"db.ts should have equal or higher churn than router.ts"
);
}
#[test]
fn test_co_change_edges() {
let repo_path = fixture_path("git-sample");
let file_paths: Vec<String> = vec![
"src/auth.ts".to_string(),
"src/db.ts".to_string(),
"src/router.ts".to_string(),
];
let analysis = analyze_repo(&repo_path, &file_paths).expect("analyze_repo failed");
let co_changes = &analysis.co_changes;
let has_auth_db = co_changes.iter().any(|(a, b, _)| {
(a == "src/auth.ts" && b == "src/db.ts") || (a == "src/db.ts" && b == "src/auth.ts")
});
assert!(
has_auth_db,
"should have co-change edge between auth.ts and db.ts"
);
if let Some((_, _, weight)) = co_changes.iter().find(|(a, b, _)| {
(a == "src/auth.ts" && b == "src/db.ts") || (a == "src/db.ts" && b == "src/auth.ts")
}) {
assert!(
*weight > 0.5,
"co-change weight should be > 0.5, got {}",
weight
);
}
}
#[test]
fn test_ownership() {
let repo_path = fixture_path("git-sample");
let file_paths: Vec<String> = vec![
"src/auth.ts".to_string(),
"src/db.ts".to_string(),
"src/router.ts".to_string(),
];
let analysis = analyze_repo(&repo_path, &file_paths).expect("analyze_repo failed");
let owners = &analysis.file_owners;
let auth_owners = owners.get("src/auth.ts");
assert!(auth_owners.is_some(), "auth.ts should have ownership data");
if let Some(auth_owners) = auth_owners {
let has_alice = auth_owners
.iter()
.any(|(_, email, _)| email == "alice@dev.io");
assert!(
has_alice,
"Alice should own auth.ts (she made 3 of 4 commits to this file)"
);
if let Some((_, _, pct)) = auth_owners
.iter()
.find(|(_, email, _)| email == "alice@dev.io")
{
assert!(
*pct > 0.5,
"Alice should own > 50% of auth.ts, got {:.2}",
pct
);
}
}
let router_owners = owners.get("src/router.ts");
if let Some(router_owners) = router_owners {
let has_bob = router_owners
.iter()
.any(|(_, email, _)| email == "bob@dev.io");
assert!(has_bob, "Bob should have ownership of router.ts");
}
}
#[test]
fn test_not_a_git_repo() {
let non_git_path = fixture_path("ts-sample");
let file_paths: Vec<String> = vec![];
let result = analyze_repo(&non_git_path, &file_paths);
assert!(result.is_err(), "should error for non-git directory");
}