use std::path::Path;
use thiserror::Error;
use crate::corpus::types::Target;
#[derive(Debug, Error)]
pub enum CorpusLoaderError {
#[error("unable to read toml file '{path}': {source}")]
Read {
path: String,
source: std::io::Error,
},
#[error("unable to parse toml file '{path}': {source}")]
Parse {
path: String,
source: toml::de::Error,
},
#[error("target mismatch: expected '{expected}', got '{found}'")]
TargetMismatch { expected: Target, found: Target },
#[error("{0}")]
OptionViolation(String),
#[error("{0}")]
InvalidInput(String),
}
impl CorpusLoaderError {
pub(crate) fn read_for_path(path: impl AsRef<Path>, source: std::io::Error) -> Self {
CorpusLoaderError::Read {
path: path.as_ref().to_string_lossy().to_string(),
source,
}
}
pub(crate) fn parse_for_path(path: impl AsRef<Path>, source: toml::de::Error) -> Self {
CorpusLoaderError::Parse {
path: path.as_ref().to_string_lossy().to_string(),
source,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_display_formats_target_mismatch() {
let error = CorpusLoaderError::TargetMismatch {
expected: "weapon".to_string(),
found: "person".to_string(),
};
assert_eq!(
error.to_string(),
"target mismatch: expected 'weapon', got 'person'"
);
assert!(matches!(error, CorpusLoaderError::TargetMismatch { .. }));
}
#[test]
fn test_read_for_path_includes_path_in_message() {
let error = CorpusLoaderError::read_for_path(
"custom-file.toml",
std::io::Error::new(std::io::ErrorKind::NotFound, "missing"),
);
assert!(error.to_string().contains("custom-file.toml"));
assert!(matches!(error, CorpusLoaderError::Read { .. }));
}
#[test]
fn test_option_violation_variant() {
let error = CorpusLoaderError::OptionViolation("some constraint".to_string());
assert_eq!(error.to_string(), "some constraint");
assert!(matches!(error, CorpusLoaderError::OptionViolation(_)));
}
#[test]
fn test_invalid_input_variant() {
let error = CorpusLoaderError::InvalidInput("bad input".to_string());
assert_eq!(error.to_string(), "bad input");
assert!(matches!(error, CorpusLoaderError::InvalidInput(_)));
}
}