package org.hibernate.validator.test.constraints.br; import java.util.Arrays; import java.util.List; import java.util.Set; import javax.validation.ConstraintViolation; import org.testng.annotations.Test; import org.hibernate.validator.constraints.br.CPF; import org.hibernate.validator.internal.util.ModUtil; import org.hibernate.validator.testutil.TestForIssue; import org.hibernate.validator.testutil.ValidatorUtil; import static org.hibernate.validator.testutil.ConstraintViolationAssert.assertNumberOfViolations; import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertTrue; public class Mod11CPFBugTestCase { @Test public void testFailMod11SelfValidation() throws Exception { /* * This issue happens when 2 different digits can be used to grant the same mod result. * The check digit should not be used for validating or it can validate itself, * ie changing only the check digit does not invalidates the value. */ List digits = Arrays.asList( 0, 1 ); assertFalse("'0-1' must be invalid", ModUtil.passesMod11Test( digits, 11 ) ); digits = Arrays.asList( 0, 0, 0, 0, 0, 0, 0 ); assertTrue("'000000-0' must be valid", ModUtil.passesMod11Test( digits, 11 ) ); digits = Arrays.asList( 0, 0, 0, 0, 0, 0, 1 ); assertFalse("'000000-1' must be invalid", ModUtil.passesMod11Test( digits, 11 ) ); digits = Arrays.asList( 3, 3, 1, 8, 1, 4, 2, 9, 6, 5 ); assertFalse("'331814296-5' must be invalid", ModUtil.passesMod11Test( digits, 11 ) ); } @Test public void testCPFBoundaryConditionsForAllSameDigitValidMod11() { String[] invalidCPFs = { "000.000.000-00", "111.111.111-11", "222.222.222-22", "333.333.333-33", "444.444.444-44", "555.555.555-55", "666.666.666-66", "777.777.777-77", "888.888.888-88", "999.999.999-99" }; Set> violations = null; for(String cpf : invalidCPFs){ violations = ValidatorUtil.getValidator().validate( new Person( cpf ) ); assertNumberOfViolations( violations, 1 ); violations = ValidatorUtil.getValidator().validate( new Person( cpf.replaceAll( "[^0-9]", "" ) ) ); assertNumberOfViolations( violations, 1 ); } } @Test public void testCorrectFormattedCPFWithReportAsSingleViolationForCheckDigitSelfValidation() { //Valid CPF Set> violations = ValidatorUtil.getValidator().validate( new Person( "378.796.950-01" ) ); assertNumberOfViolations( violations, 0 ); /* * Invalid CPF reported as valid because of a issue in ModUtil class. * This issue happens when 2 different digits can me used to grant the same mod result. * Check digit must not be used in the validation or can self validate, ie * changing only the check digit does not invalidates the value. */ violations = ValidatorUtil.getValidator().validate( new Person( "378.796.950-02" ) ); assertNumberOfViolations( violations, 1 ); //Valid CPF violations = ValidatorUtil.getValidator().validate( new Person( "331.814.296-43" ) ); assertNumberOfViolations( violations, 0 ); /* * Same as above but in this case both check digits are wrong, * the fist invalid digit affects the result of the sencond mod11 check * and the second can be change too resulting in 3 valid pairs of check digits */ violations = ValidatorUtil.getValidator().validate( new Person( "331.814.296-52" ) ); assertNumberOfViolations( violations, 1 ); violations = ValidatorUtil.getValidator().validate( new Person( "331.814.296-51" ) ); assertNumberOfViolations( violations, 1 ); } public static class Person { @CPF private String cpf; public Person(String cpf) { this.cpf = cpf; } } }