1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use crate::config::Config;
use crate::errors::RunError;
use crate::traces::{CoverageStat, TraceMap};
use std::fs::File;
use std::io::Write;
pub fn export(coverage_data: &TraceMap, config: &Config) -> Result<(), RunError> {
let file_path = config.output_directory.join("lcov.info");
let mut file = match File::create(file_path) {
Ok(k) => k,
Err(e) => {
return Err(RunError::Lcov(format!(
"File is not writeable: {}",
e.to_string()
)))
}
};
for (path, traces) in coverage_data.iter() {
writeln!(file, "TN:")?;
writeln!(file, "SF:{}", path.to_str().unwrap())?;
let mut fns: Vec<String> = vec![];
let mut fnda: Vec<String> = vec![];
let mut da: Vec<(u64, u64)> = vec![];
for trace in traces {
if trace.fn_name.is_some() {
let fn_name = trace.fn_name.clone().unwrap();
let fn_hits = match trace.stats {
CoverageStat::Line(hits) => hits,
_ => {
return Err(RunError::Lcov(
"Function doesn't have hits number".to_string(),
))
}
};
fns.push(format!("FN:{},{}", trace.line, fn_name));
fnda.push(format!("FNDA:{},{}", fn_hits, fn_name));
}
match trace.stats {
CoverageStat::Line(hits) => da.push((trace.line, hits)),
_ => (),
};
}
for fn_line in fns.iter() {
writeln!(file, "{}", fn_line)?;
}
writeln!(file, "FNF:{}", fns.len())?;
for fnda_line in fnda {
writeln!(file, "{}", fnda_line)?;
}
for (line, hits) in da.iter() {
writeln!(file, "DA:{},{}", line, hits)?;
}
writeln!(file, "LF:{}", da.len())?;
writeln!(
file,
"LH:{}",
da.iter().filter(|(_, hits)| *hits != 0).count()
)?;
writeln!(file, "end_of_record")?;
}
Ok(())
}