use thiserror::Error;
#[derive(Error, Debug)]
pub enum AppError {
#[error("I/O error accessing path '{path}': {source}")]
IoError {
path: String, #[source]
source: std::io::Error,
},
#[error("Invalid configuration: {0}")]
ConfigError(String),
#[cfg(feature = "clipboard")]
#[error("Clipboard error: {0}")]
ClipboardError(String),
#[error("Operation cancelled by user (Ctrl+C)")]
Interrupted,
}
pub fn io_error_with_path<P: AsRef<std::path::Path>>(source: std::io::Error, path: P) -> AppError {
AppError::IoError {
path: path.as_ref().display().to_string(),
source,
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::{io, path::PathBuf};
#[test]
fn test_io_error_with_path_helper() {
let path = PathBuf::from("some/test/path.txt"); let source_error = io::Error::new(io::ErrorKind::NotFound, "File not found");
let app_error = io_error_with_path(source_error, &path);
match app_error {
AppError::IoError {
path: error_path,
source,
} => {
assert!(error_path.contains("some/test/path.txt")); assert_eq!(source.kind(), io::ErrorKind::NotFound);
assert!(source.to_string().contains("File not found"));
}
_ => panic!("Expected AppError::IoError"),
}
let path_str = "another/path";
let source_error_perm = io::Error::new(io::ErrorKind::PermissionDenied, "Access denied");
let app_error_perm = io_error_with_path(source_error_perm, path_str); match app_error_perm {
AppError::IoError {
path: error_path,
source,
} => {
assert!(error_path.contains("another/path")); assert_eq!(source.kind(), io::ErrorKind::PermissionDenied);
assert!(source.to_string().contains("Access denied"));
}
_ => panic!("Expected AppError::IoError"),
}
}
}