#![cfg(test)]
use std::path::Path;
use code_repo_wiki::analysis;
use code_repo_wiki::ingest;
fn build_fixture_repo(repo: &Path) -> anyhow::Result<()> {
std::fs::create_dir_all(repo.join("src").join("a"))?;
std::fs::create_dir_all(repo.join("src").join("b"))?;
std::fs::write(
repo.join("src").join("a").join("lib.rs"),
r#"
//! 模块 A 入口
pub mod helper;
pub fn process(data: &[u8]) -> u32 {
helper::checksum(data)
}
"#,
)?;
std::fs::write(
repo.join("src").join("a").join("helper.rs"),
r#"
//! 模块 A 辅助函数
pub fn checksum(data: &[u8]) -> u32 {
data.iter().fold(0u32, |acc, b| acc.wrapping_add(*b as u32))
}
"#,
)?;
std::fs::write(
repo.join("src").join("b").join("mod.rs"),
r#"
//! 模块 B:独立功能,与 A 无依赖
pub fn beta() -> &'static str { "beta" }
"#,
)?;
Ok(())
}
#[test]
fn test_community_detection_and_features() {
let tmp = std::env::temp_dir().join(format!(
"code_repo_wiki_clustering_test_{}",
std::process::id()
));
let _ = std::fs::remove_dir_all(&tmp);
build_fixture_repo(&tmp).expect("构造测试仓库失败");
let root = code_repo_wiki::project::ProjectRoot::new(tmp.clone());
let result = (|| -> anyhow::Result<()> {
let insights = ingest::scan_and_parse_at(&root)?.insights;
assert!(!insights.is_empty(), "应扫描到源文件");
let mut graph = analysis::build_graph(&insights)?;
graph.features = code_repo_wiki::analysis::feature::detect_features(&graph, None)?;
assert!(
!graph.modules.is_empty(),
"a/b 两个独立目录应检出模块"
);
let mut names: Vec<&str> = graph.modules.iter().map(|m| m.name.as_str()).collect();
names.sort();
names.dedup();
assert_eq!(
names.len(),
graph.modules.len(),
"模块名必须唯一: {:?}",
names
);
for name in &names {
assert!(
!name.contains(".rs"),
"模块名不能含文件名(文件名当目录段是错误命名): {name}"
);
}
assert!(
names.iter().any(|n| n.ends_with("a")),
"a 目录应检出一个模块,实际: {names:?}"
);
assert!(
names.iter().any(|n| n.ends_with("b")),
"b 目录应检出一个模块,实际: {names:?}"
);
assert!(
!graph.features.is_empty(),
"a 目录的跨文件调用应形成特征"
);
let feature_names: Vec<String> = graph
.features
.iter()
.flat_map(|f| {
f.node_ids
.iter()
.map(|nid| {
graph
.graph
.node_weight(*nid)
.map(|n| n.name.clone())
.unwrap_or_default()
})
.collect::<Vec<_>>()
})
.collect();
assert!(
feature_names.iter().any(|n| n == "checksum"),
"特征应包含 checksum: {feature_names:?}"
);
assert!(
feature_names.iter().any(|n| n == "process"),
"特征应包含 process: {feature_names:?}"
);
Ok(())
})();
let _ = std::fs::remove_dir_all(&tmp);
result.expect("集成断言失败");
}