1 use super::{const_io_error, Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage}; 2 use crate::std::assert_matches::assert_matches; 3 use crate::std::error; 4 use crate::std::fmt; 5 use crate::std::mem::size_of; 6 use crate::std::sys::decode_error_kind; 7 use crate::std::sys::os::error_string; 8 9 #[test] 10 fn test_size() { 11 assert!(size_of::<Error>() <= size_of::<[usize; 2]>()); 12 } 13 14 #[test] 15 fn test_debug_error() { 16 let code = 6; 17 let msg = error_string(code); 18 let kind = decode_error_kind(code); 19 let err = Error { 20 repr: Repr::new_custom(Box::new(Custom { 21 kind: ErrorKind::InvalidInput, 22 error: Box::new(Error { 23 repr: super::Repr::new_os(code), 24 }), 25 })), 26 }; 27 let expected = format!( 28 "Custom {{ \ 29 kind: InvalidInput, \ 30 error: Os {{ \ 31 code: {:?}, \ 32 kind: {:?}, \ 33 message: {:?} \ 34 }} \ 35 }}", 36 code, kind, msg 37 ); 38 assert_eq!(format!("{err:?}"), expected); 39 } 40 41 #[test] 42 fn test_downcasting() { 43 #[derive(Debug)] 44 struct TestError; 45 46 impl fmt::Display for TestError { 47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 48 f.write_str("asdf") 49 } 50 } 51 52 impl error::Error for TestError {} 53 54 // we have to call all of these UFCS style right now since method 55 // resolution won't implicitly drop the Send+Sync bounds 56 let mut err = Error::new(ErrorKind::Other, TestError); 57 assert!(err.get_ref().unwrap().is::<TestError>()); 58 assert_eq!("asdf", err.get_ref().unwrap().to_string()); 59 assert!(err.get_mut().unwrap().is::<TestError>()); 60 let extracted = err.into_inner().unwrap(); 61 extracted.downcast::<TestError>().unwrap(); 62 } 63 64 #[test] 65 fn test_const() { 66 const E: Error = const_io_error!(ErrorKind::NotFound, "hello"); 67 68 assert_eq!(E.kind(), ErrorKind::NotFound); 69 assert_eq!(E.to_string(), "hello"); 70 assert!(format!("{E:?}").contains("\"hello\"")); 71 assert!(format!("{E:?}").contains("NotFound")); 72 } 73 74 #[test] 75 fn test_os_packing() { 76 for code in -20..20 { 77 let e = Error::from_raw_os_error(code); 78 assert_eq!(e.raw_os_error(), Some(code)); 79 assert_matches!( 80 e.repr.data(), 81 ErrorData::Os(c) if c == code, 82 ); 83 } 84 } 85 86 #[test] 87 fn test_errorkind_packing() { 88 assert_eq!(Error::from(ErrorKind::NotFound).kind(), ErrorKind::NotFound); 89 assert_eq!( 90 Error::from(ErrorKind::PermissionDenied).kind(), 91 ErrorKind::PermissionDenied 92 ); 93 assert_eq!( 94 Error::from(ErrorKind::Uncategorized).kind(), 95 ErrorKind::Uncategorized 96 ); 97 // Check that the innards look like what we want. 98 assert_matches!( 99 Error::from(ErrorKind::OutOfMemory).repr.data(), 100 ErrorData::Simple(ErrorKind::OutOfMemory), 101 ); 102 } 103 104 #[test] 105 fn test_simple_message_packing() { 106 use super::{ErrorKind::*, SimpleMessage}; 107 macro_rules! check_simple_msg { 108 ($err:expr, $kind:ident, $msg:literal) => {{ 109 let e = &$err; 110 // Check that the public api is right. 111 assert_eq!(e.kind(), $kind); 112 assert!(format!("{e:?}").contains($msg)); 113 // and we got what we expected 114 assert_matches!( 115 e.repr.data(), 116 ErrorData::SimpleMessage(SimpleMessage { 117 kind: $kind, 118 message: $msg 119 }) 120 ); 121 }}; 122 } 123 124 let not_static = const_io_error!(Uncategorized, "not a constant!"); 125 check_simple_msg!(not_static, Uncategorized, "not a constant!"); 126 127 const CONST: Error = const_io_error!(NotFound, "definitely a constant!"); 128 check_simple_msg!(CONST, NotFound, "definitely a constant!"); 129 130 static STATIC: Error = const_io_error!(BrokenPipe, "a constant, sort of!"); 131 check_simple_msg!(STATIC, BrokenPipe, "a constant, sort of!"); 132 } 133 134 #[derive(Debug, PartialEq)] 135 struct Bojji(bool); 136 impl error::Error for Bojji {} 137 impl fmt::Display for Bojji { 138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 139 write!(f, "ah! {:?}", self) 140 } 141 } 142 143 #[test] 144 fn test_custom_error_packing() { 145 use super::Custom; 146 let test = Error::new(ErrorKind::Uncategorized, Bojji(true)); 147 assert_matches!( 148 test.repr.data(), 149 ErrorData::Custom(Custom { 150 kind: ErrorKind::Uncategorized, 151 error, 152 }) if error.downcast_ref::<Bojji>().as_deref() == Some(&Bojji(true)), 153 ); 154 } 155 156 #[derive(Debug)] 157 struct E; 158 159 impl fmt::Display for E { 160 fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { 161 Ok(()) 162 } 163 } 164 165 impl error::Error for E {} 166 167 #[test] 168 fn test_std_io_error_downcast() { 169 // Case 1: custom error, downcast succeeds 170 let io_error = Error::new(ErrorKind::Other, Bojji(true)); 171 let e: Box<Bojji> = io_error.downcast().unwrap(); 172 assert!(e.0); 173 174 // Case 2: custom error, downcast fails 175 let io_error = Error::new(ErrorKind::Other, Bojji(true)); 176 let io_error = io_error.downcast::<E>().unwrap_err(); 177 178 // ensures that the custom error is intact 179 assert_eq!(ErrorKind::Other, io_error.kind()); 180 let e: Box<Bojji> = io_error.downcast().unwrap(); 181 assert!(e.0); 182 183 // Case 3: os error 184 let errno = 20; 185 let io_error = Error::from_raw_os_error(errno); 186 let io_error = io_error.downcast::<E>().unwrap_err(); 187 188 assert_eq!(errno, io_error.raw_os_error().unwrap()); 189 190 // Case 4: simple 191 let kind = ErrorKind::OutOfMemory; 192 let io_error: Error = kind.into(); 193 let io_error = io_error.downcast::<E>().unwrap_err(); 194 195 assert_eq!(kind, io_error.kind()); 196 197 // Case 5: simple message 198 const SIMPLE_MESSAGE: SimpleMessage = SimpleMessage { 199 kind: ErrorKind::Other, 200 message: "simple message error test", 201 }; 202 let io_error = Error::from_static_message(&SIMPLE_MESSAGE); 203 let io_error = io_error.downcast::<E>().unwrap_err(); 204 205 assert_eq!(SIMPLE_MESSAGE.kind, io_error.kind()); 206 assert_eq!(SIMPLE_MESSAGE.message, format!("{io_error}")); 207 } 208