Skip to content

Commit

Permalink
Stop using using legacy locale data for Date/Time formatting tests
Browse files Browse the repository at this point in the history
Commit 84714fb introduced usage of the
-Djava.locale.providers=COMPAT command-line argument for javac in order
to allow our JDK 20 builds to pass by using legacy locale data.

That was done to ensure that Date/Time formats using AM/PM produced a
standard space (" ") before the "AM" or "PM" instead of a narrow
non-breaking space (NNBSP "\u202F"), which was introduced in Java 20
due to adoption of Unicode Common Locale Data Repository (CLDR-14032).

This commit removes usage of the -Djava.locale.providers=COMPAT
command-line argument and updates all affected tests to:

- Use an NNBSP before "AM" or "PM" in input text when running on Java 20
  or higher.

- Leniently match against any Unicode space character in formatted
  values containing "AM" or "PM".

See https://jdk.java.net/20/release-notes#JDK-8284840
See https://unicode-org.atlassian.net/browse/CLDR-14032
See gh-30185
Closes gh-33144
  • Loading branch information
sbrannen committed Jul 4, 2024
1 parent 51641ec commit 89338c9
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -63,8 +63,7 @@ private void configureTests(Project project, Test test) {
test.systemProperty("testGroups", project.getProperties().get("testGroups"));
}
test.jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED",
"--add-opens=java.base/java.util=ALL-UNNAMED",
"-Djava.locale.providers=COMPAT");
"--add-opens=java.base/java.util=ALL-UNNAMED");
}

private void configureTestRetryPlugin(Project project, Test test) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ void createDateTimeFormatterWithFallback() {
void createDateTimeFormatterInOrderOfPropertyPriority() {
factory.setStylePattern("SS");
String value = applyLocale(factory.createDateTimeFormatter()).format(dateTime);
assertThat(value).startsWith("10/21/09");
assertThat(value).endsWith("12:10 PM");
// \p{Zs} matches any Unicode space character
assertThat(value).startsWith("10/21/09").matches(".+?12:10\\p{Zs}PM");

factory.setIso(ISO.DATE);
assertThat(applyLocale(factory.createDateTimeFormatter()).format(dateTime)).isEqualTo("2009-10-21");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
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;

Expand All @@ -58,6 +59,8 @@
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
Expand All @@ -68,6 +71,12 @@
*/
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;
Expand Down Expand Up @@ -210,10 +219,11 @@ void testBindLocalDateFromJavaUtilCalendar() {
@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
Expand All @@ -222,7 +232,8 @@ void testBindLocalTimeWithISO() {
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
Expand All @@ -231,10 +242,11 @@ void testBindLocalTimeWithSpecificStyle() {
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
Expand All @@ -252,10 +264,11 @@ void testBindLocalTimeWithSpecificFormatter() {
@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
Expand All @@ -264,7 +277,8 @@ void testBindLocalTimeFromJavaUtilCalendar() {
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
Expand All @@ -274,7 +288,8 @@ void testBindLocalDateTime() {
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
Expand All @@ -284,7 +299,8 @@ void testBindLocalDateTimeWithISO() {
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
Expand All @@ -294,7 +310,8 @@ void testBindLocalDateTimeAnnotated() {
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
Expand All @@ -304,7 +321,8 @@ void testBindLocalDateTimeFromJavaUtilCalendar() {
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
Expand All @@ -317,7 +335,8 @@ void testBindDateTimeWithSpecificStyle() {
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
Expand Down Expand Up @@ -558,18 +577,32 @@ void patternLocalDate(String propertyValue) {
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}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,10 @@ void customizeDateFormatNone() {
cal.set(Calendar.DATE, 1);
Date date = cal.getTime();
bean.setDate(date);
// \p{Zs} matches any Unicode space character
assertThat(gson.toJson(bean))
.startsWith("{\"date\":\"Jan 1, 2014")
.endsWith("12:00:00 AM\"}");
.matches(".+?12:00:00\\p{Zs}AM\"}");
}

@Test
Expand Down

0 comments on commit 89338c9

Please sign in to comment.