use thiserror::Error;
#[derive(Error, Debug)]
pub enum CopiaError {
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("Invalid block size: {0} (must be power of 2, 512-65536)")]
InvalidBlockSize(usize),
#[error("Invalid hash length: {0} (must be 4-32)")]
InvalidHashLength(usize),
#[error("Invalid copy bounds: offset {offset} + len {len} exceeds basis size {basis_size}")]
InvalidCopyBounds {
offset: u64,
len: u32,
basis_size: u64,
},
#[error("Checksum mismatch: expected {expected:?}, got {actual:?}")]
ChecksumMismatch {
expected: [u8; 32],
actual: [u8; 32],
},
#[error("Empty signature: cannot compute delta without signatures")]
EmptySignature,
#[error("Corrupted delta data")]
CorruptedDelta,
#[error("Protocol error: {0}")]
ProtocolError(String),
}
pub type Result<T> = std::result::Result<T, CopiaError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn error_display_io() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
let err = CopiaError::Io(io_err);
assert!(err.to_string().contains("I/O error"));
}
#[test]
fn error_display_invalid_block_size() {
let err = CopiaError::InvalidBlockSize(100);
assert!(err.to_string().contains("Invalid block size: 100"));
}
#[test]
fn error_display_invalid_hash_length() {
let err = CopiaError::InvalidHashLength(2);
assert!(err.to_string().contains("Invalid hash length: 2"));
}
#[test]
fn error_display_invalid_copy_bounds() {
let err = CopiaError::InvalidCopyBounds {
offset: 1000,
len: 500,
basis_size: 1200,
};
let msg = err.to_string();
assert!(msg.contains("offset 1000"));
assert!(msg.contains("len 500"));
assert!(msg.contains("basis size 1200"));
}
#[test]
fn error_display_checksum_mismatch() {
let err = CopiaError::ChecksumMismatch {
expected: [1u8; 32],
actual: [2u8; 32],
};
assert!(err.to_string().contains("Checksum mismatch"));
}
#[test]
fn error_display_empty_signature() {
let err = CopiaError::EmptySignature;
assert!(err.to_string().contains("Empty signature"));
}
#[test]
fn error_display_corrupted_delta() {
let err = CopiaError::CorruptedDelta;
assert!(err.to_string().contains("Corrupted delta"));
}
#[test]
fn error_display_protocol_error() {
let err = CopiaError::ProtocolError("invalid frame".to_string());
assert!(err.to_string().contains("Protocol error"));
assert!(err.to_string().contains("invalid frame"));
}
#[test]
fn result_type_ok() {
let result: Result<i32> = Ok(42);
assert_eq!(result.unwrap_or(0), 42);
}
#[test]
fn result_type_err() {
let result: Result<i32> = Err(CopiaError::EmptySignature);
assert!(result.is_err());
}
}