Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public String getInvalid(BaseProviders faker) {
}

public String getValid(BaseProviders faker) {
LocalDate birthDate = faker.date().birthdayLocalDate(0, 200);
LocalDate birthDate = faker.timeAndDate().birthday(0, 200);
boolean female = faker.bool().bool();
String basePart = yy(birthDate.getYear()) + mm(birthDate.getMonthValue(), female) + dd(birthDate.getDayOfMonth()) + sss(faker);
return basePart + checksum(basePart);
Expand Down
62 changes: 62 additions & 0 deletions src/main/java/net/datafaker/idnumbers/BulgarianIdNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package net.datafaker.idnumbers;

import net.datafaker.providers.base.BaseProviders;

import java.time.LocalDate;

/**
* <a href="https://en.wikipedia.org/wiki/Unique_citizenship_number">Specification</a>
*/
public class BulgarianIdNumber implements IdNumbers {
private static final int[] CHECKSUM_WEIGHTS = {2, 4, 8, 5, 10, 9, 7, 3, 6};
private static final int[] EVEN_DIGITS = {0, 2, 4, 6, 8};
private static final int[] ODD_DIGITS = {1, 3, 5, 7, 9};

public String getValid(BaseProviders faker) {
String basePart = basePart(faker);
return basePart + checksum(basePart);
}

public String getInvalid(BaseProviders faker) {
String basePart = basePart(faker);
return basePart + (checksum(basePart) + 1) % 10;
}

private String basePart(BaseProviders faker) {
LocalDate birthDate = faker.timeAndDate().birthday(0, 200);
boolean female = faker.bool().bool();
return yy(birthDate) + mm(birthDate) + dd(birthDate) + order(faker, female);
}

private String yy(LocalDate birthDate) {
return "%02d".formatted(birthDate.getYear() % 100);
}

private String mm(LocalDate birthDate) {
int monthAddition = birthDate.getYear() < 1900 ? 20 :
birthDate.getYear() >= 2000 ? 40 : 0;
return "%02d".formatted(birthDate.getMonthValue() + monthAddition);
}

private String dd(LocalDate birthDate) {
return "%02d".formatted(birthDate.getDayOfMonth());
}

private String order(BaseProviders faker, boolean female) {
int[] availableLastDigits = female ? ODD_DIGITS : EVEN_DIGITS;
int lastDigit = availableLastDigits[faker.number().numberBetween(0, 5)];
return faker.number().digits(2) + lastDigit;
}

int checksum(String text) {
int checksum = 0;
for (int i = 0; i < text.length(); i++) {
checksum += digitAt(text, i) * CHECKSUM_WEIGHTS[i];
}
return (checksum % 11) % 10;
}

private int digitAt(String text, int index) {
return text.charAt(index) - '0';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public String getValid(final BaseProviders faker) {
}

private String basePart(BaseProviders faker) {
LocalDate birthday = faker.date().birthdayLocalDate(0, 100);
LocalDate birthday = faker.timeAndDate().birthday(0, 100);
return firstDigit(faker) +
BIRTHDAY_FORMAT.format(birthday) +
faker.number().digits(3);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/net/datafaker/idnumbers/MoldovaIdNumber.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public String getInvalid(BaseProviders faker) {
}

private String basePart(BaseProviders faker) {
var birthday = faker.date().birthdayLocalDate(0, 120);
var birthday = faker.timeAndDate().birthday(0, 120);
// IDNP: 2ГГГXXXYYYYYK
return firstDigit() + ГГГ(birthday) + XXX(faker) + YYYYY(faker);
}
Expand Down
85 changes: 50 additions & 35 deletions src/main/java/net/datafaker/providers/base/IdNumber.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.datafaker.providers.base;

import net.datafaker.idnumbers.AlbanianIdNumber;
import net.datafaker.idnumbers.BulgarianIdNumber;
import net.datafaker.idnumbers.EnIdNumber;
import net.datafaker.idnumbers.EnZAIdNumber;
import net.datafaker.idnumbers.EsMXIdNumber;
Expand All @@ -16,6 +17,7 @@
import net.datafaker.idnumbers.SvSEIdNumber;
import net.datafaker.idnumbers.ZhCnIdNumber;

import java.lang.reflect.InvocationTargetException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Map;
Expand All @@ -26,7 +28,7 @@
*/
public class IdNumber extends AbstractProvider<BaseProviders> {

private final Map<Class<? extends IdNumbers>, IdNumbers> map = new ConcurrentHashMap<>();
private final Map<Class<? extends IdNumbers>, IdNumbers> providers = new ConcurrentHashMap<>();

protected IdNumber(BaseProviders faker) {
super(faker);
Expand All @@ -41,40 +43,35 @@ public String invalid() {
}

public String ssnValid() {
EnIdNumber enIdNumber = (EnIdNumber) map.computeIfAbsent(EnIdNumber.class, aClass -> new EnIdNumber());
return enIdNumber.getValidSsn(faker);
return provider(EnIdNumber.class).getValidSsn(faker);
}

/**
* Specified as #{IDNumber.valid_sv_se_ssn} in sv-SE.yml
*/
public String validSvSeSsn() {
SvSEIdNumber svSEIdNumber = (SvSEIdNumber) map.computeIfAbsent(SvSEIdNumber.class, aClass -> new SvSEIdNumber());
return svSEIdNumber.getValidSsn(faker);
return provider(SvSEIdNumber.class).getValidSsn(faker);
}

/**
* Specified as #{IDNumber.valid_en_za_ssn} in en-ZA.yml
*/
public String validEnZaSsn() {
EnZAIdNumber enZAIdNumber = (EnZAIdNumber) map.computeIfAbsent(EnZAIdNumber.class, aClass -> new EnZAIdNumber());
return enZAIdNumber.getValidSsn(faker);
return provider(EnZAIdNumber.class).getValidSsn(faker);
}

/**
* Specified as #{IDNumber.invalid_en_za_ssn} in en-ZA.yml
*/
public String inValidEnZaSsn() {
EnZAIdNumber enZAIdNumber = (EnZAIdNumber) map.computeIfAbsent(EnZAIdNumber.class, aClass -> new EnZAIdNumber());
return enZAIdNumber.getInValidSsn(faker);
return provider(EnZAIdNumber.class).getInValidSsn(faker);
}

/**
* Specified as #{IDNumber.invalid_sv_se_ssn} in sv-SE.yml
*/
public String invalidSvSeSsn() {
SvSEIdNumber svSEIdNumber = (SvSEIdNumber) map.computeIfAbsent(SvSEIdNumber.class, aClass -> new SvSEIdNumber());
return svSEIdNumber.getInvalidSsn(faker);
return provider(SvSEIdNumber.class).getInvalidSsn(faker);
}

public String singaporeanFin() {
Expand All @@ -99,18 +96,15 @@ public String singaporeanUinBefore2000() {
* @return A Zh-CN id number
*/
public String validZhCNSsn() {
ZhCnIdNumber zhCnIdNumber = (ZhCnIdNumber) map.computeIfAbsent(ZhCnIdNumber.class, aClass -> new ZhCnIdNumber());
return zhCnIdNumber.getValidSsn(faker);
return provider(ZhCnIdNumber.class).getValidSsn(faker);
}

public String validPtNif() {
PtNifIdNumber idNumber = (PtNifIdNumber) map.computeIfAbsent(PtNifIdNumber.class, aClass -> new PtNifIdNumber());
return idNumber.getValid(faker);
return provider(PtNifIdNumber.class).getValid(faker);
}

public String invalidPtNif() {
PtNifIdNumber idNumber = (PtNifIdNumber) map.computeIfAbsent(PtNifIdNumber.class, aClass -> new PtNifIdNumber());
return idNumber.getInvalid(faker);
return provider(PtNifIdNumber.class).getInvalid(faker);
}


Expand All @@ -120,8 +114,7 @@ public String invalidPtNif() {
* @return A valid MEX CURP.
*/
public String validEsMXSsn() {
EsMXIdNumber esMXIdNumber = (EsMXIdNumber) map.computeIfAbsent(EsMXIdNumber.class, aClass -> new EsMXIdNumber());
return esMXIdNumber.get(faker);
return provider(EsMXIdNumber.class).get(faker);
}

/**
Expand All @@ -130,8 +123,7 @@ public String validEsMXSsn() {
* @return A valid MEX CURP.
*/
public String invalidEsMXSsn() {
EsMXIdNumber esMXIdNumber = (EsMXIdNumber) map.computeIfAbsent(EsMXIdNumber.class, aClass -> new EsMXIdNumber());
return esMXIdNumber.getWrong(faker);
return provider(EsMXIdNumber.class).getWrong(faker);
}

/**
Expand Down Expand Up @@ -163,8 +155,7 @@ public String peselNumber(LocalDate birthDate, Gender gender) {
* @since 1.8.0
*/
public String validKoKrRrn() {
KoKrIdNumber koKrIdNumber = (KoKrIdNumber) map.computeIfAbsent(KoKrIdNumber.class, aClass -> new KoKrIdNumber());
return koKrIdNumber.getValidRrn(faker);
return provider(KoKrIdNumber.class).getValidRrn(faker);
}

/**
Expand All @@ -182,8 +173,7 @@ public String validGeIDNumber() {
* @return A valid ID Number
*/
public String validEstonianPersonalCode() {
EstonianIdNumber idNumber = (EstonianIdNumber) map.computeIfAbsent(EstonianIdNumber.class, aClass -> new EstonianIdNumber());
return idNumber.getValid(faker);
return provider(EstonianIdNumber.class).getValid(faker);
}

/**
Expand All @@ -193,8 +183,7 @@ public String validEstonianPersonalCode() {
* @return An invalid ID Number
*/
public String invalidEstonianPersonalCode() {
EstonianIdNumber idNumber = (EstonianIdNumber) map.computeIfAbsent(EstonianIdNumber.class, aClass -> new EstonianIdNumber());
return idNumber.getInvalid(faker);
return provider(EstonianIdNumber.class).getInvalid(faker);
}

/**
Expand All @@ -203,8 +192,7 @@ public String invalidEstonianPersonalCode() {
* @return A valid ID Number
*/
public String validAlbanianPersonalCode() {
AlbanianIdNumber idNumber = (AlbanianIdNumber) map.computeIfAbsent(AlbanianIdNumber.class, aClass -> new AlbanianIdNumber());
return idNumber.getValid(faker);
return provider(AlbanianIdNumber.class).getValid(faker);
}

/**
Expand All @@ -213,8 +201,7 @@ public String validAlbanianPersonalCode() {
* @return An invalid ID Number
*/
public String invalidAlbanianPersonalCode() {
AlbanianIdNumber idNumber = (AlbanianIdNumber) map.computeIfAbsent(AlbanianIdNumber.class, aClass -> new AlbanianIdNumber());
return idNumber.getInvalid(faker);
return provider(AlbanianIdNumber.class).getInvalid(faker);
}

/**
Expand All @@ -223,8 +210,7 @@ public String invalidAlbanianPersonalCode() {
* @return A valid ID Number
*/
public String validMoldovaPersonalCode() {
MoldovaIdNumber idNumber = (MoldovaIdNumber) map.computeIfAbsent(MoldovaIdNumber.class, aClass -> new MoldovaIdNumber());
return idNumber.getValid(faker);
return provider(MoldovaIdNumber.class).getValid(faker);
}

/**
Expand All @@ -233,8 +219,37 @@ public String validMoldovaPersonalCode() {
* @return An invalid ID Number
*/
public String invalidMoldovaPersonalCode() {
MoldovaIdNumber idNumber = (MoldovaIdNumber) map.computeIfAbsent(MoldovaIdNumber.class, aClass -> new MoldovaIdNumber());
return idNumber.getInvalid(faker);
return provider(MoldovaIdNumber.class).getInvalid(faker);
}

/**
* Generates a valid ID number for Bulgaria citizens and residents
* Specified as #{IDNumber.valid_bulgarian_personal_code} in et.yml
* @return A valid ID Number
*/
public String validBulgarianPersonalCode() {
return provider(BulgarianIdNumber.class).getValid(faker);
}

/**
* Generates a valid ID number for Bulgaria citizens and residents
* Specified as #{IDNumber.invalid_bulgarian_personal_code} in et.yml
* @return An invalid ID Number
*/
public String invalidBulgarianPersonalCode() {
return provider(BulgarianIdNumber.class).getInvalid(faker);
}

@SuppressWarnings("unchecked")
private <T extends IdNumbers> T provider(Class<T> clazz) {
return (T) providers.computeIfAbsent(clazz, aClass -> create(clazz));
}

private <T extends IdNumbers> T create(Class<T> clazz) {
try {
return clazz.getDeclaredConstructor().newInstance();
} catch (InstantiationException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException("Failed to instantiate class " + clazz.getName(), e);
}
}
}
4 changes: 4 additions & 0 deletions src/main/resources/bg.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@ bg:

passport:
valid: "[0-9]{9}"

id_number:
valid: "#{IDNumber.valid_bulgarian_personal_code}"
invalid: "#{IDNumber.invalid_bulgarian_personal_code}"
21 changes: 21 additions & 0 deletions src/test/java/net/datafaker/idnumbers/BulgarianIdNumberTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package net.datafaker.idnumbers;

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

class BulgarianIdNumberTest {
private final BulgarianIdNumber generator = new BulgarianIdNumber();

@Test
void checksum() {
assertThat(generator.checksum("803205603")).isEqualTo(1);
assertThat(generator.checksum("800101000")).isEqualTo(8);
assertThat(generator.checksum("750102001")).isEqualTo(8);
assertThat(generator.checksum("820630876")).isEqualTo(0);
assertThat(generator.checksum("560628204")).isEqualTo(7);
assertThat(generator.checksum("752316926")).isEqualTo(3);
assertThat(generator.checksum("755201000")).isEqualTo(5);
assertThat(generator.checksum("754201103")).isEqualTo(0);
}
}
Loading