diff --git a/src/main/java/net/datafaker/idnumbers/HungarianIdNumber.java b/src/main/java/net/datafaker/idnumbers/HungarianIdNumber.java new file mode 100644 index 000000000..dc05cb666 --- /dev/null +++ b/src/main/java/net/datafaker/idnumbers/HungarianIdNumber.java @@ -0,0 +1,86 @@ +package net.datafaker.idnumbers; + +import net.datafaker.providers.base.BaseProviders; +import net.datafaker.providers.base.IdNumber; +import net.datafaker.providers.base.PersonIdNumber; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +import static java.lang.Character.getNumericValue; +import static net.datafaker.idnumbers.Utils.randomGender; + +/** + * Hungarian personal identification number + *

+ * The structure of such number is GYYMMDDXXC, whereas + *

+ *

+ * See Hungarian identification number + */ +public class HungarianIdNumber implements IdNumberGenerator { + + private static final DateTimeFormatter BIRTHDAY_FORMAT = DateTimeFormatter.ofPattern("yyMMdd"); + + @Override + public String countryCode() { + return "HU"; + } + + @Override + public String generateInvalid(BaseProviders faker) { + String validIdNumber = generateValid(faker); + String basePart = validIdNumber.substring(0, 9); + int validCheckDigit = getNumericValue(validIdNumber.charAt(9)); + int invalidCheckDigit = (validCheckDigit + 1) % 10; + return basePart + invalidCheckDigit; + } + + @Override + public PersonIdNumber generateValid(BaseProviders faker, IdNumber.IdNumberRequest request) { + LocalDate birthday = faker.timeAndDate().birthday(); + PersonIdNumber.Gender gender = randomGender(faker); + int checkDigit; + String basePart; + do { + basePart = basePart(faker, birthday, gender); + checkDigit = getCheckDigit(basePart); + } while (checkDigit == 10); + + String idNumber = basePart + checkDigit; + return new PersonIdNumber(idNumber, birthday, gender); + } + + private String basePart(BaseProviders faker, LocalDate birthday, PersonIdNumber.Gender gender) { + return firstDigit(birthday.getYear(), gender) + + BIRTHDAY_FORMAT.format(birthday) + + faker.number().digits(2); + } + + static int getCheckDigit(String basePart) { + char[] numbers = basePart.toCharArray(); + int summ = 0; + for (int i = 0; i < numbers.length; i++) { + summ += getNumericValue(numbers[i]) * (i + 1); + } + + return summ % 11; + } + + static int firstDigit(int birthYear, PersonIdNumber.Gender gender) { + return switch (gender) { + case MALE -> isInRange(birthYear) ? 1 : 3; + case FEMALE -> isInRange(birthYear) ? 2 : 4; + }; + } + + private static boolean isInRange(int birthYear) { + return birthYear >= 1900 && birthYear <= 1999; + } + +} diff --git a/src/main/resources/META-INF/services/net.datafaker.idnumbers.IdNumberGenerator b/src/main/resources/META-INF/services/net.datafaker.idnumbers.IdNumberGenerator index 3633ebdda..36f31788d 100644 --- a/src/main/resources/META-INF/services/net.datafaker.idnumbers.IdNumberGenerator +++ b/src/main/resources/META-INF/services/net.datafaker.idnumbers.IdNumberGenerator @@ -5,6 +5,7 @@ net.datafaker.idnumbers.ChineseIdNumber net.datafaker.idnumbers.EstonianIdNumber net.datafaker.idnumbers.FrenchIdNumber net.datafaker.idnumbers.GeorgianIdNumber +net.datafaker.idnumbers.HungarianIdNumber net.datafaker.idnumbers.ItalianIdNumber net.datafaker.idnumbers.LatvianIdNumber net.datafaker.idnumbers.MacedonianIdNumber diff --git a/src/test/java/net/datafaker/helpers/IdNumberPatterns.java b/src/test/java/net/datafaker/helpers/IdNumberPatterns.java index cc069dbee..3248f8b38 100644 --- a/src/test/java/net/datafaker/helpers/IdNumberPatterns.java +++ b/src/test/java/net/datafaker/helpers/IdNumberPatterns.java @@ -10,5 +10,6 @@ public class IdNumberPatterns { public static final Pattern FRENCH = Pattern.compile("[12]\\d{2}(1[0-2]|0[1-9])\\d[0-9a-zA-Z]\\d{8}"); public static final Pattern ITALIAN = Pattern.compile("[A-Z]{6}\\d{2}[ABCDEHLMPRST]\\d{2}[\\dA-Z]{5}"); public static final Pattern POLISH = Pattern.compile("\\d{11}"); + public static final Pattern HUNGARIAN = Pattern.compile("[1-4]\\d{9}"); } diff --git a/src/test/java/net/datafaker/idnumbers/HungarianIdNumberTest.java b/src/test/java/net/datafaker/idnumbers/HungarianIdNumberTest.java new file mode 100644 index 000000000..16a792fa7 --- /dev/null +++ b/src/test/java/net/datafaker/idnumbers/HungarianIdNumberTest.java @@ -0,0 +1,34 @@ +package net.datafaker.idnumbers; + +import org.junit.jupiter.api.Test; + +import static net.datafaker.providers.base.PersonIdNumber.Gender.FEMALE; +import static net.datafaker.providers.base.PersonIdNumber.Gender.MALE; +import static org.assertj.core.api.Assertions.assertThat; + +class HungarianIdNumberTest { + + @Test + void firstDigit() { + assertThat(HungarianIdNumber.firstDigit(1899, MALE)).isEqualTo(3); + assertThat(HungarianIdNumber.firstDigit(1900, MALE)).isEqualTo(1); + assertThat(HungarianIdNumber.firstDigit(1901, MALE)).isEqualTo(1); + assertThat(HungarianIdNumber.firstDigit(1899, FEMALE)).isEqualTo(4); + assertThat(HungarianIdNumber.firstDigit(1900, FEMALE)).isEqualTo(2); + assertThat(HungarianIdNumber.firstDigit(1901, FEMALE)).isEqualTo(2); + assertThat(HungarianIdNumber.firstDigit(1999, MALE)).isEqualTo(1); + assertThat(HungarianIdNumber.firstDigit(2000, MALE)).isEqualTo(3); + assertThat(HungarianIdNumber.firstDigit(1999, FEMALE)).isEqualTo(2); + assertThat(HungarianIdNumber.firstDigit(2000, FEMALE)).isEqualTo(4); + } + + @Test + void checkDigit() { + assertThat(HungarianIdNumber.getCheckDigit("807159215")).isEqualTo(3); + assertThat(HungarianIdNumber.getCheckDigit("100000000")).isEqualTo(1); + assertThat(HungarianIdNumber.getCheckDigit("010000000")).isEqualTo(2); + assertThat(HungarianIdNumber.getCheckDigit("001000000")).isEqualTo(3); + assertThat(HungarianIdNumber.getCheckDigit("000000001")).isEqualTo(9); + assertThat(HungarianIdNumber.getCheckDigit("170010103")).isEqualTo(10); + } +} diff --git a/src/test/java/net/datafaker/providers/base/IdNumberTest.java b/src/test/java/net/datafaker/providers/base/IdNumberTest.java index 020d79bf4..e011479a7 100644 --- a/src/test/java/net/datafaker/providers/base/IdNumberTest.java +++ b/src/test/java/net/datafaker/providers/base/IdNumberTest.java @@ -34,6 +34,7 @@ class IdNumberTest extends BaseFakerTest { private static final Faker UKRAINIAN = new Faker(new Locale("uk", "UA")); private static final Faker FRENCH = new Faker(new Locale("fr", "FR")); private static final Faker ITALIAN = new Faker(new Locale("it", "IT")); + private static final Faker HUNGARIAN = new Faker(new Locale("hu", "HU")); @Test void testValid() { @@ -235,6 +236,16 @@ void italianIdNumber() { assertThatPin(ITALIAN.idNumber().valid()).matches(IdNumberPatterns.ITALIAN); } + @RepeatedTest(100) + void hungarianIdNumber_valid() { + assertThatPin(HUNGARIAN.idNumber().valid()).matches(IdNumberPatterns.HUNGARIAN); + } + + @RepeatedTest(100) + void hungarianIdNumber_invalid() { + assertThatPin(HUNGARIAN.idNumber().invalid()).matches(IdNumberPatterns.HUNGARIAN); + } + private static AbstractStringAssert assertThatPin(String pin) { return assertThat(pin) .as(() -> "PIN: %s".formatted(pin));