use utils;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FixError {
NonAsciiString,
TooLong,
CheckDigitIncorrect,
}
pub fn check(code: &str) -> bool {
if code.len() != 14 {
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[13] - 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() > 14 {
return Err(FixError::TooLong);
}
fixed = utils::zero_pad(fixed, 14);
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("00000000000000"), true);
assert_eq!(check("17342894127884"), true);
assert_eq!(check("44889977112244"), true);
}
#[test]
fn check_invalid_length() {
assert_eq!(check("0000000000000"), false);
assert_eq!(check("1734289412788"), false);
}
#[test]
fn check_non_ascii() {
assert_eq!(check("❤"), false);
}
#[test]
fn check_non_numeric() {
assert_eq!(check("a"), false);
assert_eq!(check("abcdabcdabcdab"), false); assert_eq!(check("0000000000000a"), false); }
#[test]
fn check_invalid_check_digit() {
assert_eq!(check("00000000000001"), false);
assert_eq!(check("00000000000002"), false);
assert_eq!(check("00000000000003"), false);
assert_eq!(check("00000000000004"), false);
assert_eq!(check("00000000000005"), false);
assert_eq!(check("00000000000006"), false);
assert_eq!(check("00000000000007"), false);
assert_eq!(check("00000000000008"), false);
assert_eq!(check("00000000000009"), false);
}
#[test]
fn check_static_data() {
assert_eq!(check("14567815983469"), true); assert_eq!(check("1456781598346"), false); assert_eq!(check("14567815983468"), false); }
#[test]
fn fix_non_ascii() {
assert!(fix("❤").is_err());
}
#[test]
fn fix_too_long() {
assert_eq!(fix("000000000000000"), Err(FixError::TooLong));
}
#[test]
fn fix_incorrect_check_digit() {
assert_eq!(fix("17342894127889"), Err(FixError::CheckDigitIncorrect));
}
#[test]
fn fix_needs_zero_padding() {
assert!(fix("0").is_ok());
assert_eq!(fix("0").unwrap(), "00000000000000");
assert_eq!(fix("8987561651112").unwrap(), "08987561651112");
}
proptest! {
#[test]
fn doesnt_crash(ref s in ".*") {
check(s);
}
}
}