use utils;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FixError {
NonAsciiString,
TooLong,
CheckDigitIncorrect,
}
pub fn check(code: &str) -> bool {
if code.len() != 8 {
return false;
}
if !utils::is_ascii_numeric(code) {
return false;
}
let bytes = code.as_bytes();
let check = utils::compute_check_digit(bytes);
if check != bytes[7] - 48 {
return false;
}
true
}
pub fn fix(code: &str) -> Result<String, FixError> {
let mut fixed = code.trim().to_string();
if !fixed.is_ascii() {
return Err(FixError::NonAsciiString);
}
if fixed.len() > 8 {
return Err(FixError::TooLong);
}
fixed = utils::zero_pad(fixed, 8);
if !check(&fixed) {
return Err(FixError::CheckDigitIncorrect);
}
Ok(fixed)
}
#[cfg(test)]
mod tests {
use super::check;
use super::fix;
use super::FixError;
#[test]
fn check_valid() {
assert_eq!(check("00000000"), true);
assert_eq!(check("49137712"), true);
assert_eq!(check("44196318"), true);
}
#[test]
fn check_invalid_length() {
assert_eq!(check("0000000"), false); assert_eq!(check("734289412"), false); }
#[test]
fn check_non_ascii() {
assert_eq!(check("❤"), false);
}
#[test]
fn check_non_numeric() {
assert_eq!(check("a"), false);
assert_eq!(check("abcdabcd"), false); assert_eq!(check("0000000a"), false); }
#[test]
fn check_invalid_check_digit() {
assert_eq!(check("00000001"), false);
assert_eq!(check("00000002"), false);
assert_eq!(check("00000003"), false);
assert_eq!(check("00000004"), false);
assert_eq!(check("00000005"), false);
assert_eq!(check("00000006"), false);
assert_eq!(check("00000007"), false);
assert_eq!(check("00000008"), false);
assert_eq!(check("00000009"), false);
}
#[test]
fn check_static_data() {
assert_eq!(check("14567810"), true); assert_eq!(check("1456781"), false); assert_eq!(check("14567811"), false); }
#[test]
fn fix_non_ascii() {
assert!(fix("❤").is_err());
}
#[test]
fn fix_too_long() {
assert_eq!(fix("000000000"), Err(FixError::TooLong));
}
#[test]
fn fix_incorrect_check_digit() {
assert_eq!(fix("14567813"), Err(FixError::CheckDigitIncorrect));
}
#[test]
fn fix_needs_zero_padding() {
assert!(fix("0").is_ok());
assert_eq!(fix("0").unwrap(), "00000000");
assert_eq!(fix("9944220").unwrap(), "09944220");
}
proptest! {
#[test]
fn doesnt_crash(ref s in ".*") {
check(s);
}
}
}