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
86 changes: 86 additions & 0 deletions src/main/java/net/datafaker/idnumbers/HungarianIdNumber.java
Original file line number Diff line number Diff line change
@@ -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
* <p>
* The structure of such number is GYYMMDDXXC, whereas
* <ul>
* <li>G indicates century of birth and gender,</li>
* <li>YYMMDD indicates birth year, month and day,</li>
* <li>XX is the serial number, and</li>
* <li>C is a checksum digit.</li>
* </ul>
* <p>
* See <a href="https://en.wikipedia.org/wiki/National_identification_number#Hungary">Hungarian identification number</a>
*/
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;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/test/java/net/datafaker/helpers/IdNumberPatterns.java
Original file line number Diff line number Diff line change
Expand Up @@ -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}");

}
34 changes: 34 additions & 0 deletions src/test/java/net/datafaker/idnumbers/HungarianIdNumberTest.java
Original file line number Diff line number Diff line change
@@ -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);
Comment thread
kingthorin marked this conversation as resolved.
}
}
11 changes: 11 additions & 0 deletions src/test/java/net/datafaker/providers/base/IdNumberTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class IdNumberTest extends BaseFakerTest<BaseFaker> {
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() {
Expand Down Expand Up @@ -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));
Expand Down