use gix_hash::ObjectId;
#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
pub enum RegistryError {
#[error("repo not found")]
NotFound,
#[error("access denied")]
Forbidden,
#[error("repo already exists")]
AlreadyExists,
#[error("invalid registry record or field")]
Invalid,
#[error("registry backing-store failure: {0}")]
Io(String),
}
#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
pub enum StorageError {
#[error("object {oid} does not exist")]
ObjectMissing {
oid: ObjectId,
},
#[error("invalid object-storage input or state: {0}")]
Invalid(String),
#[error("object-storage backing-store failure: {0}")]
Io(String),
}
#[cfg(test)]
mod tests {
use super::*;
fn oid(b: u8) -> ObjectId {
ObjectId::from([b; 20])
}
#[test]
fn registry_error_has_exactly_the_five_pinned_variants() {
let all = [
RegistryError::NotFound,
RegistryError::Forbidden,
RegistryError::AlreadyExists,
RegistryError::Invalid,
RegistryError::Io("corrupted index".to_string()),
];
for e in &all {
let _dbg: &dyn std::fmt::Debug = e;
let _err: &dyn std::error::Error = e;
}
assert_eq!(all.len(), 5);
}
#[test]
fn registry_error_display_paths_render() {
assert_eq!(RegistryError::NotFound.to_string(), "repo not found");
assert_eq!(RegistryError::Forbidden.to_string(), "access denied");
assert_eq!(
RegistryError::AlreadyExists.to_string(),
"repo already exists"
);
assert_eq!(
RegistryError::Invalid.to_string(),
"invalid registry record or field"
);
assert_eq!(
RegistryError::Io("sqlite step failed".to_string()).to_string(),
"registry backing-store failure: sqlite step failed"
);
}
#[test]
fn registry_error_is_comparable_and_clonable() {
assert_eq!(RegistryError::NotFound, RegistryError::NotFound);
assert_ne!(RegistryError::NotFound, RegistryError::Forbidden);
let io = RegistryError::Io("disk".to_string());
assert_eq!(io.clone(), io);
}
#[test]
fn storage_error_has_exactly_the_three_pinned_variants() {
let all = [
StorageError::ObjectMissing { oid: oid(1) },
StorageError::Invalid("malformed pack stream".to_string()),
StorageError::Io("blob store unavailable".to_string()),
];
for e in &all {
let _dbg: &dyn std::fmt::Debug = e;
let _err: &dyn std::error::Error = e;
}
assert_eq!(all.len(), 3);
}
#[test]
fn storage_error_object_missing_carries_the_gix_oid() {
let e = StorageError::ObjectMissing { oid: oid(7) };
match e {
StorageError::ObjectMissing { oid: carried } => assert_eq!(carried, oid(7)),
other => panic!("wrong variant: {other:?}"),
}
assert_eq!(
StorageError::ObjectMissing { oid: oid(7) }.to_string(),
"object 0707070707070707070707070707070707070707 does not exist"
);
}
#[test]
fn storage_error_display_paths_render() {
assert_eq!(
StorageError::Invalid("index-write failed fsck".to_string()).to_string(),
"invalid object-storage input or state: index-write failed fsck"
);
assert_eq!(
StorageError::Io("rocksdb opened twice".to_string()).to_string(),
"object-storage backing-store failure: rocksdb opened twice"
);
}
#[test]
fn storage_error_is_comparable_and_clonable() {
assert_eq!(
StorageError::ObjectMissing { oid: oid(2) },
StorageError::ObjectMissing { oid: oid(2) }
);
let invalid = StorageError::Invalid("d".to_string());
assert_eq!(invalid.clone(), invalid);
assert_ne!(
StorageError::Invalid("a".to_string()),
StorageError::Io("a".to_string())
);
}
}