1#[cfg(feature = "alloc")]
2#[allow(
3 unused_imports,
4 reason = "alloc prelude items; subset used per cfg/feature combination"
5)]
6use alloc::{format, string::ToString, vec, vec::Vec};
7use thiserror::Error as ThisError;
8
9#[derive(Debug, ThisError, PartialEq, Eq)]
11pub enum Error {
12 #[error(
14 "Integer Overflow: The decoded Base64 value exceeds the maximum size for the target integer type."
15 )]
16 IntegerOverflow,
17 #[error(
19 "Invalid Base64 Character: Encountered '{0}', which is not part of the URL-safe Base64 character set."
20 )]
21 InvalidBase64Char(char),
22 #[error(
24 "Invalid Base64 Value: The value {0} is out of bounds for the Base64 character set (0-63)."
25 )]
26 InvalidBase64Value(u8),
27
28 #[error(
30 "Short Binary Stream: More bytes were expected to complete the parsing operation, but the stream ended."
31 )]
32 ShortBinaryStream,
33
34 #[error("Misaligned: length {len} is not a multiple of {unit}.")]
37 Misaligned {
38 len: usize,
40 unit: usize,
42 },
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 #[test]
52 fn integer_overflow_display() {
53 let err = Error::IntegerOverflow;
54 let msg = err.to_string();
55 assert!(
56 msg.contains("Integer Overflow"),
57 "expected 'Integer Overflow' in: {msg}"
58 );
59 }
60
61 #[test]
62 fn misaligned_display_names_len_and_unit() {
63 let err = Error::Misaligned { len: 3, unit: 4 };
64 let msg = err.to_string();
65 assert!(msg.contains('3') && msg.contains('4'), "got: {msg}");
66 }
67
68 #[test]
69 fn invalid_base64_char_display_contains_char() {
70 let err = Error::InvalidBase64Char('+');
71 let msg = err.to_string();
72 assert!(msg.contains('+'), "expected '+' in: {msg}");
73 }
74
75 #[test]
76 fn invalid_base64_char_display_contains_label() {
77 let err = Error::InvalidBase64Char('!');
78 let msg = err.to_string();
79 assert!(
80 msg.contains("Invalid Base64 Character"),
81 "expected 'Invalid Base64 Character' in: {msg}"
82 );
83 }
84
85 #[test]
86 fn invalid_base64_value_display_contains_value() {
87 let err = Error::InvalidBase64Value(65);
88 let msg = err.to_string();
89 assert!(msg.contains("65"), "expected '65' in: {msg}");
90 }
91
92 #[test]
93 fn invalid_base64_value_display_contains_label() {
94 let err = Error::InvalidBase64Value(99);
95 let msg = err.to_string();
96 assert!(
97 msg.contains("Invalid Base64 Value"),
98 "expected 'Invalid Base64 Value' in: {msg}"
99 );
100 }
101
102 #[test]
103 fn short_binary_stream_display() {
104 let err = Error::ShortBinaryStream;
105 let msg = err.to_string();
106 assert!(
107 msg.contains("Short Binary Stream"),
108 "expected 'Short Binary Stream' in: {msg}"
109 );
110 }
111
112 #[test]
115 fn same_variants_are_equal() {
116 assert_eq!(Error::IntegerOverflow, Error::IntegerOverflow);
117 assert_eq!(Error::ShortBinaryStream, Error::ShortBinaryStream);
118 assert_eq!(Error::InvalidBase64Char('x'), Error::InvalidBase64Char('x'));
119 assert_eq!(Error::InvalidBase64Value(10), Error::InvalidBase64Value(10));
120 }
121
122 #[test]
123 fn different_payloads_are_not_equal() {
124 assert_ne!(Error::InvalidBase64Char('x'), Error::InvalidBase64Char('y'));
125 assert_ne!(Error::InvalidBase64Value(10), Error::InvalidBase64Value(11));
126 }
127
128 #[test]
129 fn different_variants_are_not_equal() {
130 assert_ne!(Error::IntegerOverflow, Error::ShortBinaryStream);
131 }
132
133 #[test]
136 fn error_debug_contains_variant_name() {
137 let cases: Vec<(&str, Error)> = vec![
138 ("IntegerOverflow", Error::IntegerOverflow),
139 ("InvalidBase64Char", Error::InvalidBase64Char('!')),
140 ("InvalidBase64Value", Error::InvalidBase64Value(99)),
141 ("ShortBinaryStream", Error::ShortBinaryStream),
142 ];
143 for (expected_name, err) in cases {
144 let debug = format!("{err:?}");
145 assert!(
146 debug.contains(expected_name),
147 "expected '{expected_name}' in debug output: {debug}"
148 );
149 }
150 }
151
152 #[test]
155 fn error_implements_std_error() {
156 fn assert_std_error<T: core::error::Error>() {}
157 assert_std_error::<Error>();
158 }
159}