qlty_coverage/parser/
coverprofile.rs

1use crate::Parser;
2use anyhow::Result;
3use qlty_types::tests::v1::FileCoverage;
4use regex::Regex;
5use std::collections::BTreeMap;
6
7pub struct Coverprofile {}
8
9impl Coverprofile {
10    pub fn new() -> Self {
11        Self {}
12    }
13
14    fn push_line_hits(
15        &self,
16        line_count_map: &BTreeMap<i64, i64>,
17        file_name: &str,
18        file_coverages: &mut Vec<FileCoverage>,
19    ) {
20        let mut line_hits: Vec<i64> = Vec::new();
21        if let Some(last_line) = line_count_map.last_key_value() {
22            if *last_line.0 > 0 {
23                for x in 1..=*last_line.0 {
24                    if line_count_map.contains_key(&x) {
25                        line_hits.push(*line_count_map.get(&x).unwrap());
26                    } else {
27                        line_hits.push(-1);
28                    }
29                }
30            }
31        }
32        let file_coverage = FileCoverage {
33            path: file_name.to_string(),
34            hits: line_hits,
35            ..Default::default()
36        };
37
38        file_coverages.push(file_coverage);
39    }
40}
41
42impl Parser for Coverprofile {
43    fn parse_text(&self, text: &str) -> Result<Vec<FileCoverage>> {
44        let mut file_coverages: Vec<FileCoverage> = vec![];
45        let mut current_file_name = "";
46        let re = Regex::new(r"(?<start_line>\d+)\.?\d+,(?<end_line>\d+)\.?\d+ ?\d+ (?<count>\d+)")
47            .unwrap();
48
49        // becuase the results are not sorted by line number, we need to keep track of the line numbers
50        let mut line_count_map: BTreeMap<i64, i64> = BTreeMap::new();
51
52        text.split("\n").skip(1).for_each(|line| {
53            if line.is_empty() {
54                return;
55            }
56
57            let tokens: Vec<_> = line.split(":").collect();
58            let file_name = tokens[0];
59            let line_info = tokens[1];
60
61            if current_file_name != file_name {
62                if current_file_name != "" {
63                    self.push_line_hits(&line_count_map, current_file_name, &mut file_coverages);
64                    line_count_map = BTreeMap::new();
65                }
66
67                current_file_name = file_name;
68            }
69
70            let regex_capture = re.captures(line_info).unwrap();
71            let start_line = regex_capture
72                .name("start_line")
73                .unwrap()
74                .as_str()
75                .parse::<i64>()
76                .unwrap();
77            let end_line = regex_capture
78                .name("end_line")
79                .unwrap()
80                .as_str()
81                .parse::<i64>()
82                .unwrap();
83            let count = regex_capture
84                .name("count")
85                .unwrap()
86                .as_str()
87                .parse::<i64>()
88                .unwrap();
89
90            for x in start_line..(end_line + 1) {
91                line_count_map.insert(x, count);
92            }
93        });
94
95        self.push_line_hits(&line_count_map, current_file_name, &mut file_coverages);
96
97        Ok(file_coverages)
98    }
99}