#[derive(Debug, thiserror::Error, PartialEq, Eq)]
#[non_exhaustive]
pub enum ConfigError {
#[error("site-config JSON is invalid: {0}")]
Json(String),
#[error("site config does not define the main namespace (id 0)")]
MissingMainNamespace,
#[error("duplicate namespace id {0}")]
DuplicateNamespace(i32),
#[error("namespace alias `{alias}` maps to both namespace {first} and namespace {second}")]
ConflictingNamespaceAlias {
alias: String,
first: i32,
second: i32,
},
#[error("link-trail pattern `{pattern}` is not a valid character class")]
LinkTrail {
pattern: String,
},
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum BuildError {
#[error("invalid limits: {0}")]
InvalidLimits(&'static str),
#[error("no site config was supplied and the `presets` feature is disabled")]
MissingSiteConfig,
}
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
#[non_exhaustive]
pub enum TitleError {
#[error("title is empty after normalization")]
Empty,
#[error("title contains forbidden character `{0}`")]
ForbiddenChar(char),
#[error("title is {bytes} bytes long; MediaWiki allows at most 255")]
TooLong {
bytes: usize,
},
#[error("title contains a relative path component")]
RelativePath,
#[error("title contains a signature sequence (`~~~`)")]
Signature,
#[error("title has a colon directly after the namespace prefix")]
LeadingColon,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_variant_renders_a_message() {
let messages = [
ConfigError::Json("boom".to_owned()).to_string(),
ConfigError::MissingMainNamespace.to_string(),
ConfigError::DuplicateNamespace(10).to_string(),
ConfigError::ConflictingNamespaceAlias {
alias: "шаблон".to_owned(),
first: 10,
second: 828,
}
.to_string(),
ConfigError::LinkTrail {
pattern: "a-".to_owned(),
}
.to_string(),
BuildError::InvalidLimits("expansion depth must be non-zero").to_string(),
BuildError::MissingSiteConfig.to_string(),
TitleError::Empty.to_string(),
TitleError::ForbiddenChar('<').to_string(),
TitleError::TooLong { bytes: 300 }.to_string(),
TitleError::RelativePath.to_string(),
TitleError::Signature.to_string(),
TitleError::LeadingColon.to_string(),
];
for message in messages {
assert!(!message.is_empty());
}
}
#[test]
fn errors_are_debuggable() {
let rendered = format!(
"{:?} {:?} {:?}",
ConfigError::MissingMainNamespace,
BuildError::InvalidLimits("x"),
TitleError::Empty,
);
assert!(rendered.contains("MissingMainNamespace"));
}
}