use thiserror::Error;
#[derive(Debug, Error, PartialEq, Eq)]
pub enum AppError {
#[error("cannot evaluate: {0}")]
Calculator(String),
#[error("{0}")]
Units(String),
#[error("invalid variable name: '{0}'")]
InvalidVariableName(String),
#[error("'{0}' is reserved and cannot be a variable")]
ReservedName(String),
#[error("no previous answer")]
NoPreviousAnswer,
#[error("no previous answer to save")]
NoAnswerToSave,
#[error("storage error: {0}")]
Storage(String),
}
pub type Result<T> = std::result::Result<T, AppError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_variant_renders_the_message_the_user_reads() {
let cases = [
(
AppError::Calculator("unexpected ')'".to_string()),
"cannot evaluate: unexpected ')'",
),
(
AppError::Units("No such unit foounit".to_string()),
"No such unit foounit",
),
(
AppError::InvalidVariableName("1bad".to_string()),
"invalid variable name: '1bad'",
),
(
AppError::ReservedName("pi".to_string()),
"'pi' is reserved and cannot be a variable",
),
(AppError::NoPreviousAnswer, "no previous answer"),
(AppError::NoAnswerToSave, "no previous answer to save"),
(
AppError::Storage("write failed".to_string()),
"storage error: write failed",
),
];
for (error, expected) in cases {
assert_eq!(error.to_string(), expected);
}
}
#[test]
fn a_units_error_is_not_buried_under_a_second_prefix() {
let units = AppError::Units("Conformance error: N != Pa".to_string());
assert!(!units.to_string().starts_with("cannot evaluate"));
}
}