use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
fn default_track() -> bool {
true
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct LocalOutputsSpec {
#[serde(default = "default_track")]
pub track: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub retention_days: Option<u32>,
}
impl Default for LocalOutputsSpec {
fn default() -> Self {
Self {
track: true,
retention_days: None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_block_tracks_and_inherits_the_default_window() {
let spec: LocalOutputsSpec = serde_yaml::from_str("{}").unwrap();
assert!(spec.track);
assert_eq!(spec.retention_days, None);
assert_eq!(spec, LocalOutputsSpec::default());
}
#[test]
fn parses_a_retention_override() {
let spec: LocalOutputsSpec = serde_yaml::from_str("retention_days: 3").unwrap();
assert_eq!(spec.retention_days, Some(3));
assert!(spec.track, "tracking stays on unless explicitly disabled");
}
#[test]
fn parses_an_opt_out() {
let spec: LocalOutputsSpec = serde_yaml::from_str("track: false").unwrap();
assert!(!spec.track);
}
#[test]
fn zero_days_parses_as_keep_forever() {
let spec: LocalOutputsSpec = serde_yaml::from_str("retention_days: 0").unwrap();
assert_eq!(spec.retention_days, Some(0));
}
#[test]
fn rejects_unknown_fields() {
let err = serde_yaml::from_str::<LocalOutputsSpec>("retention_dayz: 3").unwrap_err();
assert!(err.to_string().contains("retention_dayz"), "{err}");
}
#[test]
fn schema_generates_with_both_fields() {
let schema = schemars::schema_for!(LocalOutputsSpec);
let v = serde_json::to_value(&schema).unwrap();
assert!(v["properties"]["track"].is_object());
assert!(v["properties"]["retention_days"].is_object());
}
#[test]
fn round_trips_through_yaml() {
let spec = LocalOutputsSpec {
track: false,
retention_days: Some(14),
};
let yaml = serde_yaml::to_string(&spec).unwrap();
assert_eq!(
serde_yaml::from_str::<LocalOutputsSpec>(&yaml).unwrap(),
spec
);
}
}