|
|
|
|
@ -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}") |
|
|
|
|
|