age_crypto/errors/
encrypt.rs1use std::io;
2use thiserror::Error;
3#[derive(Debug, Error)]
4pub enum EncryptError {
5 #[error("No recipients provided")]
6 NoRecipients,
7 #[error("Invalid recipient '{recipient}': {reason}")]
8 InvalidRecipient { recipient: String, reason: String },
9 #[error("Encryption failed: {0}")]
10 Failed(String),
11 #[error("I/O error: {0}")]
12 Io(#[from] io::Error),
13}
14impl EncryptError {
15 #[must_use]
16 pub fn is_user_correctable(&self) -> bool {
17 matches!(
18 self,
19 EncryptError::NoRecipients | EncryptError::InvalidRecipient { .. }
20 )
21 }
22 #[must_use]
23 pub fn invalid_recipient(&self) -> Option<&str> {
24 match self {
25 EncryptError::InvalidRecipient { recipient, .. } => Some(recipient),
26 _ => None,
27 }
28 }
29}
30#[cfg(test)]
31mod tests {
32 use super::*;
33 use std::io::{self, ErrorKind};
34 #[test]
35 fn test_no_recipients_display() {
36 let err = EncryptError::NoRecipients;
37 assert_eq!(format!("{}", err), "No recipients provided");
38 }
39 #[test]
40 fn test_invalid_recipient_display() {
41 let err = EncryptError::InvalidRecipient {
42 recipient: "age1badkey".into(),
43 reason: "invalid checksum".into(),
44 };
45 assert_eq!(
46 format!("{}", err),
47 "Invalid recipient 'age1badkey': invalid checksum"
48 );
49 }
50 #[test]
51 fn test_failed_display() {
52 let err = EncryptError::Failed("internal crypto error".into());
53 assert_eq!(
54 format!("{}", err),
55 "Encryption failed: internal crypto error"
56 );
57 }
58 #[test]
59 fn test_io_error_display() {
60 let io_err = io::Error::new(ErrorKind::OutOfMemory, "alloc failed");
61 let err = EncryptError::Io(io_err);
62 assert_eq!(format!("{}", err), "I/O error: alloc failed");
63 }
64 #[test]
65 fn test_from_io_error_conversion() {
66 let io_err: io::Error = ErrorKind::PermissionDenied.into();
67 let encrypt_err: EncryptError = io_err.into();
68 assert!(matches!(encrypt_err, EncryptError::Io(_)));
69 }
70 #[test]
71 fn test_io_error_preserves_kind() {
72 let io_err = io::Error::new(ErrorKind::UnexpectedEof, "test");
73 let encrypt_err = EncryptError::Io(io_err);
74 if let EncryptError::Io(e) = encrypt_err {
75 assert_eq!(e.kind(), ErrorKind::UnexpectedEof);
76 } else {
77 panic!("Expected Io variant");
78 }
79 }
80 #[test]
81 fn test_is_user_correctable_true() {
82 assert!(EncryptError::NoRecipients.is_user_correctable());
83 let invalid = EncryptError::InvalidRecipient {
84 recipient: "bad".into(),
85 reason: "x".into(),
86 };
87 assert!(invalid.is_user_correctable());
88 }
89 #[test]
90 fn test_is_user_correctable_false() {
91 assert!(!EncryptError::Failed("x".into()).is_user_correctable());
92 assert!(!EncryptError::Io(io::Error::last_os_error()).is_user_correctable());
93 }
94 #[test]
95 fn test_invalid_recipient_some() {
96 let err = EncryptError::InvalidRecipient {
97 recipient: "age1test".into(),
98 reason: "bad".into(),
99 };
100 assert_eq!(err.invalid_recipient(), Some("age1test"));
101 }
102 #[test]
103 fn test_invalid_recipient_none() {
104 assert_eq!(EncryptError::NoRecipients.invalid_recipient(), None);
105 assert_eq!(EncryptError::Failed("x".into()).invalid_recipient(), None);
106 }
107 #[test]
108 fn test_error_is_send_sync() {
109 fn assert_send_sync<T: Send + Sync>() {}
110 assert_send_sync::<EncryptError>();
111 }
112 #[test]
113 fn test_error_implements_std_error() {
114 fn assert_error<T: std::error::Error>() {}
115 assert_error::<EncryptError>();
116 }
117 #[test]
118 fn test_error_source_chain() {
119 use std::error::Error as StdError;
120 let io_err = io::Error::other("underlying cause");
121 let encrypt_err = EncryptError::Io(io_err);
122 assert!(encrypt_err.source().is_some());
123 }
124 #[test]
125 fn test_debug_format_contains_variant_name() {
126 let err = EncryptError::InvalidRecipient {
127 recipient: "key".into(),
128 reason: "bad".into(),
129 };
130 let debug = format!("{:?}", err);
131 assert!(debug.contains("InvalidRecipient"));
132 assert!(debug.contains("key"));
133 }
134}