cargo_tarpaulin/report/
json.rs

1use crate::config::Config;
2use crate::errors::*;
3use crate::traces::{Trace, TraceMap};
4use serde::Serialize;
5use std::{fs, io::Write};
6
7#[derive(Serialize)]
8struct SourceFile {
9    path: Vec<String>,
10    content: String,
11    traces: Vec<Trace>,
12    covered: usize,
13    coverable: usize,
14}
15
16#[derive(Serialize)]
17pub struct CoverageReport {
18    files: Vec<SourceFile>,
19    coverage: f64,
20    covered: usize,
21    coverable: usize,
22}
23
24impl From<&TraceMap> for Vec<SourceFile> {
25    fn from(coverage_data: &TraceMap) -> Self {
26        coverage_data
27            .iter()
28            .map(|(path, traces)| -> Result<SourceFile, RunError> {
29                let content = fs::read_to_string(path).map_err(RunError::from)?;
30                Ok(SourceFile {
31                    path: path
32                        .components()
33                        .map(|c| c.as_os_str().to_string_lossy().to_string())
34                        .collect(),
35                    content,
36                    traces: traces.clone(),
37                    covered: coverage_data.covered_in_path(path),
38                    coverable: coverage_data.coverable_in_path(path),
39                })
40            })
41            .filter_map(Result::ok)
42            .collect()
43    }
44}
45
46impl From<&TraceMap> for CoverageReport {
47    fn from(coverage_data: &TraceMap) -> Self {
48        CoverageReport {
49            files: Vec::<SourceFile>::from(coverage_data),
50            coverage: 100.0 * coverage_data.coverage_percentage(),
51            covered: coverage_data.total_covered(),
52            coverable: coverage_data.total_coverable(),
53        }
54    }
55}
56
57type JsonStringResult = Result<String, serde_json::error::Error>;
58
59impl From<&TraceMap> for JsonStringResult {
60    fn from(val: &TraceMap) -> Self {
61        serde_json::to_string(&CoverageReport::from(val))
62    }
63}
64
65pub fn export(coverage_data: &TraceMap, config: &Config) -> Result<(), RunError> {
66    let file_path = config.output_dir().join("tarpaulin-report.json");
67    let report: JsonStringResult = coverage_data.into();
68    fs::File::create(file_path)?
69        .write_all(report?.as_bytes())
70        .map_err(RunError::from)
71}