Skip to main content

crap4rust/
coverage_index.rs

1// Copyright 2025 Umberto Gotti <umberto.gotti@umbertogotti.dev>
2// Licensed under the MIT License or Apache License, Version 2.0
3// SPDX-License-Identifier: MIT OR Apache-2.0
4
5use 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}