diff options
Diffstat (limited to 'library/std/src/io/error/tests.rs')
-rw-r--r-- | library/std/src/io/error/tests.rs | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs new file mode 100644 index 000000000..c897a5e87 --- /dev/null +++ b/library/std/src/io/error/tests.rs @@ -0,0 +1,194 @@ +use super::{const_io_error, Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage}; +use crate::assert_matches::assert_matches; +use crate::error; +use crate::fmt; +use crate::mem::size_of; +use crate::sys::decode_error_kind; +use crate::sys::os::error_string; + +#[test] +fn test_size() { + assert!(size_of::<Error>() <= size_of::<[usize; 2]>()); +} + +#[test] +fn test_debug_error() { + let code = 6; + let msg = error_string(code); + let kind = decode_error_kind(code); + let err = Error { + repr: Repr::new_custom(Box::new(Custom { + kind: ErrorKind::InvalidInput, + error: Box::new(Error { repr: super::Repr::new_os(code) }), + })), + }; + let expected = format!( + "Custom {{ \ + kind: InvalidInput, \ + error: Os {{ \ + code: {:?}, \ + kind: {:?}, \ + message: {:?} \ + }} \ + }}", + code, kind, msg + ); + assert_eq!(format!("{err:?}"), expected); +} + +#[test] +fn test_downcasting() { + #[derive(Debug)] + struct TestError; + + impl fmt::Display for TestError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("asdf") + } + } + + impl error::Error for TestError {} + + // we have to call all of these UFCS style right now since method + // resolution won't implicitly drop the Send+Sync bounds + let mut err = Error::new(ErrorKind::Other, TestError); + assert!(err.get_ref().unwrap().is::<TestError>()); + assert_eq!("asdf", err.get_ref().unwrap().to_string()); + assert!(err.get_mut().unwrap().is::<TestError>()); + let extracted = err.into_inner().unwrap(); + extracted.downcast::<TestError>().unwrap(); +} + +#[test] +fn test_const() { + const E: Error = const_io_error!(ErrorKind::NotFound, "hello"); + + assert_eq!(E.kind(), ErrorKind::NotFound); + assert_eq!(E.to_string(), "hello"); + assert!(format!("{E:?}").contains("\"hello\"")); + assert!(format!("{E:?}").contains("NotFound")); +} + +#[test] +fn test_os_packing() { + for code in -20i32..20i32 { + let e = Error::from_raw_os_error(code); + assert_eq!(e.raw_os_error(), Some(code)); + assert_matches!( + e.repr.data(), + ErrorData::Os(c) if c == code, + ); + } +} + +#[test] +fn test_errorkind_packing() { + assert_eq!(Error::from(ErrorKind::NotFound).kind(), ErrorKind::NotFound); + assert_eq!(Error::from(ErrorKind::PermissionDenied).kind(), ErrorKind::PermissionDenied); + assert_eq!(Error::from(ErrorKind::Uncategorized).kind(), ErrorKind::Uncategorized); + // Check that the innards look like like what we want. + assert_matches!( + Error::from(ErrorKind::OutOfMemory).repr.data(), + ErrorData::Simple(ErrorKind::OutOfMemory), + ); +} + +#[test] +fn test_simple_message_packing() { + use super::{ErrorKind::*, SimpleMessage}; + macro_rules! check_simple_msg { + ($err:expr, $kind:ident, $msg:literal) => {{ + let e = &$err; + // Check that the public api is right. + assert_eq!(e.kind(), $kind); + assert!(format!("{e:?}").contains($msg)); + // and we got what we expected + assert_matches!( + e.repr.data(), + ErrorData::SimpleMessage(SimpleMessage { kind: $kind, message: $msg }) + ); + }}; + } + + let not_static = const_io_error!(Uncategorized, "not a constant!"); + check_simple_msg!(not_static, Uncategorized, "not a constant!"); + + const CONST: Error = const_io_error!(NotFound, "definitely a constant!"); + check_simple_msg!(CONST, NotFound, "definitely a constant!"); + + static STATIC: Error = const_io_error!(BrokenPipe, "a constant, sort of!"); + check_simple_msg!(STATIC, BrokenPipe, "a constant, sort of!"); +} + +#[derive(Debug, PartialEq)] +struct Bojji(bool); +impl error::Error for Bojji {} +impl fmt::Display for Bojji { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ah! {:?}", self) + } +} + +#[test] +fn test_custom_error_packing() { + use super::Custom; + let test = Error::new(ErrorKind::Uncategorized, Bojji(true)); + assert_matches!( + test.repr.data(), + ErrorData::Custom(Custom { + kind: ErrorKind::Uncategorized, + error, + }) if error.downcast_ref::<Bojji>().as_deref() == Some(&Bojji(true)), + ); +} + +#[derive(Debug)] +struct E; + +impl fmt::Display for E { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + Ok(()) + } +} + +impl error::Error for E {} + +#[test] +fn test_std_io_error_downcast() { + // Case 1: custom error, downcast succeeds + let io_error = Error::new(ErrorKind::Other, Bojji(true)); + let e: Box<Bojji> = io_error.downcast().unwrap(); + assert!(e.0); + + // Case 2: custom error, downcast fails + let io_error = Error::new(ErrorKind::Other, Bojji(true)); + let io_error = io_error.downcast::<E>().unwrap_err(); + + // ensures that the custom error is intact + assert_eq!(ErrorKind::Other, io_error.kind()); + let e: Box<Bojji> = io_error.downcast().unwrap(); + assert!(e.0); + + // Case 3: os error + let errno = 20; + let io_error = Error::from_raw_os_error(errno); + let io_error = io_error.downcast::<E>().unwrap_err(); + + assert_eq!(errno, io_error.raw_os_error().unwrap()); + + // Case 4: simple + let kind = ErrorKind::OutOfMemory; + let io_error: Error = kind.into(); + let io_error = io_error.downcast::<E>().unwrap_err(); + + assert_eq!(kind, io_error.kind()); + + // Case 5: simple message + const SIMPLE_MESSAGE: SimpleMessage = + SimpleMessage { kind: ErrorKind::Other, message: "simple message error test" }; + let io_error = Error::from_static_message(&SIMPLE_MESSAGE); + let io_error = io_error.downcast::<E>().unwrap_err(); + + assert_eq!(SIMPLE_MESSAGE.kind, io_error.kind()); + assert_eq!(SIMPLE_MESSAGE.message, &*format!("{io_error}")); +} |