/*
* 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.messageinterpolation;
import java.util.Collections;
import java.util.Locale;
import javax.validation.MessageInterpolator;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.hibernate.validator.internal.engine.MessageInterpolatorContext;
import org.hibernate.validator.internal.metadata.core.ConstraintHelper;
import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl;
import org.hibernate.validator.internal.util.annotationfactory.AnnotationDescriptor;
import org.hibernate.validator.internal.util.annotationfactory.AnnotationFactory;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
import org.hibernate.validator.testutil.TestForIssue;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
/**
* Tests for message interpolation using EL.
*
* @author Hardy Ferentschik
*/
public class ExpressionLanguageMessageInterpolationTest {
private MessageInterpolator interpolatorUnderTest;
private ConstraintDescriptorImpl<NotNull> notNullDescriptor;
private ConstraintDescriptorImpl<Size> sizeDescriptor;
@BeforeTest
public void setUp() {
// Create some annotations for testing using AnnotationProxies
AnnotationDescriptor<NotNull> descriptor = new AnnotationDescriptor<NotNull>( NotNull.class );
NotNull notNull = AnnotationFactory.create( descriptor );
notNullDescriptor = new ConstraintDescriptorImpl<NotNull>(
new ConstraintHelper(),
null,
notNull,
java.lang.annotation.ElementType.FIELD
);
AnnotationDescriptor<Size> sizeAnnotationDescriptor = new AnnotationDescriptor<Size>( Size.class );
Size size = AnnotationFactory.create( sizeAnnotationDescriptor );
sizeDescriptor = new ConstraintDescriptorImpl<Size>(
new ConstraintHelper(),
null,
size,
java.lang.annotation.ElementType.FIELD
);
interpolatorUnderTest = new ResourceBundleMessageInterpolator();
}
@Test
public void testExpressionLanguageGraphNavigation() {
User user = new User();
user.setAge( 18 );
MessageInterpolator.Context context = new MessageInterpolatorContext(
notNullDescriptor,
user,
null,
Collections.<String, Object>emptyMap(),
Collections.<String, Object>emptyMap()
);
String expected = "18";
String actual = interpolatorUnderTest.interpolate( "${validatedValue.age}", context );
assertEquals( actual, expected, "Wrong substitution" );
}
@Test
public void testUnknownPropertyInExpressionLanguageGraphNavigation() {
MessageInterpolator.Context context = new MessageInterpolatorContext(
notNullDescriptor,
new User(),
null,
Collections.<String, Object>emptyMap(),
Collections.<String, Object>emptyMap()
);
String expected = "${validatedValue.foo}";
String actual = interpolatorUnderTest.interpolate( "${validatedValue.foo}", context );
assertEquals( actual, expected, "No substitution should occur" );
}
@Test
public void testNullValidatedValue() {
MessageInterpolator.Context context = createMessageInterpolatorContext( notNullDescriptor );
String expected = "Validated value was null";
String actual = interpolatorUnderTest.interpolate(
"Validated value was ${validatedValue == null ? 'null' : validatedValue}",
context
);
assertEquals( actual, expected, "Wrong substitution" );
}
@Test
public void testExpressionAndParameterInterpolationInSameMessageDescriptor() {
MessageInterpolator.Context context = createMessageInterpolatorContext( sizeDescriptor );
String expected = "2 0 2147483647";
String actual = interpolatorUnderTest.interpolate( "${1+1} {min} {max}", context );
assertEquals( actual, expected, "Wrong substitution" );
}
@Test
public void testEscapedExpressionLanguage() {
MessageInterpolator.Context context = createMessageInterpolatorContext( sizeDescriptor );
String expected = "${1+1}";
String actual = interpolatorUnderTest.interpolate( "\\${1+1}", context );
assertEquals( actual, expected, "Wrong substitution" );
}
@Test
public void testTernaryExpressionLanguageOperator() {
MessageInterpolator.Context context = createMessageInterpolatorContext( sizeDescriptor );
String expected = "foo";
String actual = interpolatorUnderTest.interpolate( "${min == 0 ? 'foo' : 'bar'}", context );
assertEquals( actual, expected, "Wrong substitution" );
}
@Test
public void testParameterFormatting() {
MessageInterpolator.Context context = createMessageInterpolatorContext( sizeDescriptor );
String expected = "Max 2147483647, min 0";
String actual = interpolatorUnderTest.interpolate( "${formatter.format('Max %s, min %s', max, min)}", context );
assertEquals( actual, expected, "Wrong substitution" );
}
@Test
public void testLiteralStaysUnchanged() {
MessageInterpolator.Context context = createMessageInterpolatorContext( sizeDescriptor );
String expected = "foo";
String actual = interpolatorUnderTest.interpolate( "foo", context );
assertEquals( actual, expected, "Wrong substitution" );
}
@Test
public void testLiteralBackslash() {
MessageInterpolator.Context context = createMessageInterpolatorContext( sizeDescriptor );
String expected = "\\foo";
String actual = interpolatorUnderTest.interpolate( "\\foo", context );
assertEquals( actual, expected, "Wrong substitution" );
}
@Test
public void testPrecedenceOfParameterInterpolation() {
MessageInterpolator.Context context = createMessageInterpolatorContext( sizeDescriptor );
String expected = "$0";
String actual = interpolatorUnderTest.interpolate( "${min}", context );
assertEquals( actual, expected, "Wrong substitution" );
}
@Test
public void testLocaleBasedFormatting() {
MessageInterpolator.Context context = new MessageInterpolatorContext(
notNullDescriptor,
42.00000d,
null,
Collections.<String, Object>emptyMap(),
Collections.<String, Object>emptyMap()
);
// german locale
String expected = "42,00";
String actual = interpolatorUnderTest.interpolate(
"${formatter.format('%1$.2f', validatedValue)}",
context,
Locale.GERMAN
);
assertEquals( actual, expected, "Wrong substitution" );
// us locale
expected = "42.00";
actual = interpolatorUnderTest.interpolate(
"${formatter.format('%1$.2f', validatedValue)}",
context,
Locale.US
);
assertEquals( actual, expected, "Wrong substitution" );
}
@Test
public void testMissingFormatArgument() {
MessageInterpolator.Context context = createMessageInterpolatorContext( sizeDescriptor );
String expected = "${formatter.format('%1$s')}";
String actual = interpolatorUnderTest.interpolate( "${formatter.format('%1$s')}", context );
assertEquals(
actual,
expected,
"Calling of formatter#format w/o format parameter. No substitution should occur"
);
}
@Test
public void testNoParametersToFormatter() {
MessageInterpolator.Context context = createMessageInterpolatorContext( sizeDescriptor );
String expected = "${formatter.format()}";
String actual = interpolatorUnderTest.interpolate( "${formatter.format()}", context );
assertEquals( actual, expected, "Calling of formatter#format w/o parameters. No substitution should occur" );
}
@Test
public void testNonFormatterFunction() {
MessageInterpolator.Context context = createMessageInterpolatorContext( sizeDescriptor );
String expected = "foo";
String actual = interpolatorUnderTest.interpolate( "${'foobar'.substring(0,3)}", context );
assertEquals( actual, expected, "Calling of String#substring should work" );
}
@Test
public void testCallingWrongFormatterMethod() {
MessageInterpolator.Context context = new MessageInterpolatorContext(
notNullDescriptor,
42.00000d,
null,
Collections.<String, Object>emptyMap(),
Collections.<String, Object>emptyMap()
);
String expected = "${formatter.foo('%1$.2f', validatedValue)}";
String actual = interpolatorUnderTest.interpolate(
"${formatter.foo('%1$.2f', validatedValue)}",
context,
Locale.GERMAN
);
assertEquals(
actual,
expected,
"Wrong substitution, no formatting should occur, because the wrong method name is used"
);
}
@Test
@TestForIssue(jiraKey = "HV-834")
public void testOpeningCurlyBraceInELExpression() {
MessageInterpolator.Context context = createMessageInterpolatorContext( sizeDescriptor );
String expected = "{";
String actual = interpolatorUnderTest.interpolate( "${1 > 0 ? '\\{' : '\\}'}", context );
assertEquals( actual, expected, "Curly braces are allowed in EL expressions, but need to be escaped" );
}
@Test
@TestForIssue(jiraKey = "HV-834")
public void testClosingCurlyBraceInELExpression() {
MessageInterpolator.Context context = createMessageInterpolatorContext( sizeDescriptor );
String expected = "}";
String actual = interpolatorUnderTest.interpolate( "${1 < 0 ? '\\{' : '\\}'}", context );
assertEquals( actual, expected, "Curly braces are allowed in EL expressions, but need to be escaped" );
}
@Test
@TestForIssue(jiraKey = "HV-834")
public void testCurlyBracesInELExpression() {
MessageInterpolator.Context context = createMessageInterpolatorContext( sizeDescriptor );
String expected = "a{b}d";
String actual = interpolatorUnderTest.interpolate( "${1 < 0 ? 'foo' : 'a\\{b\\}d'}", context );
assertEquals( actual, expected, "Curly braces are allowed in EL expressions, but need to be escaped" );
}
@Test
@TestForIssue(jiraKey = "HV-834")
public void testEscapedQuoteInELExpression() {
MessageInterpolator.Context context = createMessageInterpolatorContext( sizeDescriptor );
String expected = "\"";
String actual = interpolatorUnderTest.interpolate( "${ true ? \"\\\"\" : \"foo\"}", context );
assertEquals( actual, expected, "If quotes are used in EL expression literal quotes need to be escaped" );
}
@Test
@TestForIssue(jiraKey = "HV-834")
public void testSingleEscapedQuoteInELExpression() {
MessageInterpolator.Context context = createMessageInterpolatorContext( sizeDescriptor );
String expected = "'";
String actual = interpolatorUnderTest.interpolate( "${ false ? 'foo' : '\\''}", context );
assertEquals(
actual,
expected,
"If single quotes are used in EL expression literal single quotes need to be escaped"
);
}
private MessageInterpolatorContext createMessageInterpolatorContext(ConstraintDescriptorImpl<?> descriptor) {
return new MessageInterpolatorContext(
descriptor,
null,
null,
Collections.<String, Object>emptyMap(),
Collections.<String, Object>emptyMap()
);
}
}