crap4rust/
coverage_index.rs1use std::collections::HashMap;
6
7use crate::model::{CoverageRecord, SourceFunction};
8
9pub struct CoverageIndex {
10 inner: HashMap<(String, usize), CoverageRecord>,
11}
12
13impl CoverageIndex {
14 pub fn from_records(records: Vec<CoverageRecord>) -> Self {
15 let mut inner = HashMap::new();
16 for record in records {
17 let key = (record.path_key.clone(), record.line);
18 inner
19 .entry(key)
20 .and_modify(|existing: &mut CoverageRecord| {
21 if record.covered_regions > 0 || existing.covered_regions == 0 {
22 existing.covered_regions += record.covered_regions;
23 existing.total_regions += record.total_regions;
24 }
25 })
26 .or_insert(record);
27 }
28 Self { inner }
29 }
30
31 pub fn match_function(&self, function: &SourceFunction) -> Option<f64> {
32 match_function_coverage(function, &self.inner).map(|record| record.coverage_ratio())
33 }
34
35 pub fn get(&self, path_key: &str, line: usize) -> Option<&CoverageRecord> {
36 self.inner.get(&(path_key.to_string(), line))
37 }
38}
39
40pub fn match_function_coverage(
41 function: &SourceFunction,
42 coverage_index: &HashMap<(String, usize), CoverageRecord>,
43) -> Option<CoverageRecord> {
44 let matching: Vec<&CoverageRecord> = coverage_index
45 .iter()
46 .filter(|((path_key, line), _)| {
47 path_key == &function.path_key && *line >= function.line && *line <= function.end_line
48 })
49 .map(|(_, record)| record)
50 .collect();
51
52 if matching.is_empty() {
53 return None;
54 }
55
56 let covered_regions = matching.iter().map(|r| r.covered_regions).sum();
57 let total_regions = matching.iter().map(|r| r.total_regions).sum();
58
59 Some(CoverageRecord {
60 path_key: function.path_key.clone(),
61 line: function.line,
62 covered_regions,
63 total_regions,
64 })
65}