use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
NotFound,
MultipleLinks,
Malformed(&'static str),
Inaccessible,
}
impl Error {
pub fn code(&self) -> Option<&'static str> {
match self {
Self::Inaccessible => Some("manifest.inaccessible"),
Self::NotFound | Self::MultipleLinks | Self::Malformed(_) => None,
}
}
pub fn is_no_manifest_located(&self) -> bool {
matches!(
self,
Self::NotFound | Self::MultipleLinks | Self::Malformed(_)
)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NotFound => write!(f, "no c2pa-manifest Link header found"),
Self::MultipleLinks => {
write!(f, "more than one c2pa-manifest target was advertised")
}
Self::Malformed(why) => write!(f, "malformed Link header: {why}"),
Self::Inaccessible => {
write!(f, "the advertised manifest could not be retrieved")
}
}
}
}
impl std::error::Error for Error {}
#[cfg(test)]
mod tests {
use super::*;
fn all() -> Vec<Error> {
vec![
Error::NotFound,
Error::MultipleLinks,
Error::Malformed("unterminated target"),
Error::Inaccessible,
]
}
#[test]
fn display_composes_into_a_sentence_for_every_variant() {
for e in all() {
let s = e.to_string();
assert!(!s.is_empty(), "{e:?} rendered empty");
assert!(!s.ends_with('.'), "{e:?} ends with a period: {s}");
let first = s.chars().next().expect("checked non-empty above");
assert!(!first.is_uppercase(), "{e:?} starts uppercase: {s}");
}
}
#[test]
fn only_inaccessible_carries_a_code() {
assert_eq!(Error::Inaccessible.code(), Some("manifest.inaccessible"));
for e in [Error::NotFound, Error::MultipleLinks, Error::Malformed("x")] {
assert_eq!(e.code(), None, "{e:?} must not report a status code");
assert!(
e.is_no_manifest_located(),
"{e:?} must classify as unsigned"
);
}
}
#[test]
fn inaccessible_is_not_an_absence_of_provenance() {
assert!(!Error::Inaccessible.is_no_manifest_located());
}
#[test]
fn every_code_is_a_registered_identifier() {
for e in all() {
if let Some(code) = e.code() {
assert_eq!(code, "manifest.inaccessible", "{e:?} invented a code");
}
}
}
}