use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BatchActionResult {
pub index: usize,
pub success: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub location: Option<url::Url>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
impl BatchActionResult {
pub fn success(index: usize, location: Option<url::Url>) -> Self {
Self {
index,
success: true,
location,
error: None,
}
}
pub fn failure(index: usize, error: String) -> Self {
Self {
index,
success: false,
location: None,
error: Some(error),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BatchActionResponse {
pub results: Vec<BatchActionResult>,
}
impl BatchActionResponse {
pub fn new(results: Vec<BatchActionResult>) -> Self {
Self { results }
}
pub fn is_all_success(&self) -> bool {
self.results.iter().all(|r| r.success)
}
pub fn failed_count(&self) -> usize {
self.results.iter().filter(|r| !r.success).count()
}
pub fn success_count(&self) -> usize {
self.results.iter().filter(|r| r.success).count()
}
}
impl IntoIterator for BatchActionResponse {
type Item = BatchActionResult;
type IntoIter = std::vec::IntoIter<BatchActionResult>;
fn into_iter(self) -> Self::IntoIter {
self.results.into_iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn batch_result_success() {
let result =
BatchActionResult::success(0, Some("https://example.com/post/1".parse().unwrap()));
assert!(result.success);
assert_eq!(result.index, 0);
assert!(result.location.is_some());
assert!(result.error.is_none());
}
#[test]
fn batch_result_failure() {
let result = BatchActionResult::failure(1, "Something went wrong".to_string());
assert!(!result.success);
assert_eq!(result.index, 1);
assert!(result.location.is_none());
assert!(result.error.is_some());
}
#[test]
fn batch_response_all_success() {
let response = BatchActionResponse::new(vec![
BatchActionResult::success(0, None),
BatchActionResult::success(1, None),
]);
assert!(response.is_all_success());
assert_eq!(response.success_count(), 2);
assert_eq!(response.failed_count(), 0);
}
#[test]
fn batch_response_partial_success() {
let response = BatchActionResponse::new(vec![
BatchActionResult::success(0, None),
BatchActionResult::failure(1, "Failed".to_string()),
BatchActionResult::success(2, None),
]);
assert!(!response.is_all_success());
assert_eq!(response.success_count(), 2);
assert_eq!(response.failed_count(), 1);
}
#[test]
fn batch_response_serialization() {
let response = BatchActionResponse::new(vec![
BatchActionResult::success(0, Some("https://example.com/post/1".parse().unwrap())),
BatchActionResult::failure(1, "Invalid request".to_string()),
]);
let json = serde_json::to_string(&response).unwrap();
assert!(json.contains("\"index\":0"));
assert!(json.contains("\"success\":true"));
assert!(json.contains("\"index\":1"));
assert!(json.contains("\"success\":false"));
}
#[test]
fn batch_response_deserialization() {
let json = r#"{"results":[{"index":0,"success":true,"location":"https://example.com"},{"index":1,"success":false,"error":"Failed"}]}"#;
let response: BatchActionResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.results.len(), 2);
assert!(response.results[0].success);
assert!(!response.results[1].success);
}
}