use std::io::Write;
use anyhow::Result;
use serde::Serialize;
use crate::cli::gmail::format::{write_scalar_jsonl, JsonlSerialize};
#[derive(Debug, Default, Serialize)]
pub(crate) struct ExtractAttachmentsReport {
pub(crate) actions: Vec<ExtractAction>,
pub(crate) errors: Vec<ExtractError>,
}
impl JsonlSerialize for ExtractAttachmentsReport {
fn write_jsonl(&self, out: &mut dyn Write) -> Result<()> {
write_scalar_jsonl(self, out)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub(crate) enum ExtractAction {
Extracted { id: String, count: usize },
WouldExtract { id: String, count: usize },
}
#[derive(Debug, Clone, Serialize)]
pub(crate) struct ExtractError {
pub(crate) id: String,
pub(crate) reason: String,
}
#[derive(Debug, Default, PartialEq, Eq, Serialize)]
pub(crate) struct ExtractSummary {
pub(crate) extracted: usize,
pub(crate) would_extract: usize,
pub(crate) errors: usize,
}
impl ExtractAttachmentsReport {
pub(crate) fn summary(&self) -> ExtractSummary {
let mut summary = ExtractSummary {
errors: self.errors.len(),
..ExtractSummary::default()
};
for action in &self.actions {
match action {
ExtractAction::Extracted { .. } => summary.extracted += 1,
ExtractAction::WouldExtract { .. } => summary.would_extract += 1,
}
}
summary
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
#[test]
fn summary_counts_each_action_variant() {
let report = ExtractAttachmentsReport {
actions: vec![
ExtractAction::Extracted {
id: "m1".to_string(),
count: 2,
},
ExtractAction::WouldExtract {
id: "m2".to_string(),
count: 1,
},
],
errors: vec![ExtractError {
id: "m3".to_string(),
reason: "boom".to_string(),
}],
};
assert_eq!(
report.summary(),
ExtractSummary {
extracted: 1,
would_extract: 1,
errors: 1,
}
);
}
#[test]
fn summary_of_empty_report_is_all_zero() {
assert_eq!(
ExtractAttachmentsReport::default().summary(),
ExtractSummary::default()
);
}
}