use crate::secondary_validation::{Validator, get_previous_digit};
pub struct LuhnChecksum;
impl Validator for LuhnChecksum {
fn is_valid_match(&self, regex_match: &str) -> bool {
let mut input_iter = regex_match.chars();
if let Some(checksum) = get_previous_digit(&mut input_iter) {
let mut sum: u32 = 0;
let mut is_odd = false;
while let Some(digit) = get_previous_digit(&mut input_iter) {
if is_odd {
sum += digit
} else if digit > 4 {
sum += digit * 2 - 9;
} else {
sum += digit * 2
}
is_odd = !is_odd;
}
return (10 - (sum % 10)) % 10 == checksum;
}
false
}
}
#[cfg(test)]
mod test {
use crate::secondary_validation::*;
#[test]
fn validate_various_credit_cards() {
let credit_cards = vec![
"3782 822463 10005",
"3714 4963 5398 431",
"378734493671000",
"5610591081018250",
"3056 930902 5904",
"3852 0000 0232 37",
"6011111111111117",
"6011 0009 9013 9424",
"3530111333300000",
"35660020 20360505",
"5555555555554444",
"5105 1051 0510 5100",
"4111 1111 1111 1111",
"40128888 88881881",
"4222222222222",
"5019717010103742",
"6331101999990016",
];
for credit_card in credit_cards {
println!("credit card input: {credit_card}");
assert!(LuhnChecksum.is_valid_match(credit_card));
let (split_credit_card, last_digit) = credit_card.split_at(credit_card.len() - 1);
let mut wrong_credit_card = split_credit_card.to_string();
wrong_credit_card
.push_str(&((last_digit.parse::<u32>().unwrap() + 1) * 2 % 10).to_string());
println!("wrong credit card input: {wrong_credit_card}");
assert!(!LuhnChecksum.is_valid_match(&wrong_credit_card));
}
}
#[test]
fn skip_non_digit_characters() {
assert!(LuhnChecksum.is_valid_match("378282246310005"));
assert!(LuhnChecksum.is_valid_match("3 7 8 2 8 2 2 4ABC, 6 3 1 🎅0 0 0 5"));
}
}