bcore_mutation/
coverage.rs1use crate::error::{MutationError, Result};
2use regex::Regex;
3use std::collections::HashMap;
4use std::fs;
5use std::path::Path;
6
7pub fn parse_coverage_file(coverage_file_path: &Path) -> Result<HashMap<String, Vec<usize>>> {
8 let content = fs::read_to_string(coverage_file_path)?;
9 let mut coverage_data: HashMap<String, Vec<usize>> = HashMap::new();
10 let mut current_file: Option<String> = None;
11
12 let file_pattern = Regex::new(r"^SF:(.+)$")?; let line_pattern = Regex::new(r"^DA:(\d+),(\d+)$")?; for line in content.lines() {
17 let line = line.trim();
18
19 if let Some(captures) = file_pattern.captures(line) {
21 current_file = Some(captures[1].to_string());
22 coverage_data.insert(captures[1].to_string(), Vec::new());
23 continue;
24 }
25
26 if let Some(captures) = line_pattern.captures(line) {
28 if let Some(ref file) = current_file {
29 let line_number: usize = captures[1]
30 .parse()
31 .map_err(|_| MutationError::Coverage("Invalid line number".to_string()))?;
32 let hits: usize = captures[2]
33 .parse()
34 .map_err(|_| MutationError::Coverage("Invalid hit count".to_string()))?;
35
36 if hits > 0 {
37 if let Some(lines) = coverage_data.get_mut(file) {
38 if !lines.contains(&line_number) {
39 lines.push(line_number);
40 }
41 }
42 }
43 }
44 }
45 }
46
47 Ok(coverage_data)
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use std::io::Write;
54 use tempfile::NamedTempFile;
55
56 #[test]
57 fn test_parse_coverage_file() {
58 let mut temp_file = NamedTempFile::new().unwrap();
59 writeln!(temp_file, "SF:/path/to/file1.cpp").unwrap();
60 writeln!(temp_file, "DA:1,5").unwrap();
61 writeln!(temp_file, "DA:2,0").unwrap();
62 writeln!(temp_file, "DA:3,10").unwrap();
63 writeln!(temp_file, "SF:/path/to/file2.cpp").unwrap();
64 writeln!(temp_file, "DA:10,1").unwrap();
65 writeln!(temp_file, "DA:11,0").unwrap();
66
67 let result = parse_coverage_file(temp_file.path()).unwrap();
68
69 assert_eq!(result.len(), 2);
70 assert_eq!(result["/path/to/file1.cpp"], vec![1, 3]);
71 assert_eq!(result["/path/to/file2.cpp"], vec![10]);
72 }
73}