pub struct BlockCountMismatch {
pub family: String,
pub expected: usize,
pub got: usize,
}
impl BlockCountMismatch {
pub fn message(&self) -> String {
let unit = if self.expected == 1 {
"block"
} else {
"blocks"
};
format!(
"{} expects {} {unit}, got {}",
self.family, self.expected, self.got
)
}
}
impl From<BlockCountMismatch> for String {
fn from(err: BlockCountMismatch) -> String {
err.message()
}
}
#[inline]
pub fn validate_block_count<E>(
family: impl Into<String>,
expected: usize,
got: usize,
) -> Result<(), E>
where
E: From<BlockCountMismatch>,
{
if got != expected {
return Err(BlockCountMismatch {
family: family.into(),
expected,
got,
}
.into());
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn matching_count_is_ok() {
let result: Result<(), String> = validate_block_count("FooFamily", 2, 2);
assert!(result.is_ok());
let zero: Result<(), String> = validate_block_count("EmptyFamily", 0, 0);
assert!(zero.is_ok());
}
#[test]
fn wrong_count_is_rejected_with_canonical_message() {
let err: String = validate_block_count::<String>("FooFamily", 2, 1).unwrap_err();
assert_eq!(err, "FooFamily expects 2 blocks, got 1");
let too_many: String = validate_block_count::<String>("FooFamily", 2, 3).unwrap_err();
assert_eq!(too_many, "FooFamily expects 2 blocks, got 3");
}
#[test]
fn singular_block_wording_when_expected_is_one() {
let err: String = validate_block_count::<String>("BarFamily", 1, 0).unwrap_err();
assert_eq!(err, "BarFamily expects 1 block, got 0");
}
#[test]
fn mismatch_carrier_message_matches_helper() {
let carrier = BlockCountMismatch {
family: "BazFamily".to_string(),
expected: 3,
got: 5,
};
assert_eq!(carrier.message(), "BazFamily expects 3 blocks, got 5");
let converted: String = carrier.into();
assert_eq!(converted, "BazFamily expects 3 blocks, got 5");
}
}