/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package org.hibernate.validator.test.internal.engine;
import static org.hibernate.validator.testutil.ConstraintViolationAssert.assertCorrectConstraintTypes;
import static org.hibernate.validator.testutil.ConstraintViolationAssert.assertCorrectPropertyPaths;
import static org.hibernate.validator.testutil.ConstraintViolationAssert.assertNumberOfViolations;
import static org.hibernate.validator.testutils.ValidatorUtil.getValidator;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.GroupSequence;
import javax.validation.Valid;
import javax.validation.ValidationException;
import javax.validation.Validator;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.executable.ExecutableValidator;
import javax.validation.metadata.BeanDescriptor;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.internal.engine.ValidatorImpl;
import org.hibernate.validator.testutil.CountValidationCalls;
import org.hibernate.validator.testutil.CountValidationCallsValidator;
import org.hibernate.validator.testutil.TestForIssue;
import org.testng.annotations.Test;
/**
* @author Hardy Ferentschik
* @author Kevin Pollet <kevin.pollet@serli.com> (C) 2011 SERLI
* @author Guillaume Smet
*/
public class ValidatorTest {
@Test
@TestForIssue(jiraKey = "HV-429")
public void testValidatePropertyWithRedefinedDefaultGroupOnMainEntity() {
Validator validator = getValidator();
A testInstance = new A();
testInstance.c = new C( "aaa" );
Set<ConstraintViolation<A>> constraintViolations = validator.validateProperty( testInstance, "c.id" );
assertNumberOfViolations( constraintViolations, 1 );
assertCorrectPropertyPaths( constraintViolations, "c.id" );
}
@Test
@TestForIssue(jiraKey = "HV-429")
public void testValidatePropertyWithRedefinedDefaultGroupOnSuperClass() {
Validator validator = getValidator();
A testInstance = new A();
testInstance.d = new D( "aa" );
Set<ConstraintViolation<A>> constraintViolations = validator.validateProperty( testInstance, "d.e" );
assertNumberOfViolations( constraintViolations, 1 );
assertCorrectPropertyPaths( constraintViolations, "d.e" );
}
@Test
@TestForIssue(jiraKey = "HV-429")
public void testValidateValueWithRedefinedDefaultGroupOnMainEntity() {
Validator validator = getValidator();
Set<ConstraintViolation<A>> constraintViolations = validator.validateValue( A.class, "c.id", "aaa" );
assertNumberOfViolations( constraintViolations, 1 );
assertCorrectPropertyPaths( constraintViolations, "c.id" );
}
@Test
@TestForIssue(jiraKey = "HV-429")
public void testValidateValueWithRedefinedDefaultGroupOnSuperClass() {
Validator validator = getValidator();
Set<ConstraintViolation<A>> constraintViolations = validator.validateValue( A.class, "d.e", "aa" );
assertNumberOfViolations( constraintViolations, 1 );
assertCorrectPropertyPaths( constraintViolations, "d.e" );
}
@Test
@TestForIssue(jiraKey = "HV-376")
public void testValidatePropertyWithCurrencySymbol() {
Validator validator = getValidator();
Ticket testInstance = new Ticket();
Set<ConstraintViolation<Ticket>> constraintViolations = validator.validateProperty( testInstance, "€price" );
assertNumberOfViolations( constraintViolations, 1 );
}
@Test
@TestForIssue(jiraKey = "HV-376")
public void testValidateValueWithCurrencySymbol() {
Validator validator = getValidator();
Ticket testInstance = new Ticket();
Set<ConstraintViolation<Ticket>> constraintViolations = validator.validateValue(
Ticket.class, "€price", testInstance.€price
);
assertNumberOfViolations( constraintViolations, 1 );
}
@Test
@TestForIssue(jiraKey = "HV-208")
public void testPropertyPathDoesNotStartWithLeadingDot() {
Validator validator = getValidator();
A testInstance = new A();
Set<ConstraintViolation<A>> constraintViolations = validator.validate( testInstance );
assertNumberOfViolations( constraintViolations, 1 );
assertCorrectPropertyPaths( constraintViolations, "b" );
}
@Test
public void testIsBeanConstrained() {
Validator validator = getValidator();
BeanDescriptor beanDescriptor = validator.getConstraintsForClass( B.class );
assertTrue( beanDescriptor.isBeanConstrained() );
}
@Test
@TestForIssue(jiraKey = "HV-466")
public void testValidateInterfaceConstraintsAreValidatedOneTime() {
CountValidationCallsValidator.init();
Set<ConstraintViolation<H>> constraintViolations = getValidator().validate( new H() );
assertNumberOfViolations( constraintViolations, 0 );
assertEquals( CountValidationCallsValidator.getNumberOfValidationCall(), 2 );
}
@Test
@TestForIssue(jiraKey = "HV-466")
public void testValidatePropertyInterfaceConstraintsAreValidatedOneTime() {
CountValidationCallsValidator.init();
Set<ConstraintViolation<H>> constraintViolations = getValidator().validateProperty( new H(), "foo" );
assertNumberOfViolations( constraintViolations, 0 );
assertEquals( CountValidationCallsValidator.getNumberOfValidationCall(), 1 );
}
@Test
@TestForIssue(jiraKey = "HV-466")
public void testValidateValueInterfaceConstraintsAreValidatedOneTime() {
CountValidationCallsValidator.init();
Set<ConstraintViolation<H>> constraintViolations = getValidator().validateValue( H.class, "foo", null );
assertNumberOfViolations( constraintViolations, 0 );
assertEquals( CountValidationCallsValidator.getNumberOfValidationCall(), 1 );
}
@Test
@TestForIssue(jiraKey = "HV-468")
public void testPropertyPath() {
Validator validator = getValidator();
Foo foo = new Foo();
Set<ConstraintViolation<Foo>> constraintViolations = validator.validate( foo );
assertNumberOfViolations( constraintViolations, 1 );
assertCorrectPropertyPaths( constraintViolations, "bar[0].alwaysNull" );
}
@Test
public void testConstraintDefinedOnEntityNotFollowingBeanNotation() {
CountValidationCallsValidator.init();
Set<ConstraintViolation<NotFollowingJavaBeanNotation>> constraintViolations = getValidator().validate( new NotFollowingJavaBeanNotation() );
// validating the whole entity
assertNumberOfViolations( constraintViolations, 1 );
assertCorrectConstraintTypes( constraintViolations, NotNull.class );
// using validateProperty (which is used by JSF) to validate explicitly
constraintViolations = getValidator().validateProperty( new NotFollowingJavaBeanNotation(), "m_foo" );
assertNumberOfViolations( constraintViolations, 1 );
assertCorrectConstraintTypes( constraintViolations, NotNull.class );
// using validateProperty (which is used by JSF) to validate explicitly (no violation, because there is no
// property foo Validator knows about
constraintViolations = getValidator().validateProperty( new NotFollowingJavaBeanNotation(), "foo" );
assertNumberOfViolations( constraintViolations, 0 );
}
@Test(expectedExceptions = ValidationException.class)
public void testUnwrapToImplementationCausesValidationException() {
Validator validator = getValidator();
validator.unwrap( ValidatorImpl.class );
}
@Test(expectedExceptions = ValidationException.class)
public void testUnwrapToExecutableValidatorCausesValidationException() {
Validator validator = getValidator();
validator.unwrap( ExecutableValidator.class );
}
@Test
public void testUnwrapToPublicTypesSucceeds() {
Validator validator = getValidator();
Validator asValidator = validator.unwrap( Validator.class );
assertSame( asValidator, validator );
Object asObject = validator.unwrap( Object.class );
assertSame( asObject, validator );
}
@Test
@TestForIssue(jiraKey = "HV-596")
public void testValidateValueWithNestedPath() {
Validator validator = getValidator();
Set<ConstraintViolation<X>> constraintViolations = validator.validateValue( X.class, "list[0].foo", null );
assertNumberOfViolations( constraintViolations, 1 );
assertCorrectPropertyPaths( constraintViolations, "list[0].foo" );
Set<ConstraintViolation<K>> constraintViolationsK = validator.validateValue( K.class, "foo.bar", null );
assertNumberOfViolations( constraintViolationsK, 1 );
assertCorrectPropertyPaths( constraintViolationsK, "foo.bar" );
}
@Test
@TestForIssue(jiraKey = "HV-1002")
public void testValidatePropertyWithNestedPath() {
Validator validator = getValidator();
X someX = new X();
someX.addZ( new Z() );
Set<ConstraintViolation<X>> constraintViolationsX = validator.validateProperty( someX, "list[0].foo" );
assertNumberOfViolations( constraintViolationsX, 1 );
assertCorrectPropertyPaths( constraintViolationsX, "list[0].foo" );
I someI = new I();
someI.putJ( "bar", new J() );
Set<ConstraintViolation<I>> constraintViolationsI = validator.validateProperty( someI, "map[bar].foo" );
assertNumberOfViolations( constraintViolationsI, 1 );
assertCorrectPropertyPaths( constraintViolationsI, "map[bar].foo" );
K someK = new K();
someK.foo = new L<String>();
Set<ConstraintViolation<K>> constraintViolationsK = validator.validateProperty( someK, "foo.bar" );
assertNumberOfViolations( constraintViolationsK, 1 );
assertCorrectPropertyPaths( constraintViolationsK, "foo.bar" );
constraintViolationsK = validator.validateProperty( someK, "foo.genericProperty" );
assertNumberOfViolations( constraintViolationsK, 1 );
assertCorrectPropertyPaths( constraintViolationsK, "foo.genericProperty" );
}
@Test(expectedExceptions = { ValidationException.class }, expectedExceptionsMessageRegExp = "^HV000195:.*")
@TestForIssue(jiraKey = "HV-1002")
public void testValidatePropertyWithNestedPathAndNullPropertyInTheWay() {
Validator validator = getValidator();
X someX = new X();
validator.validateProperty( someX, "list[0].foo" );
}
@Test(expectedExceptions = { IllegalArgumentException.class }, expectedExceptionsMessageRegExp = "^HV000039:.*")
@TestForIssue(jiraKey = "HV-1002")
public void testValidatePropertyWithNestedPathAndMissingValid() {
Validator validator = getValidator();
M someM = new M();
validator.validateProperty( someM, "foo.baz" );
}
class A {
@NotNull
String b;
@Valid
C c;
@Valid
D d;
}
class B {
private boolean b;
@AssertTrue
public boolean hasB() {
return b;
}
}
@GroupSequence({ TestGroup.class, C.class })
class C {
@Pattern(regexp = "[0-9]+", groups = TestGroup.class)
@Length(min = 2)
String id;
C(String id) {
this.id = id;
}
}
@GroupSequence({ TestGroup.class, E.class })
class E {
String e;
E(String e) {
this.e = e;
}
@Pattern(regexp = "[0-9]+", groups = TestGroup.class)
public String getE() {
return e;
}
}
class D extends E {
D(String e) {
super( e );
}
@Override
@Length(min = 2)
public String getE() {
return super.getE();
}
}
class Ticket {
@NotNull
Float €price;
}
interface TestGroup {
}
interface F {
@CountValidationCalls
String getFoo();
@CountValidationCalls
String getBar();
}
class G implements F {
@Override
public String getFoo() {
return null;
}
@Override
public String getBar() {
return null;
}
}
class H extends G implements F {
}
class Foo {
@Valid
private final Collection<Bar> bar;
public Foo() {
bar = new ArrayList<Bar>();
bar.add( new Bar() );
}
}
class Bar {
@NotNull
String alwaysNull;
}
class NotFollowingJavaBeanNotation {
@NotNull
String m_foo;
public String getFoo() {
return m_foo;
}
}
class I {
@Valid
Map<String, J> map = new HashMap<String, J>();
public void putJ(String key, J j) {
map.put( key, j );
}
}
class J {
@NotNull
String foo;
}
class K {
@Valid
L<String> foo;
}
class L<T> {
@NotNull
String bar;
@NotNull
T genericProperty;
}
class M {
N foo;
@NotNull
String bar;
}
class N {
@NotNull
String baz;
}
class X {
@Valid
List<Z> list = new ArrayList<Z>();
public void addZ(Z z) {
list.add( z );
}
}
class Z {
@NotNull
String foo;
}
}