use utils;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FixError {
NonAsciiString,
TooLong,
CheckDigitIncorrect,
}
pub fn check(code: &str) -> bool {
if code.len() != 13 {
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[12] - 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() > 13 {
return Err(FixError::TooLong);
}
fixed = utils::zero_pad(fixed, 13);
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("0000000000000"), true);
assert_eq!(check("8845791354268"), true);
assert_eq!(check("0334873614126"), true);
}
#[test]
fn check_invalid_length() {
assert_eq!(check("000"), false);
assert_eq!(check("00000000000000"), false);
}
#[test]
fn check_non_ascii() {
assert_eq!(check("❤"), false);
}
#[test]
fn check_non_numeric() {
assert_eq!(check("a"), false);
assert_eq!(check("abcdabcdabcda"), false); assert_eq!(check("000000000000a"), false); }
#[test]
fn check_invalid_check_digit() {
assert_eq!(check("0000000000001"), false);
assert_eq!(check("0000000000002"), false);
assert_eq!(check("0000000000003"), false);
assert_eq!(check("0000000000004"), false);
assert_eq!(check("0000000000005"), false);
assert_eq!(check("0000000000006"), false);
assert_eq!(check("0000000000007"), false);
assert_eq!(check("0000000000008"), false);
assert_eq!(check("0000000000009"), false);
}
#[test]
fn check_static_data() {
assert_eq!(check("0000000000000"), true);
assert_eq!(check("0123456789012"), true);
assert_eq!(check("0123456789013"), false);
assert_eq!(check("0999999999993"), true);
assert_eq!(check("0999999999999"), false);
assert_eq!(check("4459121265748"), true);
assert_eq!(check("4459121265747"), false);
}
#[test]
fn fix_non_ascii() {
assert!(fix("❤").is_err());
}
#[test]
fn fix_too_long() {
assert_eq!(fix("00000000000000"), Err(FixError::TooLong));
}
#[test]
fn fix_incorrect_check_digit() {
assert_eq!(fix("8845791354262"), Err(FixError::CheckDigitIncorrect));
}
#[test]
fn fix_needs_zero_padding() {
assert!(fix("0").is_ok());
assert_eq!(fix("0").unwrap(), "0000000000000");
assert_eq!(fix("123012301238").unwrap(), "0123012301238");
}
proptest! {
#[test]
fn doesnt_crash(ref s in ".*") {
check(s);
}
}
}