/*
* 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.constraintvalidators.hv;
import static org.hibernate.validator.testutil.ConstraintViolationAssert.assertCorrectConstraintViolationMessages;
import static org.hibernate.validator.testutil.ConstraintViolationAssert.assertCorrectPropertyPaths;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import java.time.Instant;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Set;
import javax.validation.ConstraintDeclarationException;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import org.hibernate.validator.constraints.ScriptAssert;
import org.hibernate.validator.internal.constraintvalidators.hv.ScriptAssertValidator;
import org.hibernate.validator.internal.util.annotationfactory.AnnotationDescriptor;
import org.hibernate.validator.internal.util.annotationfactory.AnnotationFactory;
import org.hibernate.validator.testutil.TestForIssue;
import org.hibernate.validator.testutils.ValidatorUtil;
import org.testng.annotations.Test;
/**
* Unit test for {@link org.hibernate.validator.internal.constraintvalidators.hv.ScriptAssertValidator}.
*
* @author Gunnar Morling
* @author Hardy Ferentschik
*/
public class ScriptAssertValidatorTest {
@Test
public void scriptEvaluatesToTrue() throws Exception {
ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator( "groovy", "true" );
assertTrue( validator.isValid( new Object(), null ) );
}
@Test
public void scriptEvaluatesToFalse() throws Exception {
ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator( "groovy", "false" );
assertFalse( validator.isValid( new Object(), null ) );
}
@Test
public void scriptExpressionReferencingAnnotatedObject() throws Exception {
ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator(
"groovy", "_this.startDate.before(_this.endDate)"
);
Date startDate = new GregorianCalendar( 2009, 8, 20 ).getTime();
Date endDate = new GregorianCalendar( 2009, 8, 21 ).getTime();
assertTrue( validator.isValid( new CalendarEvent( startDate, endDate ), null ) );
assertFalse( validator.isValid( new CalendarEvent( endDate, startDate ), null ) );
}
@Test
public void scriptExpressionUsingCustomizedAlias() throws Exception {
ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator(
"groovy", "_.startDate.before(_.endDate)", "_"
);
Date startDate = new GregorianCalendar( 2009, 8, 20 ).getTime();
Date endDate = new GregorianCalendar( 2009, 8, 21 ).getTime();
assertFalse( validator.isValid( new CalendarEvent( endDate, startDate ), null ) );
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void emptyLanguageNameRaisesException() throws Exception {
getInitializedValidator( "", "script" );
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void emptyScriptRaisesException() throws Exception {
getInitializedValidator( "lang", "" );
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void emptyAliasRaisesException() throws Exception {
getInitializedValidator( "lang", "script", "" );
}
@Test(expectedExceptions = ConstraintDeclarationException.class)
public void unknownLanguageNameRaisesException() throws Exception {
ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator( "foo", "script" );
validator.isValid( new Object(), null );
}
@Test(expectedExceptions = ConstraintDeclarationException.class)
public void illegalScriptExpressionRaisesException() throws Exception {
ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator( "groovy", "foo" );
validator.isValid( new Object(), null );
}
@Test(expectedExceptions = ConstraintDeclarationException.class)
public void scriptExpressionReturningNullRaisesException() throws Exception {
ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator( "groovy", "null" );
validator.isValid( new Object(), null );
}
@Test(expectedExceptions = ConstraintDeclarationException.class)
public void scriptExpressionReturningNoBooleanRaisesException() throws Exception {
ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator(
"groovy", "new java.util.Date()"
);
validator.isValid( new Object(), null );
}
@Test
@TestForIssue(jiraKey = "HV-1201")
public void reportOnField() {
Validator validator = ValidatorUtil.getValidator();
assertTrue( validator.validate( new AnnotatedCalendarEvent(
Date.from( Instant.now() ),
Date.from( Instant.now().plusMillis( 1000L ) )
)
).isEmpty(), "Should pass validation" );
Set<ConstraintViolation<AnnotatedCalendarEvent>> fieldViolations = validator.validate(
new AnnotatedCalendarEvent(
Date.from( Instant.now().plusMillis( 1000L ) ),
Date.from( Instant.now().minusMillis( 1000L ) )
)
);
assertCorrectPropertyPaths( fieldViolations, "startDate" );
assertCorrectConstraintViolationMessages( fieldViolations, "script expression \"_this.startDate.before(_this.endDate)\" didn't evaluate to true" );
Set<ConstraintViolation<AnnotatedWithoutReportCalendarEvent>> beanViolations = validator.validate(
new AnnotatedWithoutReportCalendarEvent(
Date.from( Instant.now().plusMillis( 1000L ) ),
Date.from( Instant.now().minusMillis( 1000L ) )
)
);
assertCorrectPropertyPaths( beanViolations, "" );
assertCorrectConstraintViolationMessages( fieldViolations, "script expression \"_this.startDate.before(_this.endDate)\" didn't evaluate to true" );
}
/**
* @param lang the script type
* @param script the actual script
* @param alias the alias name of the this object
*
* @return a {@link org.hibernate.validator.internal.constraintvalidators.hv.ScriptAssertValidator} initialized with a {@link ScriptAssert} with the given values.
*/
private ConstraintValidator<ScriptAssert, Object> getInitializedValidator(String lang, String script, String alias) {
return getInitializedValidator( lang, script, alias, null );
}
/**
* @param lang the script type
* @param script the actual script
*
* @return a {@link ScriptAssertValidator} initialized with a {@link ScriptAssert} with the given values.
*/
private ConstraintValidator<ScriptAssert, Object> getInitializedValidator(String lang, String script) {
return getInitializedValidator( lang, script, null );
}
/**
* @param lang the script type
* @param script the actual script
* @param alias the alias name of the this object
* @param reportOn a property name on which to report an error
*
* @return a {@link ScriptAssertValidator} initialized with a {@link ScriptAssert} with the given values.
*/
private ConstraintValidator<ScriptAssert, Object> getInitializedValidator(String lang, String script, String alias, String reportOn) {
ConstraintValidator<ScriptAssert, Object> validator = new ScriptAssertValidator();
validator.initialize( getScriptAssert( lang, script, alias, reportOn ) );
return validator;
}
/**
* @param lang the script type
* @param script the actual script
* @param alias the alias name of the this object
* @param reportOn a property name on which to report an error
*
* @return a {@link ScriptAssert} initialized with the given values.
*/
private ScriptAssert getScriptAssert(String lang, String script, String alias, String reportOn) {
AnnotationDescriptor<ScriptAssert> descriptor = AnnotationDescriptor.getInstance( ScriptAssert.class );
descriptor.setValue( "lang", lang );
descriptor.setValue( "script", script );
if ( alias != null ) {
descriptor.setValue( "alias", alias );
}
if ( reportOn != null ) {
descriptor.setValue( "reportOn", reportOn );
}
return AnnotationFactory.create( descriptor );
}
/**
* An exemplary model class used in tests.
*
* @author Gunnar Morling
*/
private static class CalendarEvent {
private final Date startDate;
private final Date endDate;
public CalendarEvent(Date startDate, Date endDate) {
this.startDate = startDate;
this.endDate = endDate;
}
@SuppressWarnings("unused")
public Date getStartDate() {
return startDate;
}
@SuppressWarnings("unused")
public Date getEndDate() {
return endDate;
}
}
@ScriptAssert(lang = "groovy", script = "_this.startDate.before(_this.endDate)", reportOn = "startDate")
@SuppressWarnings("unused")
private static class AnnotatedCalendarEvent {
private final Date startDate;
private final Date endDate;
public AnnotatedCalendarEvent(Date startDate, Date endDate) {
this.startDate = startDate;
this.endDate = endDate;
}
}
@ScriptAssert(lang = "groovy", script = "_this.startDate.before(_this.endDate)")
@SuppressWarnings("unused")
private static class AnnotatedWithoutReportCalendarEvent {
private final Date startDate;
private final Date endDate;
public AnnotatedWithoutReportCalendarEvent(Date startDate, Date endDate) {
this.startDate = startDate;
this.endDate = endDate;
}
}
}