1use crate::coverage::{PackageCoverage, TotalCoverage};
2use crate::error::*;
3use crate::rule::{default_rules, Rule, SourceCode};
4
5pub struct CoverageFixer {
11 rules: Vec<Box<dyn Rule>>,
12}
13
14impl CoverageFixer {
15 pub fn new() -> Self {
16 Self {
17 rules: default_rules(),
18 }
19 }
20
21 pub fn with_rules<I: Into<Vec<Box<dyn Rule>>>>(rules: I) -> Self {
22 Self {
23 rules: rules.into(),
24 }
25 }
26
27 pub fn fix(&self, data: &mut PackageCoverage) -> Result<(), Error> {
29 if self.rules.is_empty() {
30 debugln!("Skipping fix because rules are empty");
31 }
32
33 let old = CoverageSummary::new(data);
34
35 debugln!("Fixing package coverage");
36 for file_cov in &mut data.file_coverages {
37 file_cov.line_coverages.sort_by_key(|v| v.line_number);
38 file_cov.branch_coverages.sort_by_key(|v| v.line_number);
39
40 let path = file_cov.path();
41 debugln!("Processing file {:?}", path);
42
43 let source = SourceCode::new(path)?;
44
45 for rule in self.rules.iter() {
46 rule.fix_file_coverage(&source, file_cov);
47 }
48
49 file_cov.line_coverages.retain(|v| v.count.is_some());
50 file_cov.branch_coverages.retain(|v| v.taken.is_some());
51 }
52
53 let new = CoverageSummary::new(data);
54
55 infoln!("Coverages are fixed successfully!");
56
57 infoln!(
58 " line: {:.2}% ({} of {} lines) => {:.2}% ({} of {} lines)",
59 old.line_percent(),
60 old.line_executed,
61 old.line_total,
62 new.line_percent(),
63 new.line_executed,
64 new.line_total,
65 );
66
67 infoln!(
68 " branch: {:.2}% ({} of {} branches) => {:.2}% ({} of {} branches)\n",
69 old.branch_percent(),
70 old.branch_executed,
71 old.branch_total,
72 new.branch_percent(),
73 new.branch_executed,
74 new.branch_total,
75 );
76
77 Ok(())
78 }
79}
80
81impl Default for CoverageFixer {
82 fn default() -> Self {
83 Self::new()
84 }
85}
86
87struct CoverageSummary {
88 line_executed: usize,
89 line_total: usize,
90 branch_executed: usize,
91 branch_total: usize,
92}
93
94impl CoverageSummary {
95 fn new(data: &PackageCoverage) -> Self {
96 Self {
97 line_executed: data.line_executed(),
98 line_total: data.line_total(),
99 branch_executed: data.branch_executed(),
100 branch_total: data.branch_total(),
101 }
102 }
103
104 fn line_percent(&self) -> f64 {
105 (self.line_executed as f64) / (self.line_total as f64) * 100.0
106 }
107
108 fn branch_percent(&self) -> f64 {
109 (self.branch_executed as f64) / (self.branch_total as f64) * 100.0
110 }
111}