diff --git a/tools/cldr-code/src/main/java/org/unicode/cldr/tool/GenerateDateTimeTestData.java b/tools/cldr-code/src/main/java/org/unicode/cldr/tool/GenerateDateTimeTestData.java index 9767d20ca31..8709a881ddb 100644 --- a/tools/cldr-code/src/main/java/org/unicode/cldr/tool/GenerateDateTimeTestData.java +++ b/tools/cldr-code/src/main/java/org/unicode/cldr/tool/GenerateDateTimeTestData.java @@ -24,6 +24,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.regex.Matcher; @@ -39,6 +40,7 @@ import org.unicode.cldr.util.Factory; import org.unicode.cldr.util.ICUServiceBuilder; import org.unicode.cldr.util.Level; +import org.unicode.cldr.util.SimpleFactory.NoSourceDirectoryException; import org.unicode.cldr.util.SupplementalDataInfo; import org.unicode.cldr.util.TempPrintWriter; @@ -284,9 +286,15 @@ private static ZonedDateTime getZonedDateTimeFromTemporalDateInput(Map getCLDRFile(String locale) { - CLDRFile cldrFile = + CLDRFile cldrFile; + + try { + cldrFile = CLDR_FACTORY.make( - locale, true, DraftStatus.contributed); // don't include provisional data + locale, true, DraftStatus.contributed); // don't include provisional data + } catch (NoSourceDirectoryException nsde) { + return Optional.empty(); + } // This is the CLDR "effective coverage level" Level coverageLevel = @@ -1041,7 +1049,7 @@ public static String computeSkeletonFromSemanticSkeleton( return sb.toString(); } - private static TestCase convertTestCaseInputToTestCase( + private static TestCase convertTestCaseInputToTestCaseForNonSemanticSkeleton( ICUServiceBuilder icuServiceBuilder, CLDRFile localeCldrFile, TestCaseInput testCaseInput) { @@ -1081,13 +1089,21 @@ private static TestCase convertTestCaseInputToTestCase( return result; } + /** + * Primary function for converting a {@code TestCaseInput} into a {@code TestCase}, with the + * logic to handle semantic skeleton inputs differently from non-semantic skeleton inputs. + * @param icuServiceBuilder + * @param localeCldrFile + * @param testCaseInput + * @return + */ private static TestCase computeTestCase( ICUServiceBuilder icuServiceBuilder, CLDRFile localeCldrFile, TestCaseInput testCaseInput) { if (testCaseInput.fieldStyleCombo.semanticSkeleton == null) { - return convertTestCaseInputToTestCase(icuServiceBuilder, localeCldrFile, testCaseInput); + return convertTestCaseInputToTestCaseForNonSemanticSkeleton(icuServiceBuilder, localeCldrFile, testCaseInput); } else { String calendarStr = testCaseInput.calendar.getType(); String skeleton = @@ -1117,32 +1133,38 @@ private static TestCase computeTestCase( } } - public static ImmutableSet getKernelTestCases() { + //----------- + // begin: manually defined dimensions of iteration value sets + //----------- + + static List> LOCALE_CALENDAR_PAIRS = + List.of( + Pair.of(ULocale.ENGLISH, new GregorianCalendar()), + Pair.of(ULocale.forLanguageTag("ar-SA"), new IslamicCalendar()), + Pair.of(ULocale.forLanguageTag("th-TH"), new BuddhistCalendar()), + Pair.of(ULocale.forLanguageTag("ja-JP"), new JapaneseCalendar())); - // more manually defined inputs + static List DATE_TIMES = + List.of( + LocalDateTime.of(2000, 1, 1, 0, 0, 0), + LocalDateTime.of(2024, 7, 1, 8, 50, 7), + // Ramadan in Summer at 12:00 noon in the year 2014 + LocalDateTime.of(2014, 7, 15, 12, 0, 0)); - List> LOCALE_CALENDAR_PAIRS = - List.of( - Pair.of(ULocale.ENGLISH, new GregorianCalendar()), - Pair.of(ULocale.forLanguageTag("ar-SA"), new IslamicCalendar()), - Pair.of(ULocale.forLanguageTag("th-TH"), new BuddhistCalendar()), - Pair.of(ULocale.forLanguageTag("ja-JP"), new JapaneseCalendar())); + static List DATE_TIME_ONE_ONLY = List.of(DATE_TIMES.get(0)); - List DATE_TIMES = - List.of( - LocalDateTime.of(2000, 1, 1, 0, 0, 0), - LocalDateTime.of(2024, 7, 1, 8, 50, 7), - // Ramadan in Summer at 12:00 noon in the year 2014 - LocalDateTime.of(2014, 7, 15, 12, 0, 0)); + // TODO: add a 3rd time zone dynamically, which is the default time zone for the current + // locale in question when iterating over all locales + static List STATIC_TIME_ZONES = + List.of(TimeZone.GMT_ZONE, TimeZone.getTimeZone("Australia/Adelaide")); - List DATE_TIME_ONE_ONLY = List.of(DATE_TIMES.get(0)); + static List STATIC_TIME_ZONE_ONE_ONLY = List.of(STATIC_TIME_ZONES.get(0)); - // TODO: add a 3rd time zone dynamically, which is the default time zone for the current - // locale in question when iterating over all locales - List STATIC_TIME_ZONES = - List.of(TimeZone.GMT_ZONE, TimeZone.getTimeZone("Australia/Adelaide")); + //----------- + // end: manually defined dimensions of iteration value sets + //----------- - List STATIC_TIME_ZONE_ONE_ONLY = List.of(STATIC_TIME_ZONES.get(0)); + public static ImmutableSet getKernelTestCases() { // setup of return value @@ -1206,6 +1228,63 @@ public static ImmutableSet getKernelTestCases() { return builder.build(); } + public static boolean isCLDRLocaleAtLeastModern(String localeStr) { + // This is the CLDR "effective coverage level" + Level coverageLevel = + CalculatedCoverageLevels.getInstance() + .getEffectiveCoverageLevel(localeStr); + + return !(coverageLevel == null || !coverageLevel.isAtLeast(Level.MODERN)); + } + + public static ImmutableSet getAllTestCases() { + Set kernelSet = getKernelTestCases(); + + ImmutableSet.Builder newCasesBuilder = ImmutableSet.builder(); + + ICUServiceBuilder icuServiceBuilder = new ICUServiceBuilder(); + + + // append kernel to result builder + newCasesBuilder.addAll(kernelSet); + + + // iterate over all locales, cross each locale with kernel set, append to result builder + Set availableCLDRLanguages = CLDR_FACTORY.getAvailableLanguages(); + availableCLDRLanguages.stream() + .filter(GenerateDateTimeTestData::isCLDRLocaleAtLeastModern) + .map(locStr -> new ULocale(locStr)) + .sequential() // cannot go parallel when used shared object ICUServiceBuilder + .filter(Objects::nonNull) + .forEach(locale -> { + String locName = locale.getName(); + CLDRFile cldrFile = getCLDRFile(locName).orElse(null); + if (cldrFile == null) { + return; + } + icuServiceBuilder.clearCache(); + icuServiceBuilder.setCldrFile(cldrFile); + kernelSet.stream() + .map(testCase -> testCase.testCaseInput) + .map(testCaseInput -> { + // manually create a "deep copy" object to avoid unwanted mutation + TestCaseInput newInput = new TestCaseInput(); + // override locale + testCaseInput.locale = locale; + // copy over all other fields + newInput.timeZone = testCaseInput.timeZone; + newInput.fieldStyleCombo = testCaseInput.fieldStyleCombo; + newInput.dateTime = testCaseInput.dateTime; + newInput.calendar = testCaseInput.calendar; + return newInput; + }) + .map(testCaseInput -> computeTestCase(icuServiceBuilder, cldrFile, testCaseInput)) + .forEach(newCasesBuilder::add); + }); + + return newCasesBuilder.build(); + } + /** * This struct class exists specifically to convert from the structured {@code TestCase} struct * class to one that is appropriate for de-/serializing (formatting & parsing), ex: to give it a @@ -1281,7 +1360,7 @@ public static void main(String[] args) throws IOException { try (TempPrintWriter pw = TempPrintWriter.openUTF8Writer( CLDRPaths.TEST_DATA + OUTPUT_SUBDIR, OUTPUT_FILENAME)) { - ImmutableSet testCases = getKernelTestCases(); + ImmutableSet testCases = getAllTestCases(); List testCaseSerdes = testCases.stream() .map(GenerateDateTimeTestData::convertTestCaseToSerialize)