use std::{fmt::Debug, io, panic::Location};
use wherror::Error;
#[derive(Error, Debug)]
enum MError {
#[error("At {location}: location test error, sourced from {other}")]
Test {
#[from]
other: io::Error,
location: &'static Location<'static>,
},
}
#[derive(Error, Debug)]
enum TupleError {
#[error("Tuple variant at {1}: sourced from {0}")]
Test(#[from] io::Error, &'static Location<'static>),
}
#[derive(Error, Debug)]
#[error("At {location} test error, sourced from {other}")]
pub struct TestError {
#[from]
other: io::Error,
location: &'static Location<'static>,
}
#[test]
#[should_panic(expected = "Location { file:")]
fn test_enum() {
fn inner() -> Result<(), MError> {
Err(io::Error::new(io::ErrorKind::AddrInUse, String::new()))?;
Ok(())
}
inner().unwrap();
}
#[test]
#[should_panic(expected = "Location { file:")]
fn test_tuple_enum() {
fn inner() -> Result<(), TupleError> {
Err(io::Error::new(io::ErrorKind::AddrInUse, String::new()))?;
Ok(())
}
inner().unwrap();
}
#[test]
#[should_panic(expected = "Location { file:")]
fn test_struct() {
fn inner() -> Result<(), TestError> {
Err(io::Error::new(io::ErrorKind::AddrInUse, String::new()))?;
Ok(())
}
inner().unwrap();
}
#[test]
fn test_location_method() {
let error: TestError = io::Error::new(io::ErrorKind::AddrInUse, String::new()).into();
assert!(error.location().is_some());
let error: MError = io::Error::new(io::ErrorKind::AddrInUse, String::new()).into();
assert!(error.location().is_some());
let error: TupleError = io::Error::new(io::ErrorKind::AddrInUse, String::new()).into();
assert!(error.location().is_some());
}
#[derive(Error, Debug)]
#[error("No location error")]
pub struct NoLocationError {
#[from]
other: io::Error,
}
#[derive(Error, Debug)]
enum MixedLocationEnum {
#[error("With location: {location}")]
WithLocation {
#[from]
other: io::Error,
location: &'static Location<'static>,
},
#[error("Without location")]
WithoutLocation { message: String },
}
#[test]
fn test_location_method_mixed_enum() {
let error: MixedLocationEnum = io::Error::new(io::ErrorKind::AddrInUse, String::new()).into();
assert!(error.location().is_some());
let error = MixedLocationEnum::WithoutLocation {
message: "test".to_string(),
};
assert!(error.location().is_none());
}
#[test]
fn test_location_values() {
let line_direct = line!();
let error1: TestError = io::Error::new(io::ErrorKind::AddrInUse, String::new()).into();
let location1 = error1.location().expect("Error should have location");
assert_eq!(location1.file(), file!());
assert_eq!(location1.line(), line_direct + 1);
let error2: TestError = create_error_without_track_caller();
let location2 = error2.location().expect("Error should have location");
assert_eq!(location2.file(), file!());
assert_ne!(location2.line(), line_direct + 1);
let line_with_track_caller = line!();
let error3: TestError = create_error_helper();
let location3 = error3.location().expect("Error should have location");
assert_eq!(location3.file(), file!());
assert_eq!(location3.line(), line_with_track_caller + 1);
assert_ne!(location1.line(), location3.line());
assert_ne!(location2.line(), location1.line());
assert_ne!(location2.line(), location3.line());
}
#[track_caller]
fn create_error_helper() -> TestError {
io::Error::new(io::ErrorKind::AddrInUse, String::new()).into()
}
fn create_error_without_track_caller() -> TestError {
io::Error::new(io::ErrorKind::AddrInUse, String::new()).into()
}