use crate::base::Item;
use super::{
execute::ExecutionError,
plan::{CollectionAction, ItemAction, PropertyAction},
};
#[derive(Debug)]
pub struct SyncError<I: Item> {
action: SomeAction<I>,
error: ExecutionError,
}
impl<I: Item> SyncError<I> {
#[must_use]
pub fn item(action: ItemAction<I>, error: ExecutionError) -> Self {
Self {
action: SomeAction::Item(Box::from(action)),
error,
}
}
#[must_use]
pub fn collection(action: CollectionAction, alias: String, error: ExecutionError) -> Self {
Self {
action: SomeAction::Collection { action, alias },
error,
}
}
#[must_use]
pub fn property(action: PropertyAction, error: ExecutionError) -> Self {
Self {
action: SomeAction::Property(action),
error,
}
}
}
impl<I: Item> std::fmt::Display for SyncError<I> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Error executing {}: {}", self.action, self.error)
}
}
impl<I: Item> std::error::Error for SyncError<I> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.error)
}
}
#[derive(Debug)]
pub enum SomeAction<I: Item> {
Item(Box<ItemAction<I>>),
Collection {
action: CollectionAction,
alias: String,
},
Property(PropertyAction),
}
impl<I: Item> std::fmt::Display for SomeAction<I> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SomeAction::Item(action) => {
write!(f, "item action '{action}'")
}
SomeAction::Collection { action, alias } => {
write!(f, "collection action '{action}' for '{alias}'")
}
SomeAction::Property(action) => {
write!(f, "property action '{action}'")
}
}
}
}
#[cfg(test)]
mod test {
use std::backtrace::Backtrace;
use crate::{
base::IcsItem,
sync::{
error::SomeAction,
execute::ExecutionError,
plan::{CollectionAction, ItemAction},
status::{ItemState, Side},
},
};
use super::SyncError;
#[test]
fn test_syncerror_item_display() {
let err = SyncError {
action: SomeAction::Item(Box::from(ItemAction::Create {
side: Side::A,
source: ItemState::<IcsItem> {
href: "/path/to/some/file.vcf".into(),
uid: "d99ed506-dceb-49f2-a1c9-efa63c68acd0".into(),
etag: "123890".into(),
hash: "AAAAAZZZZZ".into(),
data: None,
},
})),
error: ExecutionError::Storage(crate::Error {
kind: crate::ErrorKind::AccessDenied,
source: Some(Box::from(std::io::Error::new(
std::io::ErrorKind::PermissionDenied,
"Not enough mana",
))),
backtrace: Backtrace::capture(),
}),
};
let msg = err.to_string();
let expected = concat!(
"Error executing item action 'create in storage a (uid: d99ed506-dceb-49f2-a1c9-efa63c68acd0)': ",
"storage operation returned error: ",
"access to the resource was denied: ",
"Not enough mana"
);
assert_eq!(msg, expected);
}
#[test]
fn test_syncerror_collection_display() {
let err = SyncError::<IcsItem> {
action: SomeAction::Collection {
action: CollectionAction::CreateInB,
alias: "guests".into(),
},
error: ExecutionError::Storage(crate::Error {
kind: crate::ErrorKind::AccessDenied,
source: Some(Box::from(std::io::Error::new(
std::io::ErrorKind::PermissionDenied,
"Creating new collections is forbidden",
))),
backtrace: Backtrace::capture(),
}),
};
let msg = err.to_string();
let expected = concat!(
"Error executing collection action 'create in storage b' for 'guests': ",
"storage operation returned error: ",
"access to the resource was denied: ",
"Creating new collections is forbidden"
);
assert_eq!(msg, expected);
}
}