Skip to content
Open
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
43 changes: 43 additions & 0 deletions src/main/java/net/datafaker/idnumbers/SpanishIdNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package net.datafaker.idnumbers;

import net.datafaker.providers.base.BaseProviders;
import net.datafaker.providers.base.IdNumber.IdNumberRequest;
import net.datafaker.providers.base.PersonIdNumber;

import static net.datafaker.idnumbers.Utils.birthday;
import static net.datafaker.idnumbers.Utils.gender;

/**
* Spanish national identity number (DNI/NIF).
* See <a href="https://www.interior.gob.es/opencms/es/servicios-al-ciudadano/tramites-y-gestiones/dni/calculo-del-digito-de-control-del-nif-nie/">
* Calculation of the NIF/NIE check character</a>.
*/
public class SpanishIdNumber implements IdNumberGenerator {
private static final String CHECK_LETTERS = "TRWAGMYFPDXBNJZSQVHLCKE";

@Override
public String countryCode() {
return "ES";
}

@Override
public PersonIdNumber generateValid(BaseProviders faker, IdNumberRequest request) {
String digits = faker.number().digits(8);
String idNumber = digits + checksum(digits);
return new PersonIdNumber(idNumber, birthday(faker, request), gender(faker, request));
}

@Override
public String generateInvalid(BaseProviders faker) {
String digits = faker.number().digits(8);
char validLetter = checksum(digits);
int validLetterIndex = CHECK_LETTERS.indexOf(validLetter);
char invalidLetter = CHECK_LETTERS.charAt((validLetterIndex + 1) % CHECK_LETTERS.length());
return digits + invalidLetter;
}

static char checksum(String digits) {
int number = Integer.parseInt(digits);
return CHECK_LETTERS.charAt(number % CHECK_LETTERS.length());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ net.datafaker.idnumbers.RomanianIdNumber
net.datafaker.idnumbers.SingaporeIdNumber
net.datafaker.idnumbers.SouthAfricanIdNumber
net.datafaker.idnumbers.SouthKoreanIdNumber
net.datafaker.idnumbers.SpanishIdNumber
net.datafaker.idnumbers.SwedenIdNumber
net.datafaker.idnumbers.UkrainianIdNumber
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 @@ -15,5 +15,6 @@ public class IdNumberPatterns {
public static final Pattern ESTONIAN = Pattern.compile("[1-6][0-9]{10}");
public static final Pattern BRAZILIAN = Pattern.compile("\\d{3}\\.\\d{3}\\.\\d{3}-\\d{2}");
public static final Pattern NORWEGIAN = Pattern.compile("\\d{11}");
public static final Pattern SPANISH = Pattern.compile("\\d{8}[TRWAGMYFPDXBNJZSQVHLCKE]");

}
45 changes: 45 additions & 0 deletions src/test/java/net/datafaker/idnumbers/SpanishIdNumberTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package net.datafaker.idnumbers;

import net.datafaker.Faker;
import net.datafaker.helpers.IdNumberPatterns;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

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

class SpanishIdNumberTest {
private final SpanishIdNumber generator = new SpanishIdNumber();
private final Faker faker = new Faker();

@ParameterizedTest
@CsvSource({
"00000000, T",
"00000001, R",
"12345678, Z",
"99999999, R",
})
void checksum(String digits, char expectedLetter) {
assertThat(SpanishIdNumber.checksum(digits)).isEqualTo(expectedLetter);
}

@RepeatedTest(100)
void valid() {
String generated = generator.generateValid(faker);

assertThat(generated).matches(IdNumberPatterns.SPANISH);
assertThat(generated.charAt(8))
.as("DNI check letter")
.isEqualTo(SpanishIdNumber.checksum(generated.substring(0, 8)));
}

@RepeatedTest(100)
void invalid() {
String generated = generator.generateInvalid(faker);

assertThat(generated).matches(IdNumberPatterns.SPANISH);
assertThat(generated.charAt(8))
.as("DNI check letter should be invalid")
.isNotEqualTo(SpanishIdNumber.checksum(generated.substring(0, 8)));
}
}
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 @@ -42,6 +42,7 @@ class IdNumberTest {
private static final Faker HUNGARIAN = new Faker(new Locale("hu", "HU"));
private static final Faker BRAZILIAN = new Faker(new Locale("pt", "BR"));
private static final Faker NORWEGIAN = new Faker(new Locale("no", "NO"));
private static final Faker SPANISH = new Faker(new Locale("es", "ES"));

@Test
void testValid() {
Expand Down Expand Up @@ -278,6 +279,16 @@ void norwegianIdNumber_invalid() {
assertThatPin(NORWEGIAN.idNumber().invalid()).matches(IdNumberPatterns.NORWEGIAN);
}

@RepeatedTest(100)
void spanishIdNumber_valid() {
assertThatPin(SPANISH.idNumber().valid()).matches(IdNumberPatterns.SPANISH);
}

@RepeatedTest(100)
void spanishIdNumber_invalid() {
assertThatPin(SPANISH.idNumber().invalid()).matches(IdNumberPatterns.SPANISH);
}

private static AbstractStringAssert<?> assertThatPin(String pin) {
return assertThat(pin)
.as(() -> "PIN: %s".formatted(pin));
Expand Down