org.hibernate.beanvalidation.tck.tests.constraints.constraintcomposition.ConstraintCompositionTest Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of beanvalidation-tck-tests Show documentation
Show all versions of beanvalidation-tck-tests Show documentation
Jakarta Bean Validation TCK test suite
/**
* Jakarta Bean Validation TCK
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or .
*/
package org.hibernate.beanvalidation.tck.tests.constraints.constraintcomposition;
import static org.hibernate.beanvalidation.tck.util.ConstraintViolationAssert.assertNoViolations;
import static org.hibernate.beanvalidation.tck.util.ConstraintViolationAssert.assertThat;
import static org.hibernate.beanvalidation.tck.util.ConstraintViolationAssert.violationOf;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import jakarta.validation.ConstraintDeclarationException;
import jakarta.validation.ConstraintDefinitionException;
import jakarta.validation.ConstraintTarget;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Payload;
import jakarta.validation.UnexpectedTypeException;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import jakarta.validation.groups.Default;
import jakarta.validation.metadata.BeanDescriptor;
import jakarta.validation.metadata.ConstraintDescriptor;
import org.hibernate.beanvalidation.tck.beanvalidation.Sections;
import org.hibernate.beanvalidation.tck.tests.AbstractTCKTest;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.jboss.test.audit.annotations.SpecAssertion;
import org.jboss.test.audit.annotations.SpecVersion;
import org.testng.annotations.Test;
/**
* Tests for composing constraints.
*
* @author Hardy Ferentschik
* @author Guillaume Smet
*/
@SpecVersion(spec = "beanvalidation", version = "3.0.0")
public class ConstraintCompositionTest extends AbstractTCKTest {
@Deployment
public static WebArchive createTestArchive() {
return webArchiveBuilder()
.withTestClassPackage( ConstraintCompositionTest.class )
.build();
}
@Test
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "a")
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "q")
public void testComposedConstraints() {
FrenchAddress address = getFrenchAddressWithoutZipCode();
Set> constraintViolations = getValidator().validate( address );
assertThat( constraintViolations ).containsOnlyViolations(
violationOf( NotNull.class )
.withMessage( "may not be null" )
.withRootBeanClass( FrenchAddress.class )
.withInvalidValue( null )
.withProperty( "zipCode" )
);
}
@Test
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "a")
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "q")
public void testComposedConstraintsAreRecursive() {
GermanAddress address = new GermanAddress();
address.setAddressline1( "Rathausstrasse 5" );
address.setAddressline2( "3ter Stock" );
address.setCity( "Karlsruhe" );
Set> constraintViolations = getValidator().validate( address );
assertThat( constraintViolations ).containsOnlyViolations(
violationOf( GermanZipcode.class )
.withRootBeanClass( GermanAddress.class )
.withInvalidValue( null )
.withProperty( "zipCode" )
);
}
@Test
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "b")
public void testValidationOfMainAnnotationIsAlsoApplied() {
FrenchAddress address = getFrenchAddressWithoutZipCode();
address.setZipCode( "00000" );
Set> constraintViolations = getValidator().validate( address );
assertThat( constraintViolations ).containsOnlyViolations(
violationOf( FrenchZipcode.class ).withMessage( "00000 is a reserved code" )
);
}
@Test
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "c")
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "n")
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "r")
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "s")
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "v")
public void testEachFailingConstraintCreatesConstraintViolation() {
FrenchAddress address = getFrenchAddressWithoutZipCode();
address.setZipCode( "abc" );
Set> constraintViolations = getValidator().validate( address );
assertThat( constraintViolations ).containsOnlyViolations(
violationOf( Pattern.class )
.withRootBeanClass( FrenchAddress.class )
.withProperty( "zipCode" )
.withInvalidValue( "abc" ),
violationOf( Pattern.class )
.withRootBeanClass( FrenchAddress.class )
.withProperty( "zipCode" )
.withInvalidValue( "abc" ),
violationOf( Size.class )
.withRootBeanClass( FrenchAddress.class )
.withProperty( "zipCode" )
.withInvalidValue( "abc" )
);
address.setZipCode( "123" );
constraintViolations = getValidator().validate( address );
assertThat( constraintViolations ).containsOnlyViolations(
violationOf( Pattern.class )
.withRootBeanClass( FrenchAddress.class )
.withProperty( "zipCode" )
.withInvalidValue( "123" ),
violationOf( Size.class )
.withRootBeanClass( FrenchAddress.class )
.withProperty( "zipCode" )
.withInvalidValue( "123" )
);
address.setZipCode( "33023" );
constraintViolations = getValidator().validate( address );
assertNoViolations( constraintViolations );
}
@Test
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "t")
public void testConstraintIndexWithListContainer() {
FrenchAddressListContainer address = getFrenchAddressListContainerWithoutZipCode();
address.setZipCode( "abc" );
Set> constraintViolations = getValidator().validate( address );
assertThat( constraintViolations ).containsOnlyViolations(
violationOf( Pattern.class )
.withRootBeanClass( FrenchAddressListContainer.class )
.withProperty( "zipCode" )
.withInvalidValue( "abc" ),
violationOf( Pattern.class )
.withRootBeanClass( FrenchAddressListContainer.class )
.withProperty( "zipCode" )
.withInvalidValue( "abc" ),
violationOf( Size.class )
.withRootBeanClass( FrenchAddressListContainer.class )
.withProperty( "zipCode" )
.withInvalidValue( "abc" )
);
address.setZipCode( "33023" );
constraintViolations = getValidator().validate( address );
assertNoViolations( constraintViolations );
}
@Test(expectedExceptions = { ConstraintDeclarationException.class })
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "u")
public void testConstraintIndexWithMixDirectAnnotationAndListContainer() {
FrenchAddressMixDirectAnnotationAndListContainer address = getFrenchAddressMixDirectAnnotationAndListContainerWithoutZipCode();
address.setZipCode( "abc" );
getValidator().validate( address );
}
@Test
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "d")
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "e")
public void testGroupsDefinedOnMainAnnotationAreInherited() {
FrenchAddress address = getFrenchAddressWithoutZipCode();
Set> constraintViolations = getValidator().validate( address );
assertThat( constraintViolations ).containsOnlyViolations(
violationOf( NotNull.class )
);
ConstraintViolation constraintViolation = constraintViolations.iterator().next();
NotNull notNull = (NotNull) constraintViolation.getConstraintDescriptor().getAnnotation();
List> groups = Arrays.asList( notNull.groups() );
assertTrue( groups.size() == 2, "There should be two groups" );
assertTrue( groups.contains( Default.class ), "The default group should be in the list." );
assertTrue(
groups.contains( FrenchAddress.FullAddressCheck.class ),
"The FrenchAddress.FullAddressCheck group should be inherited."
);
}
@Test
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "l")
public void testOnlySingleConstraintViolation() {
GermanAddress address = new GermanAddress();
address.setAddressline1( "Rathausstrasse 5" );
address.setAddressline2( "3ter Stock" );
address.setCity( "Karlsruhe" );
address.setZipCode( "abc" );
// actually three composing constraints fail, but due to @ReportAsSingleViolation only one will be reported.
Set> constraintViolations = getValidator().validate( address );
assertThat( constraintViolations ).containsOnlyViolations(
violationOf( GermanZipcode.class )
.withRootBeanClass( GermanAddress.class )
.withProperty( "zipCode" )
.withInvalidValue( "abc" )
);
}
@Test
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "m")
public void testAttributesDefinedOnComposingConstraints() {
BeanDescriptor descriptor = getValidator().getConstraintsForClass( FrenchAddress.class );
Set> constraintDescriptors = descriptor.getConstraintsForProperty( "zipCode" )
.getConstraintDescriptors();
boolean findPattern = checkForAppropriateAnnotation( constraintDescriptors );
assertTrue( findPattern, "Could not find @Pattern in composing constraints" );
}
private boolean checkForAppropriateAnnotation(Set> constraintDescriptors) {
boolean findPattern = false;
for ( ConstraintDescriptor> constraintDescriptor : constraintDescriptors ) {
Annotation ann = constraintDescriptor.getAnnotation();
if ( Pattern.class.getName().equals( ann.annotationType().getName() ) ) {
String regexp = ( (Pattern) ann ).regexp();
if ( regexp.equals( "bar" ) ) {
fail( "The regular expression attributes are defined in the composing constraint." );
}
findPattern = true;
}
findPattern |= checkForAppropriateAnnotation( constraintDescriptor.getComposingConstraints() );
}
return findPattern;
}
@Test(expectedExceptions = ConstraintDefinitionException.class)
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "p")
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "w")
public void testOverriddenAttributesMustMatchInType() {
getValidator().validate( new DummyEntityWithZipCode( "foobar" ) );
}
@Test(expectedExceptions = UnexpectedTypeException.class)
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "j")
public void testAllComposingConstraintsMustBeApplicableToAnnotatedType() {
getValidator().validate( new Shoe( 41 ) );
}
@Test
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "f")
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "g")
public void testPayloadPropagationInComposedConstraints() {
Friend john = new Friend( "John", "Doe" );
Set> constraintViolations = getValidator().validate( john );
assertThat( constraintViolations ).containsOnlyViolations(
violationOf( NotNull.class )
);
ConstraintViolation constraintViolation = constraintViolations.iterator().next();
Set> payloads = constraintViolation.getConstraintDescriptor().getPayload();
assertTrue( payloads.size() == 1, "There should be one payload in the set" );
Class extends Payload> payload = payloads.iterator().next();
assertTrue( payload.getName().equals( Severity.Warn.class.getName() ), "Unexpected payload" );
}
@Test
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "h")
@SpecAssertion(section = Sections.CONSTRAINTSDEFINITIONIMPLEMENTATION_CONSTRAINTCOMPOSITION, id = "i")
public void testConstraintTargetPropagationInComposedConstraints() throws Exception {
Object object = new DummyEntityWithGenericAndCrossParameterConstraint();
Method method = DummyEntityWithGenericAndCrossParameterConstraint.class.getMethod( "doSomething", int.class );
Object[] parameterValues = new Object[] { 0 };
Set> constraintViolations = getExecutableValidator().validateParameters(
object,
method,
parameterValues
);
//The composing constraint is expected to fail
assertThat( constraintViolations ).containsOnlyViolations(
violationOf( GenericAndCrossParameterConstraint.class )
);
//and it should inherit the constraint target from the composed constraint
ConstraintViolation