use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileCoverage {
pub path: String,
#[serde(rename = "statementMap")]
pub statement_map: BTreeMap<String, Location>,
#[serde(rename = "fnMap")]
pub fn_map: BTreeMap<String, FnEntry>,
#[serde(rename = "branchMap")]
pub branch_map: BTreeMap<String, BranchEntry>,
#[serde(deserialize_with = "deserialize_null_as_zero_map")]
pub s: BTreeMap<String, u32>,
#[serde(deserialize_with = "deserialize_null_as_zero_map")]
pub f: BTreeMap<String, u32>,
#[serde(deserialize_with = "deserialize_null_as_zero_vec_map")]
pub b: BTreeMap<String, Vec<u32>>,
#[serde(rename = "inputSourceMap", skip_serializing_if = "Option::is_none")]
pub input_source_map: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Location {
pub start: Position,
pub end: Position,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Position {
#[serde(default, deserialize_with = "deserialize_null_as_zero")]
pub line: u32,
#[serde(default, deserialize_with = "deserialize_null_as_zero")]
pub column: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FnEntry {
pub name: String,
#[serde(default, deserialize_with = "deserialize_null_as_zero")]
pub line: u32,
pub decl: Location,
pub loc: Location,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BranchEntry {
pub loc: Location,
#[serde(default, deserialize_with = "deserialize_null_as_zero")]
pub line: u32,
#[serde(rename = "type")]
pub branch_type: String,
pub locations: Vec<Location>,
}
fn deserialize_null_as_zero<'de, D>(deserializer: D) -> Result<u32, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(Option::<u32>::deserialize(deserializer)?.unwrap_or(0))
}
fn deserialize_null_as_zero_map<'de, D>(deserializer: D) -> Result<BTreeMap<String, u32>, D::Error>
where
D: serde::Deserializer<'de>,
{
let raw: BTreeMap<String, Option<u32>> = Deserialize::deserialize(deserializer)?;
Ok(raw.into_iter().map(|(k, v)| (k, v.unwrap_or(0))).collect())
}
fn deserialize_null_as_zero_vec_map<'de, D>(
deserializer: D,
) -> Result<BTreeMap<String, Vec<u32>>, D::Error>
where
D: serde::Deserializer<'de>,
{
let raw: BTreeMap<String, Option<Vec<Option<u32>>>> = Deserialize::deserialize(deserializer)?;
Ok(raw
.into_iter()
.map(|(k, v)| {
let vec = v.unwrap_or_default().into_iter().map(|x| x.unwrap_or(0)).collect();
(k, vec)
})
.collect())
}
impl FileCoverage {
pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(json)
}
pub(crate) fn from_maps(
path: String,
statement_map: BTreeMap<String, Location>,
fn_map: BTreeMap<String, FnEntry>,
branch_map: BTreeMap<String, BranchEntry>,
) -> Self {
let s = statement_map.keys().map(|k| (k.clone(), 0)).collect();
let f = fn_map.keys().map(|k| (k.clone(), 0)).collect();
let b = branch_map
.iter()
.map(|(k, entry)| (k.clone(), vec![0; entry.locations.len()]))
.collect();
Self { path, statement_map, fn_map, branch_map, s, f, b, input_source_map: None }
}
}