use thiserror::Error;
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum Error {
#[error("invalid style: {message}")]
StyleParse {
message: String,
},
#[error("invalid color: {message}")]
ColorParse {
message: String,
},
#[error("invalid markup: {message}")]
MarkupParse {
message: String,
},
#[error("console I/O error: {source}")]
ConsoleIo {
#[from]
source: std::io::Error,
},
#[error("feature not available: {feature}")]
FeatureNotAvailable {
feature: String,
},
#[error("value out of range: {message}")]
OutOfRange {
message: String,
},
#[error("table error: {message}")]
TableError {
message: String,
},
#[error("theme error: {message}")]
ThemeError {
message: String,
},
#[error("regex error: {source}")]
RegexError {
#[from]
source: regex::Error,
},
#[error("JSON error: {source}")]
JsonError {
#[from]
source: serde_json::Error,
},
#[error("integer conversion error: {message}")]
IntegerConversion {
message: String,
},
#[error("no emoji called '{0}'")]
NoEmoji(String),
#[error("no spinner called '{0}'")]
NoSpinner(String),
}
pub type Result<T> = std::result::Result<T, Error>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_style_parse_error_display() {
let err = Error::StyleParse {
message: "unknown attribute 'foobar'".to_owned(),
};
assert_eq!(err.to_string(), "invalid style: unknown attribute 'foobar'");
}
#[test]
fn test_color_parse_error_display() {
let err = Error::ColorParse {
message: "invalid hex color '#gggggg'".to_owned(),
};
assert_eq!(
err.to_string(),
"invalid color: invalid hex color '#gggggg'"
);
}
#[test]
fn test_markup_parse_error_display() {
let err = Error::MarkupParse {
message: "unclosed tag at position 5".to_owned(),
};
assert_eq!(
err.to_string(),
"invalid markup: unclosed tag at position 5"
);
}
#[test]
fn test_feature_not_available_display() {
let err = Error::FeatureNotAvailable {
feature: "syntax_highlighting".to_owned(),
};
assert_eq!(
err.to_string(),
"feature not available: syntax_highlighting"
);
}
#[test]
fn test_out_of_range_display() {
let err = Error::OutOfRange {
message: "color index 256 exceeds maximum 255".to_owned(),
};
assert_eq!(
err.to_string(),
"value out of range: color index 256 exceeds maximum 255"
);
}
#[test]
fn test_table_error_display() {
let err = Error::TableError {
message: "row has 3 columns but table has 4".to_owned(),
};
assert_eq!(
err.to_string(),
"table error: row has 3 columns but table has 4"
);
}
#[test]
fn test_theme_error_display() {
let err = Error::ThemeError {
message: "style name must start with a letter".to_owned(),
};
assert_eq!(
err.to_string(),
"theme error: style name must start with a letter"
);
}
#[test]
fn test_integer_conversion_display() {
let err = Error::IntegerConversion {
message: "value too large for u8".to_owned(),
};
assert_eq!(
err.to_string(),
"integer conversion error: value too large for u8"
);
}
#[test]
fn test_error_is_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<Error>();
}
#[test]
fn test_no_emoji_display() {
let err = Error::NoEmoji("nonexistent".to_owned());
assert_eq!(err.to_string(), "no emoji called 'nonexistent'");
}
}