use serde::{Deserialize, Serialize};
use crate::validation::{Validate, ValidationError};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct ResetDataRequest {
pub confirm: String,
}
impl Validate for ResetDataRequest {
fn validate(&self) -> Result<(), ValidationError> {
if self.confirm != "RESET" {
return Err(ValidationError {
field: "confirm",
message: "confirm must be exactly \"RESET\"".to_string(),
});
}
Ok(())
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct ResetDataResponse {
pub deleted: ResetDeletedCounts,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct ResetDeletedCounts {
pub hosts: u64,
pub software_items: u64,
pub plugin_configs: u64,
pub host_tags: u64,
pub update_history: u64,
pub update_batches: u64,
}
#[cfg(test)]
mod tests {
#![expect(
clippy::assertions_on_result_states,
reason = "test assertions — is_ok/is_err provides readable failure messages"
)]
use super::*;
#[test]
fn validate_accepts_reset() {
let req = ResetDataRequest {
confirm: "RESET".to_string(),
};
assert!(req.validate().is_ok());
}
#[test]
fn validate_rejects_wrong_confirm() {
let req = ResetDataRequest {
confirm: "reset".to_string(),
};
let err = req.validate().unwrap_err();
assert_eq!(err.field, "confirm");
}
#[test]
fn validate_rejects_empty() {
let req = ResetDataRequest {
confirm: String::new(),
};
assert!(req.validate().is_err());
}
#[test]
fn response_serde_round_trip() {
let resp = ResetDataResponse {
deleted: ResetDeletedCounts {
hosts: 5,
software_items: 10,
plugin_configs: 3,
host_tags: 2,
update_history: 100,
update_batches: 4,
},
};
let json = serde_json::to_string(&resp).unwrap();
let deserialized: ResetDataResponse = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized.deleted.hosts, 5);
assert_eq!(deserialized.deleted.update_history, 100);
}
}