use crate::{CharOffset, LineNumber};
use std::error;
use std::fmt;
#[derive(Debug, PartialEq)]
pub struct ParseError {
pub bad_input: String,
pub highlighted_lines: Vec<String>,
pub message: String,
pub line_number: LineNumber,
pub line_offset: CharOffset,
pub possible_values: Option<Vec<String>>,
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let ParseError {
bad_input,
highlighted_lines,
line_number,
message,
possible_values,
..
} = self;
writeln!(
f,
"On line {} {message} but saw {bad_input}",
line_number + 1
)?;
if let Some(pv) = possible_values {
writeln!(f, "Possible values: {}", pv.join(" | "))?;
}
if !highlighted_lines.is_empty() {
writeln!(f)?;
}
for line in highlighted_lines {
writeln!(f, "{line}")?;
}
Ok(())
}
}
impl error::Error for ParseError {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display_parse_error() {
let message = ParseError {
bad_input: "bar".to_string(),
message: "it should be foo".to_string(),
line_number: 3,
line_offset: 5,
possible_values: None,
highlighted_lines: vec!["foo".to_string(), "bar".to_string(), "baz".to_string()],
};
assert_eq!(
"On line 4 it should be foo but saw bar
foo
bar
baz
",
message.to_string()
);
}
#[test]
fn display_bad_input_with_possibilities() {
let message = ParseError {
bad_input: "bar".to_string(),
message: "it should be foo".to_string(),
line_number: 3,
line_offset: 5,
possible_values: Some(vec![
"one".to_string(),
"two".to_string(),
"three".to_string(),
]),
highlighted_lines: vec!["foo".to_string(), "bar".to_string(), "baz".to_string()],
};
assert_eq!(
"On line 4 it should be foo but saw bar
Possible values: one | two | three
foo
bar
baz
",
message.to_string()
);
}
}