@ -42,6 +42,7 @@ import org.junit.jupiter.api.AfterEach;
@@ -42,6 +42,7 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach ;
import org.junit.jupiter.api.Nested ;
import org.junit.jupiter.api.Test ;
import org.junit.jupiter.api.condition.EnabledForJreRange ;
import org.junit.jupiter.params.ParameterizedTest ;
import org.junit.jupiter.params.provider.ValueSource ;
@ -58,6 +59,8 @@ import org.springframework.validation.DataBinder;
@@ -58,6 +59,8 @@ import org.springframework.validation.DataBinder;
import org.springframework.validation.FieldError ;
import static org.assertj.core.api.Assertions.assertThat ;
import static org.junit.jupiter.api.condition.JRE.JAVA_19 ;
import static org.junit.jupiter.api.condition.JRE.JAVA_20 ;
/ * *
* @author Keith Donald
@ -68,6 +71,12 @@ import static org.assertj.core.api.Assertions.assertThat;
@@ -68,6 +71,12 @@ import static org.assertj.core.api.Assertions.assertThat;
* /
class DateTimeFormattingTests {
// JDK <= 19 requires a standard space before "AM/PM".
// JDK >= 20 requires a NNBSP before "AM/PM".
// \u202F is a narrow non-breaking space (NNBSP).
private static final String TIME_SEPARATOR = ( Runtime . version ( ) . feature ( ) < 20 ? " " : "\u202F" ) ;
private final FormattingConversionService conversionService = new FormattingConversionService ( ) ;
private DataBinder binder ;
@ -210,10 +219,11 @@ class DateTimeFormattingTests {
@@ -210,10 +219,11 @@ class DateTimeFormattingTests {
@Test
void testBindLocalTime ( ) {
MutablePropertyValues propertyValues = new MutablePropertyValues ( ) ;
propertyValues . add ( "localTime" , "12:00 PM" ) ;
propertyValues . add ( "localTime" , "12:00%sPM" . formatted ( TIME_SEPARATOR ) ) ;
binder . bind ( propertyValues ) ;
assertThat ( binder . getBindingResult ( ) . getErrorCount ( ) ) . isZero ( ) ;
assertThat ( binder . getBindingResult ( ) . getFieldValue ( "localTime" ) ) . isEqualTo ( "12:00 PM" ) ;
// \p{Zs} matches any Unicode space character
assertThat ( binder . getBindingResult ( ) . getFieldValue ( "localTime" ) ) . asString ( ) . matches ( "12:00\\p{Zs}PM" ) ;
}
@Test
@ -222,7 +232,8 @@ class DateTimeFormattingTests {
@@ -222,7 +232,8 @@ class DateTimeFormattingTests {
propertyValues . add ( "localTime" , "12:00:00" ) ;
binder . bind ( propertyValues ) ;
assertThat ( binder . getBindingResult ( ) . getErrorCount ( ) ) . isZero ( ) ;
assertThat ( binder . getBindingResult ( ) . getFieldValue ( "localTime" ) ) . isEqualTo ( "12:00 PM" ) ;
// \p{Zs} matches any Unicode space character
assertThat ( binder . getBindingResult ( ) . getFieldValue ( "localTime" ) ) . asString ( ) . matches ( "12:00\\p{Zs}PM" ) ;
}
@Test
@ -231,10 +242,11 @@ class DateTimeFormattingTests {
@@ -231,10 +242,11 @@ class DateTimeFormattingTests {
registrar . setTimeStyle ( FormatStyle . MEDIUM ) ;
setup ( registrar ) ;
MutablePropertyValues propertyValues = new MutablePropertyValues ( ) ;
propertyValues . add ( "localTime" , "12:00:00 PM" ) ;
propertyValues . add ( "localTime" , "12:00:00%sPM" . formatted ( TIME_SEPARATOR ) ) ;
binder . bind ( propertyValues ) ;
assertThat ( binder . getBindingResult ( ) . getErrorCount ( ) ) . isZero ( ) ;
assertThat ( binder . getBindingResult ( ) . getFieldValue ( "localTime" ) ) . isEqualTo ( "12:00:00 PM" ) ;
// \p{Zs} matches any Unicode space character
assertThat ( binder . getBindingResult ( ) . getFieldValue ( "localTime" ) ) . asString ( ) . matches ( "12:00:00\\p{Zs}PM" ) ;
}
@Test
@ -252,10 +264,11 @@ class DateTimeFormattingTests {
@@ -252,10 +264,11 @@ class DateTimeFormattingTests {
@Test
void testBindLocalTimeAnnotated ( ) {
MutablePropertyValues propertyValues = new MutablePropertyValues ( ) ;
propertyValues . add ( "styleLocalTime" , "12:00:00 PM" ) ;
propertyValues . add ( "styleLocalTime" , "12:00:00%sPM" . formatted ( TIME_SEPARATOR ) ) ;
binder . bind ( propertyValues ) ;
assertThat ( binder . getBindingResult ( ) . getErrorCount ( ) ) . isZero ( ) ;
assertThat ( binder . getBindingResult ( ) . getFieldValue ( "styleLocalTime" ) ) . isEqualTo ( "12:00:00 PM" ) ;
// \p{Zs} matches any Unicode space character
assertThat ( binder . getBindingResult ( ) . getFieldValue ( "styleLocalTime" ) ) . asString ( ) . matches ( "12:00:00\\p{Zs}PM" ) ;
}
@Test
@ -264,7 +277,8 @@ class DateTimeFormattingTests {
@@ -264,7 +277,8 @@ class DateTimeFormattingTests {
propertyValues . add ( "localTime" , new GregorianCalendar ( 1970 , 0 , 0 , 12 , 0 ) ) ;
binder . bind ( propertyValues ) ;
assertThat ( binder . getBindingResult ( ) . getErrorCount ( ) ) . isZero ( ) ;
assertThat ( binder . getBindingResult ( ) . getFieldValue ( "localTime" ) ) . isEqualTo ( "12:00 PM" ) ;
// \p{Zs} matches any Unicode space character
assertThat ( binder . getBindingResult ( ) . getFieldValue ( "localTime" ) ) . asString ( ) . matches ( "12:00\\p{Zs}PM" ) ;
}
@Test
@ -274,7 +288,8 @@ class DateTimeFormattingTests {
@@ -274,7 +288,8 @@ class DateTimeFormattingTests {
binder . bind ( propertyValues ) ;
assertThat ( binder . getBindingResult ( ) . getErrorCount ( ) ) . isZero ( ) ;
String value = binder . getBindingResult ( ) . getFieldValue ( "localDateTime" ) . toString ( ) ;
assertThat ( value ) . startsWith ( "10/31/09" ) . endsWith ( "12:00 PM" ) ;
// \p{Zs} matches any Unicode space character
assertThat ( value ) . startsWith ( "10/31/09" ) . matches ( ".+?12:00\\p{Zs}PM" ) ;
}
@Test
@ -284,7 +299,8 @@ class DateTimeFormattingTests {
@@ -284,7 +299,8 @@ class DateTimeFormattingTests {
binder . bind ( propertyValues ) ;
assertThat ( binder . getBindingResult ( ) . getErrorCount ( ) ) . isZero ( ) ;
String value = binder . getBindingResult ( ) . getFieldValue ( "localDateTime" ) . toString ( ) ;
assertThat ( value ) . startsWith ( "10/31/09" ) . endsWith ( "12:00 PM" ) ;
// \p{Zs} matches any Unicode space character
assertThat ( value ) . startsWith ( "10/31/09" ) . matches ( ".+?12:00\\p{Zs}PM" ) ;
}
@Test
@ -294,7 +310,8 @@ class DateTimeFormattingTests {
@@ -294,7 +310,8 @@ class DateTimeFormattingTests {
binder . bind ( propertyValues ) ;
assertThat ( binder . getBindingResult ( ) . getErrorCount ( ) ) . isZero ( ) ;
String value = binder . getBindingResult ( ) . getFieldValue ( "styleLocalDateTime" ) . toString ( ) ;
assertThat ( value ) . startsWith ( "Oct 31, 2009" ) . endsWith ( "12:00:00 PM" ) ;
// \p{Zs} matches any Unicode space character
assertThat ( value ) . startsWith ( "Oct 31, 2009" ) . matches ( ".+?12:00:00\\p{Zs}PM" ) ;
}
@Test
@ -304,7 +321,8 @@ class DateTimeFormattingTests {
@@ -304,7 +321,8 @@ class DateTimeFormattingTests {
binder . bind ( propertyValues ) ;
assertThat ( binder . getBindingResult ( ) . getErrorCount ( ) ) . isZero ( ) ;
String value = binder . getBindingResult ( ) . getFieldValue ( "localDateTime" ) . toString ( ) ;
assertThat ( value ) . startsWith ( "10/31/09" ) . endsWith ( "12:00 PM" ) ;
// \p{Zs} matches any Unicode space character
assertThat ( value ) . startsWith ( "10/31/09" ) . matches ( ".+?12:00\\p{Zs}PM" ) ;
}
@Test
@ -317,7 +335,8 @@ class DateTimeFormattingTests {
@@ -317,7 +335,8 @@ class DateTimeFormattingTests {
binder . bind ( propertyValues ) ;
assertThat ( binder . getBindingResult ( ) . getErrorCount ( ) ) . isZero ( ) ;
String value = binder . getBindingResult ( ) . getFieldValue ( "localDateTime" ) . toString ( ) ;
assertThat ( value ) . startsWith ( "Oct 31, 2009" ) . endsWith ( "12:00:00 PM" ) ;
// \p{Zs} matches any Unicode space character
assertThat ( value ) . startsWith ( "Oct 31, 2009" ) . matches ( ".+?12:00:00\\p{Zs}PM" ) ;
}
@Test
@ -558,18 +577,32 @@ class DateTimeFormattingTests {
@@ -558,18 +577,32 @@ class DateTimeFormattingTests {
assertThat ( bindingResult . getFieldValue ( propertyName ) ) . isEqualTo ( "2021-03-02" ) ;
}
@EnabledForJreRange ( max = JAVA_19 )
@ParameterizedTest ( name = "input date: {0}" )
// @ValueSource(strings = {"12:00:00\u202FPM", "12:00:00", "12:00"})
// JDK <= 19 requires a standard space before the "PM".
@ValueSource ( strings = { "12:00:00 PM" , "12:00:00" , "12:00" } )
void styleLocalTime ( String propertyValue ) {
void styleLocalTime_PreJDK20 ( String propertyValue ) {
styleLocalTime ( propertyValue ) ;
}
@EnabledForJreRange ( min = JAVA_20 )
@ParameterizedTest ( name = "input date: {0}" )
// JDK >= 20 requires a NNBSP before the "PM".
// \u202F is a narrow non-breaking space (NNBSP).
@ValueSource ( strings = { "12:00:00\u202FPM" , "12:00:00" , "12:00" } )
void styleLocalTime_PostJDK20 ( String propertyValue ) {
styleLocalTime ( propertyValue ) ;
}
private void styleLocalTime ( String propertyValue ) {
String propertyName = "styleLocalTimeWithFallbackPatterns" ;
MutablePropertyValues propertyValues = new MutablePropertyValues ( ) ;
propertyValues . add ( propertyName , propertyValue ) ;
binder . bind ( propertyValues ) ;
BindingResult bindingResult = binder . getBindingResult ( ) ;
assertThat ( bindingResult . getErrorCount ( ) ) . isZero ( ) ;
// assertThat(bindingResult.getFieldValue(propertyName)).asString().matches("12:00:00\\SPM");
assertThat ( bindingResult . getFieldValue ( propertyName ) ) . isEqualTo ( "12:00:00 PM" ) ;
// \p{Zs} matches any Unicode space character
assertThat ( bindingResult . getFieldValue ( propertyName ) ) . asString ( ) . matches ( "12:00:00\\p{Zs} PM") ;
}
@ParameterizedTest ( name = "input date: {0}" )