#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CheckCode {
pub(crate) bytes: [u8; 2],
}
pub enum DigitMode {
AllowLeadingZero,
NoLeadingZero,
}
impl CheckCode {
pub const fn as_bytes(&self) -> &[u8; 2] {
&self.bytes
}
pub const fn to_digit(&self, mode: DigitMode) -> u8 {
let first = match mode {
DigitMode::AllowLeadingZero => (self.bytes[0] % 10) * 10,
DigitMode::NoLeadingZero => ((self.bytes[0] % 9) + 1) * 10,
};
let second = self.bytes[1] % 10;
first + second
}
}
#[cfg(test)]
mod tests {
use proptest::prelude::*;
use super::*;
#[test]
fn check_code_with_leading_zero() {
let check_code = CheckCode { bytes: [0x0, 0x0] };
let digit = check_code.to_digit(DigitMode::AllowLeadingZero);
assert_eq!(digit, 0, "Two zero bytes should generate a 0 digit");
assert_eq!(
check_code.as_bytes(),
&[0x0, 0x0],
"CheckCode::as_bytes() should return the exact bytes we generated."
);
let check_code = CheckCode { bytes: [0x9, 0x9] };
let digit = check_code.to_digit(DigitMode::AllowLeadingZero);
assert_eq!(
check_code.as_bytes(),
&[0x9, 0x9],
"CheckCode::as_bytes() should return the exact bytes we generated."
);
assert_eq!(digit, 99);
let check_code = CheckCode { bytes: [0xff, 0xff] };
let digit = check_code.to_digit(DigitMode::AllowLeadingZero);
assert_eq!(
check_code.as_bytes(),
&[0xff, 0xff],
"CheckCode::as_bytes() should return the exact bytes we generated."
);
assert_eq!(digit, 55, "u8::MAX should generate 55");
}
#[test]
fn check_code_no_leading_zero() {
let check_code = CheckCode { bytes: [0x0, 0x0] };
let digit = check_code.to_digit(DigitMode::NoLeadingZero);
assert_eq!(digit, 10, "Two zero bytes should generate a 10 digit");
assert_eq!(
check_code.as_bytes(),
&[0x0, 0x0],
"CheckCode::as_bytes() should return the exact bytes we generated."
);
let check_code = CheckCode { bytes: [0x8, 0x9] };
let digit = check_code.to_digit(DigitMode::NoLeadingZero);
assert_eq!(
check_code.as_bytes(),
&[0x8, 0x9],
"CheckCode::as_bytes() should return the exact bytes we generated."
);
assert_eq!(digit, 99);
let check_code = CheckCode { bytes: [0xff, 0xff] };
let digit = check_code.to_digit(DigitMode::NoLeadingZero);
assert_eq!(
check_code.as_bytes(),
&[0xff, 0xff],
"CheckCode::as_bytes() should return the exact bytes we generated."
);
assert_eq!(digit, 45, "u8::MAX should generate 45");
}
proptest! {
#[test]
fn check_code_proptest_with_leading_zero(bytes in prop::array::uniform2(0u8..) ) {
let check_code = CheckCode {
bytes
};
let digit = check_code.to_digit(DigitMode::AllowLeadingZero);
prop_assert!(
(0..=99).contains(&digit),
"The digit should be in the 0-99 range"
);
}
#[test]
fn check_code_proptest_no_leading_zero(bytes in prop::array::uniform2(0u8..) ) {
let check_code = CheckCode {
bytes
};
let digit = check_code.to_digit(DigitMode::NoLeadingZero);
prop_assert!(
(0..=99).contains(&digit),
"The digit should be in the 0-99 range"
);
}
}
}