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