use std::time::Duration;
use serde::{ser::SerializeStruct, Serialize};
use crate::{Check, CheckId, Status, StatusCode};
#[derive(Debug, Clone, Serialize)]
pub enum FixResult {
Available,
Unfixable,
Fixed,
FixError(String),
}
#[derive(Debug, Clone)]
pub struct CheckResult {
pub check_id: CheckId,
pub check_name: String,
pub check_rationale: String,
pub filename: Option<String>,
pub source_filename: Option<String>,
pub section: Option<String>,
pub subresults: Vec<Status>,
pub hotfix_result: Option<FixResult>,
pub sourcefix_result: Option<FixResult>,
pub time: Duration,
}
impl Serialize for CheckResult {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let fields =
7 + self.hotfix_result.is_some() as usize + self.sourcefix_result.is_some() as usize;
let mut s = serializer.serialize_struct("CheckResult", fields)?;
s.serialize_field("check_id", &self.check_id)?;
s.serialize_field("check_name", &self.check_name)?;
s.serialize_field("check_rationale", &self.check_rationale)?;
s.serialize_field("filename", &self.filename)?;
s.serialize_field("section", &self.section)?;
s.serialize_field("subresults", &self.subresults)?;
s.serialize_field("worst_status", &self.worst_status())?;
if let Some(hotfix_result) = &self.hotfix_result {
s.serialize_field("hotfix_result", hotfix_result)?;
}
if let Some(sourcefix_result) = &self.sourcefix_result {
s.serialize_field("sourcefix_result", sourcefix_result)?;
}
s.end()
}
}
impl CheckResult {
pub fn new(
check: &Check,
filename: Option<&str>,
source_filename: Option<&str>,
section: Option<&str>,
subresults: Vec<Status>,
duration: Duration,
) -> Self {
Self {
check_id: check.id.to_string(),
check_name: check.title.to_string(),
check_rationale: check.rationale.to_string(),
filename: filename.map(|x| x.to_string()),
source_filename: source_filename.map(|x| x.to_string()),
section: section.map(|x| x.to_string()),
subresults,
hotfix_result: None,
sourcefix_result: None,
time: duration,
}
}
pub fn worst_status(&self) -> StatusCode {
self.subresults
.iter()
.map(|x| x.severity)
.max()
.unwrap_or(StatusCode::Pass)
}
pub fn is_error(&self) -> bool {
self.worst_status() == StatusCode::Error
}
}