use ohno::{AppError, IntoAppError, assert_error_message};
#[test]
fn result_into_app_err() {
fn parse_number(s: &str) -> (Result<i32, AppError>, u32) {
(s.parse::<i32>().into_app_err("failed to parse number"), line!())
}
let (result, call_line) = parse_number("xyz");
let err = result.unwrap_err();
assert_error_message!(err, "invalid digit found in string");
let msg = err.to_string();
let expected_location = format!("{}:{}", file!(), call_line);
let lines = msg.lines().collect::<Vec<_>>();
assert_eq!(lines[0], "invalid digit found in string");
assert!(lines[1].starts_with("> failed to parse number (at "), "{msg}");
assert!(lines[1].contains(&expected_location), "{msg}");
}
#[test]
fn result_into_app_err_with() {
fn parse_with_context(s: &str) -> (Result<i32, AppError>, u32) {
(s.parse::<i32>().into_app_err_with(|| format!("failed to parse: {s}")), line!())
}
let (result, call_line) = parse_with_context("abc");
let err = result.unwrap_err();
assert_error_message!(err, "invalid digit found in string");
let msg = err.to_string();
let expected_location = format!("{}:{}", file!(), call_line);
assert!(msg.contains("failed to parse: abc"), "{msg}");
assert!(msg.contains(&expected_location), "{msg}");
}
#[test]
fn option_into_app_err() {
fn make_error() -> Result<i32, AppError> {
None.into_app_err("value not found")
}
let err = make_error().unwrap_err();
assert_error_message!(err, "value not found");
assert!(err.source().is_none());
}
#[test]
fn option_into_app_err_with() {
fn with_context() -> Result<i32, AppError> {
None.into_app_err_with(|| "nothing found")
}
let err = with_context().unwrap_err();
assert_error_message!(err, "nothing found");
assert!(err.source().is_none());
}
#[test]
fn ohno_on_into_app_err_error() {
fn level1() -> Result<i32, AppError> {
Err(AppError::new("root error"))
}
fn level2() -> (Result<i32, AppError>, u32) {
(level1().into_app_err("context added"), line!())
}
fn level3(inner: Result<i32, AppError>) -> (Result<i32, AppError>, u32) {
(inner.into_app_err_with(|| "more context added"), line!())
}
let (result2, line2) = level2();
let (result3, line3) = level3(result2);
let err = result3.unwrap_err();
let msg = err.to_string();
let expected_location2 = format!("{}:{}", file!(), line2);
let expected_location3 = format!("{}:{}", file!(), line3);
assert!(msg.contains("root error"), "{msg}");
assert!(msg.contains("> context added"), "{msg}");
assert!(msg.contains("> more context added"), "{msg}");
assert!(msg.contains(&expected_location2), "{msg}");
assert!(msg.contains(&expected_location3), "{msg}");
}
#[test]
fn string_ref() {
fn fail() -> Result<i32, AppError> {
let context = String::from("failed operation");
None.into_app_err(&context)
}
let err = fail().unwrap_err();
let msg = err.to_string();
assert!(msg.contains("failed operation"), "{msg}");
}
#[test]
fn result_into_app_err_ok() {
let result: Result<i32, std::num::ParseIntError> = "42".parse();
let ok = result.into_app_err("should not appear").unwrap();
assert_eq!(ok, 42);
}
#[test]
fn result_into_app_err_with_ok() {
let result: Result<i32, std::num::ParseIntError> = "42".parse();
let ok = result.into_app_err_with(|| "should not appear").unwrap();
assert_eq!(ok, 42);
}
#[test]
fn option_into_app_err_ok() {
let ok = Some(42).into_app_err("should not appear").unwrap();
assert_eq!(ok, 42);
}
#[test]
fn option_into_app_err_with_ok() {
let ok = Some(42).into_app_err_with(|| "should not appear").unwrap();
assert_eq!(ok, 42);
}
#[test]
fn app_error_result_into_app_err_ok() {
let result: Result<i32, AppError> = Ok(42);
let ok = result.into_app_err("should not appear").unwrap();
assert_eq!(ok, 42);
}
#[test]
fn app_error_result_into_app_err_with_ok() {
let result: Result<i32, AppError> = Ok(42);
let ok = result.into_app_err_with(|| "should not appear").unwrap();
assert_eq!(ok, 42);
}