use std::time::Duration;
use serde::{ser::SerializeStruct, Deserialize, Serialize};
use crate::{Check, CheckId, FixResult, Status, StatusCode};
#[derive(Debug, Clone, Deserialize)]
pub struct CheckResult {
pub check_id: CheckId,
pub check_name: String,
pub check_rationale: String,
pub filename: Option<String>,
#[serde(default)]
pub source_filename: Option<String>,
pub section: Option<String>,
pub subresults: Vec<Status>,
pub hotfix_result: Option<FixResult>,
pub sourcefix_result: Option<FixResult>,
#[serde(default)]
pub time: Duration,
pub hotfix_available: bool,
pub sourcefix_available: bool,
}
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())?;
s.serialize_field("hotfix_available", &self.hotfix_available)?;
s.serialize_field("sourcefix_available", &self.sourcefix_available)?;
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,
hotfix_available: check.hotfix.is_some(),
sourcefix_available: check.fix_source.is_some(),
}
}
pub fn worst_status(&self) -> StatusCode {
self.subresults
.iter()
.map(|x| x.severity)
.max()
.unwrap_or(StatusCode::Pass)
}
pub fn is_fatal(&self) -> bool {
self.worst_status() == StatusCode::Fatal
}
pub fn is_error(&self) -> bool {
self.worst_status() == StatusCode::Error
}
}