gitstack/
related_files.rs1use std::collections::HashMap;
6
7#[derive(Debug, Clone)]
9pub struct RelatedFiles {
10 pub target_file: String,
12 pub related: Vec<(String, usize)>,
14}
15
16pub fn analyze_related_files<I>(target_file: &str, commit_files: I) -> RelatedFiles
21where
22 I: Iterator<Item = Vec<String>>,
23{
24 let mut co_change_counts: HashMap<String, usize> = HashMap::new();
25
26 for files in commit_files {
27 if files.iter().any(|f| f == target_file) {
29 for file in files {
31 if file != target_file {
32 *co_change_counts.entry(file).or_insert(0) += 1;
33 }
34 }
35 }
36 }
37
38 let mut related: Vec<(String, usize)> = co_change_counts.into_iter().collect();
40 related.sort_by(|a, b| b.1.cmp(&a.1));
41
42 related.truncate(20);
44
45 RelatedFiles {
46 target_file: target_file.to_string(),
47 related,
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn test_analyze_related_files_basic() {
57 let commits = vec![
58 vec!["src/a.rs".to_string(), "src/b.rs".to_string()],
59 vec!["src/a.rs".to_string(), "src/c.rs".to_string()],
60 vec![
61 "src/a.rs".to_string(),
62 "src/b.rs".to_string(),
63 "src/c.rs".to_string(),
64 ],
65 vec!["src/d.rs".to_string()], ];
67
68 let result = analyze_related_files("src/a.rs", commits.into_iter());
69
70 assert_eq!(result.target_file, "src/a.rs");
71 assert!(result
73 .related
74 .iter()
75 .any(|(f, c)| f == "src/b.rs" && *c == 2));
76 assert!(result
77 .related
78 .iter()
79 .any(|(f, c)| f == "src/c.rs" && *c == 2));
80 assert!(!result.related.iter().any(|(f, _)| f == "src/d.rs"));
82 }
83
84 #[test]
85 fn test_analyze_related_files_no_target() {
86 let commits = vec![
87 vec!["src/x.rs".to_string(), "src/y.rs".to_string()],
88 vec!["src/z.rs".to_string()],
89 ];
90
91 let result = analyze_related_files("src/a.rs", commits.into_iter());
92
93 assert!(result.related.is_empty());
94 }
95
96 #[test]
97 fn test_analyze_related_files_empty() {
98 let commits: Vec<Vec<String>> = vec![];
99 let result = analyze_related_files("src/a.rs", commits.into_iter());
100 assert!(result.related.is_empty());
101 }
102}