1
0
Fork 0
firefox/intl/components/gtest/TestDateTimeFormat.cpp
Daniel Baumann 5e9a113729
Adding upstream version 140.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-25 09:37:52 +02:00

691 lines
23 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gtest/gtest.h"
#include "mozilla/intl/Calendar.h"
#include "mozilla/intl/DateTimeFormat.h"
#include "mozilla/intl/DateTimePart.h"
#include "mozilla/intl/DateTimePatternGenerator.h"
#include "mozilla/Span.h"
#include "TestBuffer.h"
#include <string_view>
namespace mozilla::intl {
// Firefox 1.0 release date.
const double DATE = 1032800850000.0;
static UniquePtr<DateTimeFormat> testStyle(
const char* aLocale, DateTimeFormat::StyleBag& aStyleBag) {
// Always specify a time zone in the tests, otherwise it will use the system
// time zone which can vary between test runs.
auto timeZone = Some(MakeStringSpan(u"GMT+3"));
auto gen = DateTimePatternGenerator::TryCreate("en").unwrap();
return DateTimeFormat::TryCreateFromStyle(MakeStringSpan(aLocale), aStyleBag,
gen.get(), timeZone)
.unwrap();
}
TEST(IntlDateTimeFormat, Style_enUS_utf8)
{
DateTimeFormat::StyleBag style;
style.date = Some(DateTimeFormat::Style::Medium);
style.time = Some(DateTimeFormat::Style::Medium);
auto dtFormat = testStyle("en-US", style);
TestBuffer<char> buffer;
dtFormat->TryFormat(DATE, buffer).unwrap();
ASSERT_TRUE(buffer.verboseMatches("Sep 23, 2002, 8:07:30 PM"));
}
TEST(IntlDateTimeFormat, Style_enUS_utf16)
{
DateTimeFormat::StyleBag style;
style.date = Some(DateTimeFormat::Style::Medium);
style.time = Some(DateTimeFormat::Style::Medium);
auto dtFormat = testStyle("en-US", style);
TestBuffer<char16_t> buffer;
dtFormat->TryFormat(DATE, buffer).unwrap();
ASSERT_TRUE(buffer.verboseMatches(u"Sep 23, 2002, 8:07:30 PM"));
}
TEST(IntlDateTimeFormat, Style_ar_utf8)
{
DateTimeFormat::StyleBag style;
style.time = Some(DateTimeFormat::Style::Medium);
auto dtFormat = testStyle("ar-EG", style);
TestBuffer<char> buffer;
dtFormat->TryFormat(DATE, buffer).unwrap();
ASSERT_TRUE(buffer.verboseMatches("٨:٠٧:٣٠ م"));
}
TEST(IntlDateTimeFormat, Style_ar_utf16)
{
DateTimeFormat::StyleBag style;
style.time = Some(DateTimeFormat::Style::Medium);
auto dtFormat = testStyle("ar-EG", style);
TestBuffer<char16_t> buffer;
dtFormat->TryFormat(DATE, buffer).unwrap();
ASSERT_TRUE(buffer.verboseMatches(u"٨:٠٧:٣٠ م"));
}
TEST(IntlDateTimeFormat, Style_enUS_fallback_to_default_styles)
{
DateTimeFormat::StyleBag style;
auto dtFormat = testStyle("en-US", style);
TestBuffer<char> buffer;
dtFormat->TryFormat(DATE, buffer).unwrap();
ASSERT_TRUE(buffer.verboseMatches("Sep 23, 2002, 8:07:30 PM"));
}
TEST(IntlDateTimeFormat, Time_zone_IANA_identifier)
{
auto gen = DateTimePatternGenerator::TryCreate("en").unwrap();
DateTimeFormat::StyleBag style;
style.date = Some(DateTimeFormat::Style::Medium);
style.time = Some(DateTimeFormat::Style::Medium);
auto dtFormat = DateTimeFormat::TryCreateFromStyle(
MakeStringSpan("en-US"), style, gen.get(),
Some(MakeStringSpan(u"America/Chicago")))
.unwrap();
TestBuffer<char> buffer;
dtFormat->TryFormat(DATE, buffer).unwrap();
ASSERT_TRUE(buffer.verboseMatches("Sep 23, 2002, 12:07:30 PM"));
}
TEST(IntlDateTimeFormat, GetAllowedHourCycles)
{
auto allowed_en_US = DateTimeFormat::GetAllowedHourCycles(
MakeStringSpan("en"), Some(MakeStringSpan("US")))
.unwrap();
ASSERT_TRUE(allowed_en_US.length() == 2);
ASSERT_EQ(allowed_en_US[0], DateTimeFormat::HourCycle::H12);
ASSERT_EQ(allowed_en_US[1], DateTimeFormat::HourCycle::H23);
auto allowed_de =
DateTimeFormat::GetAllowedHourCycles(MakeStringSpan("de"), Nothing())
.unwrap();
ASSERT_TRUE(allowed_de.length() == 2);
ASSERT_EQ(allowed_de[0], DateTimeFormat::HourCycle::H23);
ASSERT_EQ(allowed_de[1], DateTimeFormat::HourCycle::H12);
}
TEST(IntlDateTimePatternGenerator, GetBestPattern)
{
auto gen = DateTimePatternGenerator::TryCreate("en").unwrap();
TestBuffer<char16_t> buffer;
gen->GetBestPattern(MakeStringSpan(u"yMd"), buffer).unwrap();
ASSERT_TRUE(buffer.verboseMatches(u"M/d/y"));
}
TEST(IntlDateTimePatternGenerator, GetSkeleton)
{
auto gen = DateTimePatternGenerator::TryCreate("en").unwrap();
TestBuffer<char16_t> buffer;
DateTimePatternGenerator::GetSkeleton(MakeStringSpan(u"M/d/y"), buffer)
.unwrap();
ASSERT_TRUE(buffer.verboseMatches(u"yMd"));
}
TEST(IntlDateTimePatternGenerator, GetPlaceholderPattern)
{
auto gen = DateTimePatternGenerator::TryCreate("en").unwrap();
auto span = gen->GetPlaceholderPattern();
// The default date-time pattern for 'en' locale is u"{1}, {0}".
ASSERT_EQ(span, MakeStringSpan(u"{1}, {0}"));
}
// A utility function to help test the DateTimeFormat::ComponentsBag.
[[nodiscard]] bool FormatComponents(
TestBuffer<char16_t>& aBuffer, DateTimeFormat::ComponentsBag& aComponents,
Span<const char> aLocale = MakeStringSpan("en-US")) {
UniquePtr<DateTimePatternGenerator> gen = nullptr;
auto dateTimePatternGenerator =
DateTimePatternGenerator::TryCreate(aLocale.data()).unwrap();
auto dtFormat = DateTimeFormat::TryCreateFromComponents(
aLocale, aComponents, dateTimePatternGenerator.get(),
Some(MakeStringSpan(u"GMT+3")));
if (dtFormat.isErr()) {
fprintf(stderr, "Could not create a DateTimeFormat\n");
return false;
}
auto result = dtFormat.unwrap()->TryFormat(DATE, aBuffer);
if (result.isErr()) {
fprintf(stderr, "Could not format a DateTimeFormat\n");
return false;
}
return true;
}
TEST(IntlDateTimeFormat, Components)
{
DateTimeFormat::ComponentsBag components{};
components.year = Some(DateTimeFormat::Numeric::Numeric);
components.month = Some(DateTimeFormat::Month::Numeric);
components.day = Some(DateTimeFormat::Numeric::Numeric);
components.hour = Some(DateTimeFormat::Numeric::Numeric);
components.minute = Some(DateTimeFormat::Numeric::TwoDigit);
components.second = Some(DateTimeFormat::Numeric::TwoDigit);
TestBuffer<char16_t> buffer;
ASSERT_TRUE(FormatComponents(buffer, components));
ASSERT_TRUE(buffer.verboseMatches(u"9/23/2002, 8:07:30 PM"));
}
TEST(IntlDateTimeFormat, Components_es_ES)
{
DateTimeFormat::ComponentsBag components{};
components.year = Some(DateTimeFormat::Numeric::Numeric);
components.month = Some(DateTimeFormat::Month::Numeric);
components.day = Some(DateTimeFormat::Numeric::Numeric);
components.hour = Some(DateTimeFormat::Numeric::Numeric);
components.minute = Some(DateTimeFormat::Numeric::TwoDigit);
components.second = Some(DateTimeFormat::Numeric::TwoDigit);
TestBuffer<char16_t> buffer;
ASSERT_TRUE(FormatComponents(buffer, components, MakeStringSpan("es-ES")));
ASSERT_TRUE(buffer.verboseMatches(u"23/9/2002, 20:07:30"));
}
TEST(IntlDateTimeFormat, ComponentsAll)
{
// Use most all of the components.
DateTimeFormat::ComponentsBag components{};
components.era = Some(DateTimeFormat::Text::Short);
components.year = Some(DateTimeFormat::Numeric::Numeric);
components.month = Some(DateTimeFormat::Month::Numeric);
components.day = Some(DateTimeFormat::Numeric::Numeric);
components.weekday = Some(DateTimeFormat::Text::Short);
components.hour = Some(DateTimeFormat::Numeric::Numeric);
components.minute = Some(DateTimeFormat::Numeric::TwoDigit);
components.second = Some(DateTimeFormat::Numeric::TwoDigit);
components.timeZoneName = Some(DateTimeFormat::TimeZoneName::Short);
components.hourCycle = Some(DateTimeFormat::HourCycle::H24);
components.fractionalSecondDigits = Some(3);
TestBuffer<char16_t> buffer;
ASSERT_TRUE(FormatComponents(buffer, components));
ASSERT_TRUE(buffer.verboseMatches(u"Mon, 9 23, 2002 AD, 20:07:30.000 GMT+3"));
}
TEST(IntlDateTimeFormat, ComponentsHour12Default)
{
// Assert the behavior of the default "en-US" 12 hour time with day period.
DateTimeFormat::ComponentsBag components{};
components.hour = Some(DateTimeFormat::Numeric::Numeric);
components.minute = Some(DateTimeFormat::Numeric::Numeric);
TestBuffer<char16_t> buffer;
ASSERT_TRUE(FormatComponents(buffer, components));
ASSERT_TRUE(buffer.verboseMatches(u"8:07 PM"));
}
TEST(IntlDateTimeFormat, ComponentsHour24)
{
// Test the behavior of using 24 hour time to override the default of
// hour 12 with a day period.
DateTimeFormat::ComponentsBag components{};
components.hour = Some(DateTimeFormat::Numeric::Numeric);
components.minute = Some(DateTimeFormat::Numeric::Numeric);
components.hour12 = Some(false);
TestBuffer<char16_t> buffer;
ASSERT_TRUE(FormatComponents(buffer, components));
ASSERT_TRUE(buffer.verboseMatches(u"20:07"));
}
TEST(IntlDateTimeFormat, ComponentsHour12DayPeriod)
{
// Test the behavior of specifying a specific day period.
DateTimeFormat::ComponentsBag components{};
components.hour = Some(DateTimeFormat::Numeric::Numeric);
components.minute = Some(DateTimeFormat::Numeric::Numeric);
components.dayPeriod = Some(DateTimeFormat::Text::Long);
TestBuffer<char16_t> buffer;
ASSERT_TRUE(FormatComponents(buffer, components));
ASSERT_TRUE(buffer.verboseMatches(u"8:07 in the evening"));
}
const char* ToString(uint8_t b) { return "uint8_t"; }
const char* ToString(bool b) { return b ? "true" : "false"; }
template <typename T>
const char* ToString(Maybe<T> option) {
if (option) {
if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, uint8_t>) {
return ToString(*option);
} else {
return DateTimeFormat::ToString(*option);
}
}
return "Nothing";
}
template <typename T>
[[nodiscard]] bool VerboseEquals(T expected, T actual, const char* msg) {
if (expected != actual) {
fprintf(stderr, "%s\n Actual: %s\nExpected: %s\n", msg, ToString(actual),
ToString(expected));
return false;
}
return true;
}
// A testing utility for getting nice errors when ComponentsBags don't match.
[[nodiscard]] bool VerboseEquals(DateTimeFormat::ComponentsBag& expected,
DateTimeFormat::ComponentsBag& actual) {
// clang-format off
return
VerboseEquals(expected.era, actual.era, "Components do not match: bag.era") &&
VerboseEquals(expected.year, actual.year, "Components do not match: bag.year") &&
VerboseEquals(expected.month, actual.month, "Components do not match: bag.month") &&
VerboseEquals(expected.day, actual.day, "Components do not match: bag.day") &&
VerboseEquals(expected.weekday, actual.weekday, "Components do not match: bag.weekday") &&
VerboseEquals(expected.hour, actual.hour, "Components do not match: bag.hour") &&
VerboseEquals(expected.minute, actual.minute, "Components do not match: bag.minute") &&
VerboseEquals(expected.second, actual.second, "Components do not match: bag.second") &&
VerboseEquals(expected.timeZoneName, actual.timeZoneName, "Components do not match: bag.timeZoneName") &&
VerboseEquals(expected.hour12, actual.hour12, "Components do not match: bag.hour12") &&
VerboseEquals(expected.hourCycle, actual.hourCycle, "Components do not match: bag.hourCycle") &&
VerboseEquals(expected.dayPeriod, actual.dayPeriod, "Components do not match: bag.dayPeriod") &&
VerboseEquals(expected.fractionalSecondDigits, actual.fractionalSecondDigits, "Components do not match: bag.fractionalSecondDigits");
// clang-format on
}
// A utility function to help test the DateTimeFormat::ComponentsBag.
[[nodiscard]] bool ResolveComponentsBag(
DateTimeFormat::ComponentsBag& aComponentsIn,
DateTimeFormat::ComponentsBag* aComponentsOut,
Span<const char> aLocale = MakeStringSpan("en-US")) {
UniquePtr<DateTimePatternGenerator> gen = nullptr;
auto dateTimePatternGenerator =
DateTimePatternGenerator::TryCreate("en").unwrap();
auto dtFormat = DateTimeFormat::TryCreateFromComponents(
aLocale, aComponentsIn, dateTimePatternGenerator.get(),
Some(MakeStringSpan(u"GMT+3")));
if (dtFormat.isErr()) {
fprintf(stderr, "Could not create a DateTimeFormat\n");
return false;
}
auto result = dtFormat.unwrap()->ResolveComponents();
if (result.isErr()) {
fprintf(stderr, "Could not resolve the components\n");
return false;
}
*aComponentsOut = result.unwrap();
return true;
}
TEST(IntlDateTimeFormat, ResolvedComponentsDate)
{
DateTimeFormat::ComponentsBag input{};
{
input.year = Some(DateTimeFormat::Numeric::Numeric);
input.month = Some(DateTimeFormat::Month::Numeric);
input.day = Some(DateTimeFormat::Numeric::Numeric);
}
DateTimeFormat::ComponentsBag expected = input;
DateTimeFormat::ComponentsBag resolved{};
ASSERT_TRUE(ResolveComponentsBag(input, &resolved));
ASSERT_TRUE(VerboseEquals(expected, resolved));
}
TEST(IntlDateTimeFormat, ResolvedComponentsAll)
{
DateTimeFormat::ComponentsBag input{};
{
input.era = Some(DateTimeFormat::Text::Short);
input.year = Some(DateTimeFormat::Numeric::Numeric);
input.month = Some(DateTimeFormat::Month::Numeric);
input.day = Some(DateTimeFormat::Numeric::Numeric);
input.weekday = Some(DateTimeFormat::Text::Short);
input.hour = Some(DateTimeFormat::Numeric::Numeric);
input.minute = Some(DateTimeFormat::Numeric::TwoDigit);
input.second = Some(DateTimeFormat::Numeric::TwoDigit);
input.timeZoneName = Some(DateTimeFormat::TimeZoneName::Short);
input.hourCycle = Some(DateTimeFormat::HourCycle::H24);
input.fractionalSecondDigits = Some(3);
}
DateTimeFormat::ComponentsBag expected = input;
{
expected.hour = Some(DateTimeFormat::Numeric::TwoDigit);
expected.hourCycle = Some(DateTimeFormat::HourCycle::H24);
expected.hour12 = Some(false);
}
DateTimeFormat::ComponentsBag resolved{};
ASSERT_TRUE(ResolveComponentsBag(input, &resolved));
ASSERT_TRUE(VerboseEquals(expected, resolved));
}
TEST(IntlDateTimeFormat, ResolvedComponentsHourDayPeriod)
{
DateTimeFormat::ComponentsBag input{};
{
input.hour = Some(DateTimeFormat::Numeric::Numeric);
input.minute = Some(DateTimeFormat::Numeric::Numeric);
}
DateTimeFormat::ComponentsBag expected = input;
{
expected.minute = Some(DateTimeFormat::Numeric::TwoDigit);
expected.hourCycle = Some(DateTimeFormat::HourCycle::H12);
expected.hour12 = Some(true);
}
DateTimeFormat::ComponentsBag resolved{};
ASSERT_TRUE(ResolveComponentsBag(input, &resolved));
ASSERT_TRUE(VerboseEquals(expected, resolved));
}
TEST(IntlDateTimeFormat, ResolvedComponentsHour12)
{
DateTimeFormat::ComponentsBag input{};
{
input.hour = Some(DateTimeFormat::Numeric::Numeric);
input.minute = Some(DateTimeFormat::Numeric::Numeric);
input.hour12 = Some(false);
}
DateTimeFormat::ComponentsBag expected = input;
{
expected.hour = Some(DateTimeFormat::Numeric::TwoDigit);
expected.minute = Some(DateTimeFormat::Numeric::TwoDigit);
expected.hourCycle = Some(DateTimeFormat::HourCycle::H23);
expected.hour12 = Some(false);
}
DateTimeFormat::ComponentsBag resolved{};
ASSERT_TRUE(ResolveComponentsBag(input, &resolved));
ASSERT_TRUE(VerboseEquals(expected, resolved));
}
TEST(IntlDateTimeFormat, GetOriginalSkeleton)
{
// Demonstrate that the original skeleton and the resolved skeleton can
// differ.
DateTimeFormat::ComponentsBag components{};
components.month = Some(DateTimeFormat::Month::Narrow);
components.day = Some(DateTimeFormat::Numeric::TwoDigit);
const char* locale = "zh-Hans-CN";
auto dateTimePatternGenerator =
DateTimePatternGenerator::TryCreate(locale).unwrap();
auto result = DateTimeFormat::TryCreateFromComponents(
MakeStringSpan(locale), components, dateTimePatternGenerator.get(),
Some(MakeStringSpan(u"GMT+3")));
ASSERT_TRUE(result.isOk());
auto dtFormat = result.unwrap();
TestBuffer<char16_t> originalSkeleton;
auto originalSkeletonResult = dtFormat->GetOriginalSkeleton(originalSkeleton);
ASSERT_TRUE(originalSkeletonResult.isOk());
ASSERT_TRUE(originalSkeleton.verboseMatches(u"MMMMMdd"));
TestBuffer<char16_t> pattern;
auto patternResult = dtFormat->GetPattern(pattern);
ASSERT_TRUE(patternResult.isOk());
ASSERT_TRUE(pattern.verboseMatches(u"M月dd日"));
TestBuffer<char16_t> resolvedSkeleton;
auto resolvedSkeletonResult = DateTimePatternGenerator::GetSkeleton(
Span(pattern.data(), pattern.length()), resolvedSkeleton);
ASSERT_TRUE(resolvedSkeletonResult.isOk());
ASSERT_TRUE(resolvedSkeleton.verboseMatches(u"Mdd"));
}
TEST(IntlDateTimeFormat, GetAvailableLocales)
{
using namespace std::literals;
int32_t english = 0;
int32_t german = 0;
int32_t chinese = 0;
// Since this list is dependent on ICU, and may change between upgrades, only
// test a subset of the available locales.
for (const char* locale : DateTimeFormat::GetAvailableLocales()) {
if (locale == "en"sv) {
english++;
} else if (locale == "de"sv) {
german++;
} else if (locale == "zh"sv) {
chinese++;
}
}
// Each locale should be found exactly once.
ASSERT_EQ(english, 1);
ASSERT_EQ(german, 1);
ASSERT_EQ(chinese, 1);
}
TEST(IntlDateTimeFormat, TryFormatToParts)
{
auto dateTimePatternGenerator =
DateTimePatternGenerator::TryCreate("en").unwrap();
DateTimeFormat::ComponentsBag components;
components.year = Some(DateTimeFormat::Numeric::Numeric);
components.month = Some(DateTimeFormat::Month::TwoDigit);
components.day = Some(DateTimeFormat::Numeric::TwoDigit);
components.hour = Some(DateTimeFormat::Numeric::TwoDigit);
components.minute = Some(DateTimeFormat::Numeric::TwoDigit);
components.hour12 = Some(false);
UniquePtr<DateTimeFormat> dtFormat =
DateTimeFormat::TryCreateFromComponents(
MakeStringSpan("en-US"), components, dateTimePatternGenerator.get(),
Some(MakeStringSpan(u"GMT")))
.unwrap();
TestBuffer<char16_t> buffer;
mozilla::intl::DateTimePartVector parts;
auto result = dtFormat->TryFormatToParts(DATE, buffer, parts);
ASSERT_TRUE(result.isOk());
std::u16string_view strView = buffer.get_string_view();
ASSERT_EQ(strView, u"09/23/2002, 17:07");
auto getSubStringView = [strView, &parts](size_t index) {
size_t pos = index == 0 ? 0 : parts[index - 1].mEndIndex;
size_t count = parts[index].mEndIndex - pos;
return strView.substr(pos, count);
};
ASSERT_EQ(parts[0].mType, DateTimePartType::Month);
ASSERT_EQ(getSubStringView(0), u"09");
ASSERT_EQ(parts[1].mType, DateTimePartType::Literal);
ASSERT_EQ(getSubStringView(1), u"/");
ASSERT_EQ(parts[2].mType, DateTimePartType::Day);
ASSERT_EQ(getSubStringView(2), u"23");
ASSERT_EQ(parts[3].mType, DateTimePartType::Literal);
ASSERT_EQ(getSubStringView(3), u"/");
ASSERT_EQ(parts[4].mType, DateTimePartType::Year);
ASSERT_EQ(getSubStringView(4), u"2002");
ASSERT_EQ(parts[5].mType, DateTimePartType::Literal);
ASSERT_EQ(getSubStringView(5), u", ");
ASSERT_EQ(parts[6].mType, DateTimePartType::Hour);
ASSERT_EQ(getSubStringView(6), u"17");
ASSERT_EQ(parts[7].mType, DateTimePartType::Literal);
ASSERT_EQ(getSubStringView(7), u":");
ASSERT_EQ(parts[8].mType, DateTimePartType::Minute);
ASSERT_EQ(getSubStringView(8), u"07");
ASSERT_EQ(parts.length(), 9u);
}
TEST(IntlDateTimeFormat, SetStartTimeIfGregorian)
{
using namespace std::literals;
DateTimeFormat::StyleBag style{};
style.date = Some(DateTimeFormat::Style::Long);
auto timeZone = Some(MakeStringSpan(u"UTC"));
// Gregorian change date defaults to October 15, 1582 in ICU. Test with a date
// before the default change date, in this case January 1, 1582.
constexpr double FirstJanuary1582 = -12244089600000.0;
// One year expressed in milliseconds.
constexpr double oneYear = (365 * 24 * 60 * 60) * 1000.0;
// Test with and without explicit calendar. The start time of the calendar can
// only be adjusted for the Gregorian and the ISO-8601 calendar.
for (const char* locale : {
"en-US",
"en-US-u-ca-gregory",
"en-US-u-ca-iso8601",
}) {
auto gen = DateTimePatternGenerator::TryCreate(locale).unwrap();
auto dtFormat = DateTimeFormat::TryCreateFromStyle(
MakeStringSpan(locale), style, gen.get(), timeZone)
.unwrap();
const char* Jan01_1582;
const char* Jan01_1583;
if (locale == "en-US-u-ca-iso8601"sv) {
Jan01_1582 = "1582 January 1";
Jan01_1583 = "1583 January 1";
} else {
Jan01_1582 = "January 1, 1582";
Jan01_1583 = "January 1, 1583";
}
TestBuffer<char> buffer;
// Before the default Gregorian change date, but not interpreted in the
// Julian calendar, which is December 22, 1581. Instead interpreted in
// proleptic Gregorian calendar at January 1, 1582.
dtFormat->TryFormat(FirstJanuary1582, buffer).unwrap();
ASSERT_TRUE(buffer.verboseMatches(Jan01_1582));
// After default Gregorian change date, so January 1, 1583.
dtFormat->TryFormat(FirstJanuary1582 + oneYear, buffer).unwrap();
ASSERT_TRUE(buffer.verboseMatches(Jan01_1583));
}
}
TEST(IntlDateTimeFormat, GetTimeSeparator)
{
struct TestData {
const char* locale;
const char* numberingSystem;
const char16_t* expected;
} testData[] = {
{"root", "latn", u":"},
{"root", "arab", u":"},
{"root", "thai", u":"},
{"root", "arabext", u"٫"},
// English uses the same data as the root locale.
{"en", "latn", u":"},
{"en", "arab", u":"},
{"en", "thai", u":"},
{"en", "arabext", u"٫"},
// Spanish uses the same data as the root locale.
{"es", "latn", u":"},
{"es", "arab", u":"},
{"es", "thai", u":"},
{"es", "arabext", u"٫"},
// German (Austria) uses the same data as the root locale.
{"de-AT", "latn", u":"},
{"de-AT", "arab", u":"},
{"de-AT", "thai", u":"},
{"de-AT", "arabext", u"٫"},
// Danish has a different time separator for "latn".
{"da", "latn", u"."},
{"da", "arab", u":"},
{"da", "thai", u"."},
{"da", "arabext", u"٫"},
// Same time separator as Danish.
{"en-DK", "latn", u"."},
{"en-DK", "arab", u":"},
{"en-DK", "thai", u"."},
{"en-DK", "arabext", u"٫"},
// Norwegian overrides time separators for "arab" and "arabext".
{"no", "latn", u":"},
{"no", "arab", u"."},
{"no", "thai", u":"},
{"no", "arabext", u"."},
// Parent locale of Bokmål is Norwegian.
{"nb", "latn", u":"},
{"nb", "arab", u"."},
{"nb", "thai", u":"},
{"nb", "arabext", u"."},
// Farsi overrides the time separator for "arabext".
{"fa", "latn", u":"},
{"fa", "arab", u":"},
{"fa", "thai", u":"},
{"fa", "arabext", u":"},
};
for (const auto& data : testData) {
TestBuffer<char16_t> timeSeparator;
auto timeSeparatorResult = DateTimeFormat::GetTimeSeparator(
MakeStringSpan(data.locale), MakeStringSpan(data.numberingSystem),
timeSeparator);
ASSERT_TRUE(timeSeparatorResult.isOk());
ASSERT_TRUE(timeSeparator.verboseMatches(data.expected));
}
}
} // namespace mozilla::intl