#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct FidelityReport {
pub backend: String,
pub dropped: Vec<LossNote>,
pub preserved_extras: Vec<String>,
pub warnings: Vec<String>,
}
impl FidelityReport {
#[must_use]
pub fn new(backend: impl Into<String>) -> Self {
Self {
backend: backend.into(),
..Self::default()
}
}
#[must_use]
pub fn is_lossless(&self) -> bool {
self.dropped.is_empty()
}
#[must_use]
pub fn with_dropped(mut self, field: impl Into<String>, reason: impl Into<String>) -> Self {
self.dropped.push(LossNote::new(field, reason));
self
}
#[must_use]
pub fn with_preserved_extra(mut self, extra: impl Into<String>) -> Self {
self.preserved_extras.push(extra.into());
self
}
#[must_use]
pub fn with_warning(mut self, warning: impl Into<String>) -> Self {
self.warnings.push(warning.into());
self
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LossNote {
pub field: String,
pub reason: String,
}
impl LossNote {
#[must_use]
pub fn new(field: impl Into<String>, reason: impl Into<String>) -> Self {
Self {
field: field.into(),
reason: reason.into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn warnings_survive_report_building() {
let report = FidelityReport::new("codec/plain")
.with_preserved_extra("raw-styles")
.with_warning("formula cached value differed");
assert!(report.is_lossless());
assert_eq!(report.warnings, vec!["formula cached value differed"]);
assert_eq!(report.preserved_extras, vec!["raw-styles"]);
}
#[test]
fn dropped_report_is_not_lossless() {
let report = FidelityReport::new("codec/plain")
.with_dropped("sheet.hiddenRows", "backend does not expose hidden rows");
assert!(!report.is_lossless());
assert_eq!(report.dropped[0].field, "sheet.hiddenRows");
}
}