Skip to content

Commit

Permalink
Add Bulgaria
Browse files Browse the repository at this point in the history
  • Loading branch information
SLourenco committed Dec 26, 2024
1 parent 425aace commit 387548c
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* Add Albania validator
* Add Bosnia Herzegovina
* Add Yugoslavia
* Add Bulgaria

### 1.0.0

Expand Down
1 change: 1 addition & 0 deletions src/country.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub enum Code {
AL,
BA,
BE,
BG,
BR,
CA,
DK,
Expand Down
126 changes: 126 additions & 0 deletions src/validator/bulgaria.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use crate::country::Code;
use crate::validator::CountryValidator;
use crate::Citizen;
use chrono::{Datelike, NaiveDate};
use regex::Regex;

pub(crate) struct BulgariaValidator;

/**
* TODO: Find official docs on validation
*/
impl CountryValidator for BulgariaValidator {
fn validate_id(&self, id: &str) -> bool {
let standard_id = self.sanitize_id(id);
if !Regex::new(r"^\d{10}$").unwrap().is_match(&standard_id) {
return false;
}

let sum = (2 * standard_id[0..1].parse::<u32>().unwrap())
+ (4 * standard_id[1..2].parse::<u32>().unwrap())
+ (8 * standard_id[2..3].parse::<u32>().unwrap())
+ (5 * standard_id[3..4].parse::<u32>().unwrap())
+ (10 * standard_id[4..5].parse::<u32>().unwrap())
+ (9 * standard_id[5..6].parse::<u32>().unwrap())
+ (7 * standard_id[6..7].parse::<u32>().unwrap())
+ (3 * standard_id[7..8].parse::<u32>().unwrap())
+ (6 * standard_id[8..9].parse::<u32>().unwrap());

let check_digit = standard_id[9..10].parse::<u32>().unwrap();
check_digit == (sum % 11)
}

fn country_code(&self) -> Code {
Code::BG
}

fn extract_citizen(&self, id: &str) -> Option<Citizen> {
if !self.validate_id(id) {
return None;
}
let standard_id = self.sanitize_id(id);
let year = standard_id[0..2].parse::<i32>().unwrap();
let month = standard_id[2..4].parse::<u32>().unwrap();
let m;
let y;
if month > 40 {
m = month - 40;
y = 2000 + year;
} else if month < 20 {
m = month;
y = 1900 + year;
} else {
m = month - 20;
y = 1800 + year;
}

let date_of_birth =
NaiveDate::from_ymd_opt(y, m, standard_id[4..6].parse::<u32>().unwrap());
if date_of_birth.is_none() {
return None;
}
let dob = date_of_birth.unwrap();

Some(Citizen {
gender: if standard_id[9..].parse::<u32>().unwrap() % 2 == 0 {
'F'
} else {
'M'
},
year_of_birth: dob.year(),
month_of_birth: Some(dob.month() as u8),
day_of_birth: Some(dob.day() as u8),
place_of_birth: None,
})
}
}

#[cfg(test)]
mod tests {
use crate::validator::bulgaria::BulgariaValidator;
use crate::validator::CountryValidator;

#[test]
fn bg_validator_requires_len_10() {
let validator = BulgariaValidator;
assert_eq!(false, validator.validate_id("123"));
assert_eq!(false, validator.validate_id("12345678901"));
}

#[test]
fn bg_validator_invalid_ids() {
let validator = BulgariaValidator;
assert_eq!(false, validator.validate_id("7542021030"));
assert_eq!(false, validator.validate_id("8002560008"));
assert_eq!(false, validator.validate_id("3542027033"));
assert_eq!(false, validator.validate_id("6002567498"));
assert_eq!(false, validator.validate_id("7542039611"));
}

#[test]
fn bg_validator_valid_ids() {
let validator = BulgariaValidator;
assert_eq!(true, validator.validate_id("7523169263"));
assert_eq!(true, validator.validate_id("8032056031"));
assert_eq!(true, validator.validate_id("8001010008"));
assert_eq!(true, validator.validate_id("7501020018"));
assert_eq!(true, validator.validate_id("7552010005"));
assert_eq!(true, validator.validate_id("7542011030"));
}

#[test]
fn bg_citizen_extractor() {
let validator = BulgariaValidator;
let c1 = validator.extract_citizen("7523169263").unwrap();
assert_eq!('M', c1.gender);
assert_eq!(1875, c1.year_of_birth);
assert_eq!(3, c1.month_of_birth.unwrap());
assert_eq!(16, c1.day_of_birth.unwrap());

let c2 = validator.extract_citizen("8001010008").unwrap();
assert_eq!('F', c2.gender);
assert_eq!(1980, c2.year_of_birth);
assert_eq!(1, c2.month_of_birth.unwrap());
assert_eq!(1, c2.day_of_birth.unwrap());
}
}
2 changes: 2 additions & 0 deletions src/validator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ mod albania;
mod belgium;
mod bosniaherzegovina;
mod brazil;
mod bulgaria;
mod canada;
mod denmark;
mod france;
Expand Down Expand Up @@ -55,6 +56,7 @@ pub fn get_validator(country: &country::Code) -> Box<dyn CountryValidator> {
country::Code::MX => Box::new(mexico::MexicoValidator),
country::Code::AL => Box::new(albania::AlbaniaValidator),
country::Code::BA => Box::new(bosniaherzegovina::BosniaHerzegovinaValidator),
country::Code::BG => Box::new(bulgaria::BulgariaValidator),
}
}

Expand Down

0 comments on commit 387548c

Please sign in to comment.