/*
* 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.cascaded;
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.testutil.ConstraintViolationAssert.assertThat;
import static org.hibernate.validator.testutil.ConstraintViolationAssert.pathWith;
import static org.hibernate.validator.testutils.ValidatorUtil.getValidator;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Valid;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.HibernateValidator;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.internal.engine.path.NodeImpl;
import org.hibernate.validator.testutil.TestForIssue;
import org.testng.annotations.Test;
@TestForIssue(jiraKey = "HV-1237")
public class NestedCascadedConstraintsTest {
@Test
public void testNestedValid() {
Validator validator = getValidator();
Set<ConstraintViolation<EmailAddressMap>> constraintViolations = validator.validate( EmailAddressMap.validEmailAddressMap() );
assertNumberOfViolations( constraintViolations, 0 );
constraintViolations = validator.validate( EmailAddressMap.invalidEmailAddressMap() );
assertCorrectPropertyPaths(
constraintViolations,
"map[invalid].<map value>[1].email",
"map[invalid].<map value>[2].email"
);
assertCorrectConstraintTypes( constraintViolations, Email.class, Email.class );
assertThat( constraintViolations ).containsOnlyPaths(
pathWith()
.property( "map" )
.containerElement( NodeImpl.MAP_VALUE_NODE_NAME, true, "invalid", null, Map.class, 1 )
.property( "email", true, null, 1, List.class, 0 ),
pathWith()
.property( "map" )
.containerElement( NodeImpl.MAP_VALUE_NODE_NAME, true, "invalid", null, Map.class, 1 )
.property( "email", true, null, 2, List.class, 0 )
);
}
@Test
public void testMultipleNestedValidWithCustomExtractor() {
Validator validator = Validation.byProvider( HibernateValidator.class )
.configure()
.addValueExtractor( new ReferenceValueExtractor() )
.buildValidatorFactory()
.getValidator();
Set<ConstraintViolation<CinemaEmailAddresses>> constraintViolations = validator.validate( CinemaEmailAddresses.validCinemaEmailAddresses() );
assertNumberOfViolations( constraintViolations, 0 );
CinemaEmailAddresses invalidCinemaEmailAddresses = CinemaEmailAddresses.invalidCinemaEmailAddresses();
constraintViolations = validator.validate( invalidCinemaEmailAddresses );
assertCorrectPropertyPaths(
constraintViolations,
"map[Optional[Cinema<cinema2>]].<map value>[1].email",
"map[Optional[Cinema<cinema2>]].<map value>[2].email",
"map[Optional[Cinema<cinema3>]].<map value>[0].<list element>"
);
assertCorrectConstraintTypes( constraintViolations, Email.class, Email.class, NotNull.class );
assertThat( constraintViolations ).containsOnlyPaths(
pathWith()
.property( "map" )
.containerElement( NodeImpl.MAP_VALUE_NODE_NAME, true, invalidCinemaEmailAddresses.map.keySet().toArray()[1], null, Map.class, 1 )
.property( "email", true, null, 1, List.class, 0 ),
pathWith()
.property( "map" )
.containerElement( NodeImpl.MAP_VALUE_NODE_NAME, true, invalidCinemaEmailAddresses.map.keySet().toArray()[1], null, Map.class, 1 )
.property( "email", true, null, 2, List.class, 0 ),
pathWith()
.property( "map" )
.containerElement( NodeImpl.MAP_VALUE_NODE_NAME, true, invalidCinemaEmailAddresses.map.keySet().toArray()[2], null, Map.class, 1 )
.containerElement( NodeImpl.LIST_ELEMENT_NODE_NAME, true, null, 0, List.class, 0 )
);
CinemaEmailAddresses invalidKeyCinemaEmailAddresses = CinemaEmailAddresses.invalidKey();
constraintViolations = validator.validate( invalidKeyCinemaEmailAddresses );
assertCorrectPropertyPaths(
constraintViolations,
"map<K>[Optional[Cinema<cinema4>]].<map key>.visitor.name"
);
assertCorrectConstraintTypes( constraintViolations, NotNull.class );
assertThat( constraintViolations ).containsOnlyPaths(
pathWith()
.property( "map" )
.containerElement( NodeImpl.MAP_KEY_NODE_NAME, true, invalidKeyCinemaEmailAddresses.map.keySet().toArray()[1], null, Map.class, 0 )
.property( "visitor", Optional.class, 0 )
.property( "name", Reference.class, 0 )
);
}
@Test
public void testNestedOnArray() {
Validator validator = Validation.byProvider( HibernateValidator.class )
.configure()
.addValueExtractor( new ReferenceValueExtractor() )
.buildValidatorFactory()
.getValidator();
Set<ConstraintViolation<CinemaArray>> constraintViolations = validator.validate( CinemaArray.validCinemaArray() );
assertNumberOfViolations( constraintViolations, 0 );
constraintViolations = validator.validate( CinemaArray.invalidCinemaArray() );
assertCorrectPropertyPaths(
constraintViolations,
"array[0].<iterable element>[0].<list element>",
"array[0].<iterable element>[1].visitor.name"
);
assertCorrectConstraintTypes( constraintViolations, NotNull.class, NotNull.class );
assertThat( constraintViolations ).containsOnlyPaths(
pathWith()
.property( "array" )
.containerElement( NodeImpl.ITERABLE_ELEMENT_NODE_NAME, true, null, 0, Object[].class, null )
.containerElement( NodeImpl.LIST_ELEMENT_NODE_NAME, true, null, 0, List.class, 0 ),
pathWith()
.property( "array" )
.containerElement( NodeImpl.ITERABLE_ELEMENT_NODE_NAME, true, null, 0, Object[].class, null )
.property( "visitor", true, null, 1, List.class, 0 )
.property( "name", Reference.class, 0 )
);
}
@Test
@TestForIssue(jiraKey = "HV-1326")
public void testNestedNullValue() {
Validator validator = Validation.byProvider( HibernateValidator.class )
.configure()
.addValueExtractor( new ReferenceValueExtractor() )
.buildValidatorFactory()
.getValidator();
Set<ConstraintViolation<NestedCascadingListWithValidAllAlongTheWay>> constraintViolations = validator
.validate( NestedCascadingListWithValidAllAlongTheWay.valid() );
assertNumberOfViolations( constraintViolations, 0 );
constraintViolations = validator.validate( NestedCascadingListWithValidAllAlongTheWay.withNullList() );
assertCorrectConstraintTypes( constraintViolations, NotNull.class );
assertCorrectPropertyPaths( constraintViolations, "list[0].<list element>" );
}
private static class EmailAddressMap {
private final Map<String, List<@Valid EmailAddress>> map = new LinkedHashMap<>();
private static EmailAddressMap validEmailAddressMap() {
List<EmailAddress> validEmailAddresses = Arrays.asList( new EmailAddress( "valid-email-1@example.com" ), new EmailAddress( "valid-email-2@example.com" ) );
EmailAddressMap emailAddressMap = new EmailAddressMap();
emailAddressMap.map.put( "valid", validEmailAddresses );
return emailAddressMap;
}
private static EmailAddressMap invalidEmailAddressMap() {
List<EmailAddress> validEmailAddresses = Arrays.asList( new EmailAddress( "valid-email-1@example.com" ), new EmailAddress( "valid-email-2@example.com" ) );
List<EmailAddress> emailAddressesContainingInvalidEmails = Arrays.asList( new EmailAddress( "valid-email-3@example.com" ),
new EmailAddress( "invalid-1" ), new EmailAddress( "invalid-2" ) );
EmailAddressMap emailAddressMap = new EmailAddressMap();
emailAddressMap.map.put( "valid", validEmailAddresses );
emailAddressMap.map.put( "invalid", emailAddressesContainingInvalidEmails );
return emailAddressMap;
}
}
private static class CinemaEmailAddresses {
private final Map<@NotNull Optional<@Valid Cinema>, List<@NotNull @Valid EmailAddress>> map = new LinkedHashMap<>();
private static CinemaEmailAddresses validCinemaEmailAddresses() {
CinemaEmailAddresses cinemaEmailAddresses = new CinemaEmailAddresses();
cinemaEmailAddresses.map.put(
Optional.of( new Cinema( "cinema1", new SomeReference<>( new Visitor( "Name 1" ) ) ) ),
Arrays.asList( new EmailAddress( "valid-email-1@example.com" ), new EmailAddress( "valid-email-2@example.com" ) )
);
return cinemaEmailAddresses;
}
private static CinemaEmailAddresses invalidCinemaEmailAddresses() {
CinemaEmailAddresses cinemaEmailAddresses = validCinemaEmailAddresses();
cinemaEmailAddresses.map.put(
Optional.of( new Cinema( "cinema2", new SomeReference<>( new Visitor( "Name 2" ) ) ) ),
Arrays.asList( new EmailAddress( "valid-email-3@example.com" ), new EmailAddress( "invalid-1" ), new EmailAddress( "invalid-2" ) )
);
cinemaEmailAddresses.map.put(
Optional.of( new Cinema( "cinema3", new SomeReference<>( new Visitor( "Name 3" ) ) ) ),
Arrays.asList( (EmailAddress) null )
);
return cinemaEmailAddresses;
}
private static CinemaEmailAddresses invalidKey() {
CinemaEmailAddresses cinemaEmailAddresses = validCinemaEmailAddresses();
cinemaEmailAddresses.map.put(
Optional.of( new Cinema( "cinema4", new SomeReference<>( new Visitor() ) ) ),
Arrays.asList( new EmailAddress( "valid-email-4@example.com" ) )
);
return cinemaEmailAddresses;
}
}
@SuppressWarnings({ "unused", "unchecked" })
private static class CinemaArray {
private List<@NotNull @Valid Cinema>[] array;
private static CinemaArray validCinemaArray() {
CinemaArray cinemaArray = new CinemaArray();
cinemaArray.array = new List[] { Arrays.asList( new Cinema( "cinema1", new SomeReference<>( new Visitor( "Name 1" ) ) ) ) };
return cinemaArray;
}
private static CinemaArray invalidCinemaArray() {
CinemaArray cinemaArray = new CinemaArray();
cinemaArray.array = new List[] { Arrays.asList( null, new Cinema( "cinema2", new SomeReference<>( new Visitor() ) ) ) };
return cinemaArray;
}
}
@SuppressWarnings({ "unused" })
private static class NestedCascadingListWithValidAllAlongTheWay {
private List<@NotNull List<@NotNull @Valid Cinema>> list;
private static NestedCascadingListWithValidAllAlongTheWay valid() {
NestedCascadingListWithValidAllAlongTheWay valid = new NestedCascadingListWithValidAllAlongTheWay();
valid.list = Arrays.asList( Arrays.asList( new Cinema( "cinema1", new SomeReference<>( new Visitor( "Name 1" ) ) ) ) );
return valid;
}
private static NestedCascadingListWithValidAllAlongTheWay withNullList() {
NestedCascadingListWithValidAllAlongTheWay valid = new NestedCascadingListWithValidAllAlongTheWay();
valid.list = Arrays.asList( (List<Cinema>) null );
return valid;
}
}
}