use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("Invalid input")]
InvalidFormat,
#[error("Operation failed")]
OperationFailed(
#[source]
#[from]
OperationError,
),
}
#[derive(Debug, Error)]
pub enum ConfigError {
#[error("Prefix must be between 1 and 20 characters")]
InvalidPrefixLength,
#[error("Prefix must contain only alphanumeric characters or underscores")]
InvalidPrefixCharacters,
#[error("Prefix must not contain {0} substring")]
InvalidPrefixSubstring(String),
#[error("Prefix cannot look like a version number (e.g., 'v1', 'v2', 'v42')")]
InvalidPrefixVersionLike,
#[error("String must not be empty")]
EmptyString,
#[error("Entropy must be at least 16 bytes (128 bits)")]
EntropyTooLow,
#[error("Entropy cannot exceed 64 bytes (512 bits)")]
EntropyTooHigh,
#[error("Invalid Argon2 parameters")]
InvalidHashParams,
#[error("Invalid Argon2 hash. Please raise an issue at https://github.com/gpmcp/api-keys-simplified/issues/new"
)]
InvalidArgon2Hash,
#[error("Minium checksum length should be 32 bits")]
ChecksumLenTooSmall,
#[error("Checksum length should be at MOST 128 bits")]
ChecksumLenTooLarge,
}
#[derive(Debug, Error)]
pub enum OperationError {
#[error("Key generation failed: {0}")]
Generation(String),
#[error("Hashing failed: {0}")]
Hashing(String),
#[error("Verification failed: {0}")]
Verification(String),
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Error)]
pub enum InitError {
#[error(transparent)]
Config(#[from] ConfigError),
#[error(transparent)]
Operation(#[from] Error),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_display_is_generic() {
let err =
Error::OperationFailed(OperationError::Hashing("detailed salt error".to_string()));
assert_eq!(err.to_string(), "Operation failed");
let debug_str = format!("{:?}", err);
assert!(debug_str.contains("Hashing"));
assert!(debug_str.contains("salt"));
}
#[test]
fn test_error_chaining() {
let err = Error::OperationFailed(OperationError::Verification(
"argon2 param error".to_string(),
));
if let Error::OperationFailed(source) = err {
assert!(source.to_string().contains("argon2"));
}
}
#[test]
fn test_format_errors_are_generic() {
let err = Error::InvalidFormat;
assert_eq!(err.to_string(), "Invalid input");
}
}