use thiserror::Error;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum ParseError {
#[error("unknown participant '{name}' at line {line}")]
UnknownParticipant {
name: String,
line: u32,
candidates: Vec<String>,
},
#[error("unclosed subgraph opened at line {opened_at}")]
UnclosedSubgraph {
opened_at: u32,
},
#[error("unexpected token '{found}' at {line}:{col}; expected {expected}")]
UnexpectedToken {
line: u32,
col: u32,
found: String,
expected: String,
},
#[error("invalid directive '{directive}' at {line}:{col}: {reason}")]
InvalidDirective {
line: u32,
col: u32,
directive: String,
reason: String,
},
}
#[cfg(all(test, feature = "mermaid_engine_internal_tests"))]
mod anyhow_bridge_is_derived {
use super::ParseError;
const _: fn() = || {
fn assert_error<E: std::error::Error + Send + Sync + 'static>() {}
assert_error::<ParseError>();
};
}
#[cfg(all(test, feature = "mermaid_engine_internal_tests"))]
mod tests {
use super::*;
#[test]
fn parse_error_implements_display() {
let e = ParseError::UnclosedSubgraph { opened_at: 7 };
assert_eq!(format!("{e}"), "unclosed subgraph opened at line 7");
}
#[test]
fn parse_error_unexpected_token_shape() {
let e = ParseError::UnexpectedToken {
line: 3,
col: 5,
found: "-->".into(),
expected: "node identifier".into(),
};
assert_eq!(
format!("{e}"),
"unexpected token '-->' at 3:5; expected node identifier"
);
}
#[test]
fn parse_error_invalid_directive_shape() {
let e = ParseError::InvalidDirective {
line: 1,
col: 1,
directive: "init".into(),
reason: "JSON parse error: expected '}'".into(),
};
assert_eq!(
format!("{e}"),
"invalid directive 'init' at 1:1: JSON parse error: expected '}'"
);
}
#[test]
fn parse_error_is_anyhow_convertible() {
let e: anyhow::Error = ParseError::UnclosedSubgraph { opened_at: 2 }.into();
assert!(e.to_string().contains("unclosed subgraph"));
}
}