195 lines
5.7 KiB
Rust
195 lines
5.7 KiB
Rust
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 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}"));
|
|
}
|