Skip to content

Commit

Permalink
Improve currency conversion error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
printfn committed Nov 3, 2024
1 parent ac77512 commit 251dd7e
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 11 deletions.
12 changes: 3 additions & 9 deletions core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub(crate) enum FendError {
ZeroToThePowerOfZero,
FactorialComplex,
DeserializationError,
Wrap(Box<dyn error::Error + Send + Sync + 'static>),
Wrap(String, Box<dyn error::Error + Send + Sync + 'static>),
NoExchangeRatesAvailable,
OutOfRange {
value: Box<dyn crate::format::DisplayDebug>,
Expand Down Expand Up @@ -227,7 +227,7 @@ impl fmt::Display for FendError {
)
}
Self::FormattingError(_) => write!(f, "error during formatting"),
Self::Wrap(e) => write!(f, "{e}"),
Self::Wrap(e, _) => write!(f, "{e}"),
Self::ExpectedADateLiteral => write!(f, "Expected a date literal, e.g. @1970-01-01"),
Self::NonExistentDate {
year,
Expand All @@ -251,7 +251,7 @@ impl error::Error for FendError {
match self {
Self::FormattingError(e) => Some(e),
Self::IoError(e) => Some(e),
Self::Wrap(e) => Some(e.as_ref()),
Self::Wrap(_, e) => Some(e.as_ref()),
_ => None,
}
}
Expand All @@ -269,10 +269,4 @@ impl From<io::Error> for FendError {
}
}

impl From<Box<dyn error::Error + Send + Sync + 'static>> for FendError {
fn from(e: Box<dyn error::Error + Send + Sync + 'static>) -> Self {
Self::Wrap(e)
}
}

pub(crate) use crate::interrupt::Interrupt;
12 changes: 11 additions & 1 deletion core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ mod serialize;
mod units;
mod value;

use std::error::Error;
use std::fmt::Write;
use std::sync::Arc;
use std::{collections::HashMap, fmt, io};

Expand Down Expand Up @@ -436,7 +438,15 @@ fn evaluate_with_interrupt_internal(
}
let (result, is_unit, attrs) = match eval::evaluate_to_spans(input, None, context, int) {
Ok(value) => value,
Err(e) => return Err(e.to_string()),
Err(e) => {
let mut error: &dyn Error = &e;
let mut s = error.to_string();
while let Some(inner) = error.source() {
write!(&mut s, ": {inner}").unwrap();
error = inner;
}
return Err(s);
}
};
let mut plain_result = String::new();
for s in &result {
Expand Down
6 changes: 5 additions & 1 deletion core/src/units.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ fn expr_unit<I: Interrupt>(
let Some(exchange_rate_fn) = &context.get_exchange_rate else {
return Err(FendError::NoExchangeRatesAvailable);
};
let one_base_in_currency = exchange_rate_fn.relative_to_base_currency(&singular)?;
let one_base_in_currency = exchange_rate_fn
.relative_to_base_currency(&singular)
.map_err(|e| {
FendError::Wrap(format!("failed to retrieve {singular} exchange rate"), e)
})?;
let value = evaluate_to_value(
format!("(1/{one_base_in_currency}) BASE_CURRENCY").as_str(),
None,
Expand Down
25 changes: 25 additions & 0 deletions core/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6086,3 +6086,28 @@ fn kilopond() {
test_eval("gf to N", "0.00980665 N");
expect_error("GF to N", Some("cannot convert from GF to N: units 'ampere^2 second^4 kilogram^-1 meter^-2' and 'kilogram meter / second^2' are incompatible"));
}

#[derive(Debug)]
struct TestError(Box<dyn std::error::Error + Send + Sync + 'static>);

impl std::fmt::Display for TestError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "my error")
}
}

impl std::error::Error for TestError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(self.0.as_ref())
}
}

#[test]
fn test_nested_exchange_rate_error() {
let mut context = Context::new();
context.set_exchange_rate_handler_v1(|_: &str| Err(TestError("inner error".into()).into()));
assert_eq!(
evaluate("usd to eur", &mut context).unwrap_err(),
"failed to retrieve EUR exchange rate: my error: inner error",
);
}

0 comments on commit 251dd7e

Please sign in to comment.