use std::path::PathBuf;
use serde::Serialize;
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[non_exhaustive]
pub enum ScanErrorKind {
IoError,
FileTooLarge,
JsonParseError,
YamlParseError,
InvalidEncoding,
OutsideRepository,
LimitExceeded,
WalkError,
InvalidExcludePattern,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[non_exhaustive]
pub struct ScanError {
pub file: PathBuf,
pub kind: ScanErrorKind,
pub message: String,
}
impl ScanError {
#[must_use]
pub fn format_human_readable(&self) -> String {
format!("{}: [scan error] {}", self.file.display(), self.message)
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[non_exhaustive]
pub struct ValidationError {
pub file: PathBuf,
pub line: usize,
pub column: usize,
pub json_path: String,
pub raw_value: String,
pub normalized_id: String,
pub error: String,
pub context: String,
}
impl ValidationError {
#[must_use]
pub fn format_human_readable(&self) -> String {
if self.line > 0 && self.column > 0 {
format!(
"{}:{}:{}: {} [{}]",
self.file.display(),
self.line,
self.column,
self.error,
self.raw_value
)
} else if !self.json_path.is_empty() {
format!(
"{}: {} [{}] (at {})",
self.file.display(),
self.error,
self.raw_value,
self.json_path
)
} else {
format!(
"{}: {} [{}]",
self.file.display(),
self.error,
self.raw_value
)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn test_format_markdown_error() {
let err = ValidationError {
file: PathBuf::from("docs/test.md"),
line: 42,
column: 10,
json_path: String::new(),
raw_value: "gts.invalid".to_owned(),
normalized_id: "gts.invalid".to_owned(),
error: "Invalid GTS ID".to_owned(),
context: "Some context".to_owned(),
};
let formatted = err.format_human_readable();
assert!(formatted.contains("docs/test.md:42:10"));
assert!(formatted.contains("Invalid GTS ID"));
assert!(formatted.contains("[gts.invalid]"));
assert!(!formatted.contains("(at"));
}
#[test]
fn test_format_json_error() {
let err = ValidationError {
file: PathBuf::from("config/test.json"),
line: 0,
column: 0,
json_path: "$.properties.type.x-gts-ref".to_owned(),
raw_value: "gts.invalid".to_owned(),
normalized_id: "gts.invalid".to_owned(),
error: "Invalid GTS ID".to_owned(),
context: "x-gts-ref".to_owned(),
};
let formatted = err.format_human_readable();
assert!(formatted.contains("config/test.json"));
assert!(formatted.contains("Invalid GTS ID"));
assert!(formatted.contains("[gts.invalid]"));
assert!(formatted.contains("(at $.properties.type.x-gts-ref)"));
assert!(!formatted.contains(":0:0"));
}
}