use eure::document::parse::{ParseContext, ParseError, ParseErrorKind};
use eure::FromEure;
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
pub enum InnerError {
#[error("parse error: {0}")]
Parse(#[from] ParseError),
#[error("validation error: {message}")]
Validation { message: String },
}
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
pub enum CustomError {
#[error("parse error: {0}")]
Parse(#[from] ParseError),
#[error("inner error: {0}")]
Inner(#[from] InnerError),
}
#[derive(Debug, PartialEq)]
pub struct InnerStruct {
pub value: i32,
}
impl<'doc> eure::document::parse::FromEure<'doc> for InnerStruct {
type Error = InnerError;
fn parse(ctx: &ParseContext<'doc>) -> Result<Self, Self::Error> {
let rec = ctx.parse_record()?;
let value: i32 = rec.parse_field("value")?;
if value < 0 {
return Err(InnerError::Validation {
message: "value must be non-negative".to_string(),
});
}
rec.deny_unknown_fields()?;
Ok(InnerStruct { value })
}
}
#[derive(Debug, PartialEq, FromEure)]
#[eure(crate = ::eure::document, parse_error = CustomError)]
pub struct OuterStruct {
pub name: String,
pub inner: InnerStruct,
}
#[test]
fn test_custom_error_success() {
use eure::eure;
let doc = eure!({
name = "test"
inner { value = 42 }
});
let result = doc.parse::<OuterStruct>(doc.get_root_id());
assert_eq!(
result.unwrap(),
OuterStruct {
name: "test".to_string(),
inner: InnerStruct { value: 42 }
}
);
}
#[test]
fn test_custom_error_from_parse_error() {
use eure::eure;
let doc = eure!({
inner { value = 42 }
});
let result = doc.parse::<OuterStruct>(doc.get_root_id());
assert!(result.is_err());
let err = result.unwrap_err();
match err {
CustomError::Parse(parse_err) => {
assert!(matches!(parse_err.kind, ParseErrorKind::MissingField(_)));
}
_ => panic!("expected CustomError::Parse, got {:?}", err),
}
}
#[test]
fn test_custom_error_from_inner_error() {
use eure::eure;
let doc = eure!({
name = "test"
inner { value = -1 }
});
let result = doc.parse::<OuterStruct>(doc.get_root_id());
assert!(result.is_err());
let err = result.unwrap_err();
match err {
CustomError::Inner(InnerError::Validation { message }) => {
assert_eq!(message, "value must be non-negative");
}
_ => panic!("expected CustomError::Inner(InnerError::Validation), got {:?}", err),
}
}
#[derive(Debug, PartialEq, FromEure)]
#[eure(crate = ::eure::document, parse_error = CustomError)]
pub struct NestedStruct {
pub outer: OuterStruct,
}
#[test]
fn test_nested_custom_error() {
use eure::eure;
let doc = eure!({
outer {
name = "test"
inner { value = 10 }
}
});
let result = doc.parse::<NestedStruct>(doc.get_root_id());
assert_eq!(
result.unwrap(),
NestedStruct {
outer: OuterStruct {
name: "test".to_string(),
inner: InnerStruct { value: 10 }
}
}
);
}
#[test]
fn test_nested_inner_error_bubbles_up() {
use eure::eure;
let doc = eure!({
outer {
name = "test"
inner { value = -5 }
}
});
let result = doc.parse::<NestedStruct>(doc.get_root_id());
assert!(result.is_err());
let err = result.unwrap_err();
match err {
CustomError::Inner(InnerError::Validation { message }) => {
assert_eq!(message, "value must be non-negative");
}
_ => panic!("expected CustomError::Inner(InnerError::Validation), got {:?}", err),
}
}