Skip to content

Commit

Permalink
Merge 1a2de81 into 33f96e1
Browse files Browse the repository at this point in the history
  • Loading branch information
MarceloLeite2604 committed Aug 23, 2019
2 parents 33f96e1 + 1a2de81 commit 86ba8b6
Show file tree
Hide file tree
Showing 3 changed files with 321 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -67,6 +67,7 @@ Fakers
* Beer
* Book
* Bool
* Brazilian CPF identifier
* Business
* ChuckNorris
* Cat
Expand Down
205 changes: 205 additions & 0 deletions src/main/java/com/github/javafaker/idnumbers/BrCpfIdNumber.java
@@ -0,0 +1,205 @@
package com.github.javafaker.idnumbers;

import java.util.Arrays;
import java.util.regex.Pattern;

import org.apache.commons.lang3.ArrayUtils;

import com.github.javafaker.Faker;

/**
* Generate both valid and invalid Brazilian CPF identification numbers.
*
* For more information about CPF please check
* https://en.wikipedia.org/wiki/Cadastro_de_Pessoas_F%C3%ADsicas
*
* The validation numbers algorithm was implemented following instructions
* provided by the Brazilian portuguese Wikipedia page at
* https://pt.wikipedia.org/wiki/Cadastro_de_pessoas_f%C3%ADsicas#Algoritmo
*
* @author MarceloLeite2604
* @author EullerLisowski
*
*/
public class BrCpfIdNumber {

private static final int INPUT_DIGITS_LENGTH = 9;

private static final int VERIFIER_DIGITS_LENGTH = 2;

private static final int CPF_DIGITS_LENGTH = INPUT_DIGITS_LENGTH + VERIFIER_DIGITS_LENGTH;

private static final String CPF_FORMAT_PATTERN = "###.###.###-##";

protected static final String FORMATTED_CPF_REGEX_PATTERN = "^\\d{3}\\.\\d{3}\\.\\d{3}-\\d{2}$";

static final Pattern FORMATTED_CPF_PATTERN = Pattern.compile(FORMATTED_CPF_REGEX_PATTERN);

protected static final String UNFORMATTED_CPF_REGEX_PATTERN = "^\\d{11}$";

static final Pattern UNFORMATTED_CPF_PATTERN = Pattern.compile(UNFORMATTED_CPF_REGEX_PATTERN);

public String getValidFormattedCpf(Faker faker) {

int[] cpfDigits = createCpfDigits(faker);

return convertAsFormattedString(cpfDigits);
}

public String getValidUnformattedCpf(Faker faker) {

int[] cpfDigits = createCpfDigits(faker);

return convertAsUnformattedString(cpfDigits);
}

public String getInvalidFormattedCpf(Faker faker) {

int[] cpfDigits = createInvalidCpfDigits(faker);

return convertAsFormattedString(cpfDigits);
}

public String getInvalidUnformattedCpf(Faker faker) {

int[] cpfDigits = createInvalidCpfDigits(faker);

return convertAsUnformattedString(cpfDigits);
}

private int[] createCpfDigits(Faker faker) {
int[] inputDigits = createInputDigits(faker);

int[] verifierDigits = calculateVerifierDigits(inputDigits);

return ArrayUtils.addAll(inputDigits, verifierDigits);
}

private int[] createInvalidCpfDigits(Faker faker) {
int[] inputDigits = createInputDigits(faker);

int[] verifierDigits = calculateInvalidVerifierDigits(inputDigits, faker);

return ArrayUtils.addAll(inputDigits, verifierDigits);
}

protected boolean isValid(String cpf) {

if (!isFormatted(cpf) && !isUnformatted(cpf)) {
return false;
}

int[] cpfDigits = convertAsIntegerArray(cpf);

return isValid(cpfDigits);
}

private int[] convertAsIntegerArray(String cpf) {
char[] cpfChars = cpf.toCharArray();
int[] result = new int[CPF_DIGITS_LENGTH];
int index = 0;

for (char cpfChar : cpfChars) {
if (Character.isDigit(cpfChar)) {
result[index++] = Character.getNumericValue(cpfChar);
}
}

return result;
}

private boolean isFormatted(String cpf) {
return FORMATTED_CPF_PATTERN.matcher(cpf).matches();
}

private boolean isUnformatted(String cpf) {
return UNFORMATTED_CPF_PATTERN.matcher(cpf).matches();
}

private int[] calculateInvalidVerifierDigits(int[] inputDigits, Faker faker) {
int[] verifierDigits = calculateVerifierDigits(inputDigits);

for (int index = 0; index < verifierDigits.length; index++) {
verifierDigits[index] = retrieveRandomIntDifferentFrom(verifierDigits[index], faker);
}

return verifierDigits;
}

private int retrieveRandomIntDifferentFrom(int integer, Faker faker) {
int result;

do {
result = retrieveRandomDigit(faker);
} while (result == integer);

return result;
}

private String convertAsFormattedString(int[] cpfDigits) {
String cpf = CPF_FORMAT_PATTERN;

for (int cpfDigit : cpfDigits) {
cpf = cpf.replaceFirst("#", Integer.toString(cpfDigit));
}
return cpf;
}

private String convertAsUnformattedString(int[] cpfDigits) {
StringBuilder cpfStringBuilder = new StringBuilder();

for (int cpfDigit : cpfDigits) {
cpfStringBuilder.append(cpfDigit);
}

return cpfStringBuilder.toString();
}

private int[] calculateVerifierDigits(int[] inputDigits) {

int[] invertedInputDigits = Arrays.copyOf(inputDigits, inputDigits.length);

ArrayUtils.reverse(invertedInputDigits);

int[] verifierDigits = new int[VERIFIER_DIGITS_LENGTH];

for (int index = 0; index < invertedInputDigits.length; index++) {
verifierDigits[0] += invertedInputDigits[index] * (9 - (index % 10));
verifierDigits[1] += invertedInputDigits[index] * (9 - ((index + 1) % 10));
}

verifierDigits[0] = (verifierDigits[0] % 11) % 10;

verifierDigits[1] += verifierDigits[0] * 9;
verifierDigits[1] = (verifierDigits[1] % 11) % 10;

return verifierDigits;
}

private boolean isValid(int[] cpfDigits) {
int[] inputDigits = retrieveInputDigits(cpfDigits);

int[] cpfVerifierDigits = Arrays.copyOfRange(cpfDigits, INPUT_DIGITS_LENGTH,
INPUT_DIGITS_LENGTH + VERIFIER_DIGITS_LENGTH);

int[] calculatedVerifierDigits = calculateVerifierDigits(inputDigits);

return Arrays.equals(cpfVerifierDigits, calculatedVerifierDigits);
}

private int[] retrieveInputDigits(int[] cpfDigits) {
return Arrays.copyOfRange(cpfDigits, 0, INPUT_DIGITS_LENGTH);
}

private int[] createInputDigits(Faker faker) {
int[] inputDigits = new int[INPUT_DIGITS_LENGTH];
for (int index = 0; index < inputDigits.length; index++) {
inputDigits[index] = retrieveRandomDigit(faker);
}
return inputDigits;
}

private int retrieveRandomDigit(Faker faker) {
return faker.random().nextInt(10);
}
}
115 changes: 115 additions & 0 deletions src/test/java/com/github/javafaker/idnumbers/BrCpfIdNumberTest.java
@@ -0,0 +1,115 @@
package com.github.javafaker.idnumbers;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Before;
import org.junit.Test;

import com.github.javafaker.AbstractFakerTest;

public class BrCpfIdNumberTest extends AbstractFakerTest {

private BrCpfIdNumber brCpfIdNumber;

@Before
public void setUp() {
brCpfIdNumber = new BrCpfIdNumber();
}

@Test
public void testGetValidFormattedCpf() throws Exception {
String cpf = brCpfIdNumber.getValidFormattedCpf(faker);
assertTrue(BrCpfIdNumber.FORMATTED_CPF_PATTERN.matcher(cpf).matches());
}

@Test
public void testGetValidUnformattedCpf() throws Exception {
String cpf = brCpfIdNumber.getValidUnformattedCpf(faker);
assertTrue(BrCpfIdNumber.UNFORMATTED_CPF_PATTERN.matcher(cpf).matches());
}

@Test
public void testGetInvalidFormattedCpf() throws Exception {
String cpf = brCpfIdNumber.getInvalidFormattedCpf(faker);
assertTrue(BrCpfIdNumber.FORMATTED_CPF_PATTERN.matcher(cpf).matches());
}

@Test
public void testGetInvalidUnformattedCpf() throws Exception {
String cpf = brCpfIdNumber.getInvalidUnformattedCpf(faker);
assertTrue(BrCpfIdNumber.UNFORMATTED_CPF_PATTERN.matcher(cpf).matches());
}

@Test
public void testIsValidShouldReturnTrueForValidFormattedCpfStartingWithZero() throws Exception {
String cpf = "065.154.070-41";
assertTrue(brCpfIdNumber.isValid(cpf));
}

@Test
public void testIsValidShouldReturnTrueForValidUnformattedCpfStartingWithZero() throws Exception {
String cpf = "04893747002";
assertTrue(brCpfIdNumber.isValid(cpf));
}

@Test
public void testIsValidShouldReturnFalseForInvalidFormattedCpfStartingWithZero() throws Exception {
String cpf = "099.972.740-59";
assertFalse(brCpfIdNumber.isValid(cpf));
}

@Test
public void testIsValidShouldReturnFalseForInvalidUnformattedCpfStartingWithZero() throws Exception {
String cpf = "03360109025";
assertFalse(brCpfIdNumber.isValid(cpf));
}

@Test
public void testIsValidShouldReturnTrueForValidFormattedCpfStartingWithGreaterThanZero() throws Exception {
String cpf = "919.766.290-98";
assertTrue(brCpfIdNumber.isValid(cpf));
}

@Test
public void testIsValidShouldReturnTrueForValidUnformattedCpfStartingWithGreaterThanZero() throws Exception {
String cpf = "49764225004";
assertTrue(brCpfIdNumber.isValid(cpf));
}

@Test
public void testIsValidShouldReturnFalseForInvalidFormattedCpfStartingWithGreaterThanZero() throws Exception {
String cpf = "144.970.180-88";
assertFalse(brCpfIdNumber.isValid(cpf));
}

@Test
public void testIsValidShouldReturnFalseForInvalidUnformattedCpfStartingWithGreaterThanZero() throws Exception {
String cpf = "56803652090";
assertFalse(brCpfIdNumber.isValid(cpf));
}

@Test
public void testGetValidFormattedCpfShouldReturnValidFormattedCpf() throws Exception {
String cpf = brCpfIdNumber.getValidFormattedCpf(faker);
assertTrue(brCpfIdNumber.isValid(cpf));
}

@Test
public void testGetInvalidFormattedCpfShouldReturnInvalidFormattedCpf() throws Exception {
String cpf = brCpfIdNumber.getInvalidFormattedCpf(faker);
assertFalse(brCpfIdNumber.isValid(cpf));
}

@Test
public void testGetValidUnformattedCpfShouldReturnValidFormattedCpf() throws Exception {
String cpf = brCpfIdNumber.getValidUnformattedCpf(faker);
assertTrue(brCpfIdNumber.isValid(cpf));
}

@Test
public void testGetInvalidUnformattedCpfShouldReturnInvalidFormattedCpf() throws Exception {
String cpf = brCpfIdNumber.getInvalidUnformattedCpf(faker);
assertFalse(brCpfIdNumber.isValid(cpf));
}
}

0 comments on commit 86ba8b6

Please sign in to comment.