Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Apple-Mobile][Globalization] Refactoring of CalendarData.iOS and new DateTimeFormatInfo* tests #102464

Merged
merged 19 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,12 @@ internal static unsafe bool EnumCalendarInfo(string localeName, CalendarId calen
#pragma warning disable CS8500 // takes address of managed type
private static unsafe bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, IcuEnumCalendarsData* callbackContext)
{
#if TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
callbackContext->Results.AddRange(GetCalendarInfoNative(localeName, calendarId, dataType).Split("||"));
return callbackContext->Results.Count > 0;
matouskozak marked this conversation as resolved.
Show resolved Hide resolved
#else
return Interop.Globalization.EnumCalendarInfo(&EnumCalendarInfoCallback, localeName, calendarId, dataType, (IntPtr)callbackContext);
#endif
}
#pragma warning restore CS8500

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,15 @@ private bool LoadCalendarDataFromNative(string localeName, CalendarId calendarId

sNativeName = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.NativeName);
sMonthDay = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.MonthDay);
saShortDates = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.ShortDates).Split("||");
// Handle ShortDatePattern to have "yyyy" year format
List<string> shortDatePatternList = new List<string>(saShortDates);
for (int i = 0; i < shortDatePatternList.Count; i++)
{
shortDatePatternList[i] = NormalizeDatePattern(shortDatePatternList[i]);
}
FixDefaultShortDatePattern(shortDatePatternList);
saShortDates = shortDatePatternList.ToArray();

saLongDates = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.LongDates).Split("||");
saYearMonths = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.YearMonths).Split("||");
saDayNames = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.DayNames).Split("||");
saAbbrevDayNames = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.AbbrevDayNames).Split("||");
saSuperShortDayNames = GetCalendarInfoNative(localeName, calendarId, CalendarDataType.SuperShortDayNames).Split("||");
EnumDatePatterns(localeName, calendarId, CalendarDataType.ShortDates, out this.saShortDates!);
EnumDatePatterns(localeName, calendarId, CalendarDataType.LongDates, out this.saLongDates!);
EnumDatePatterns(localeName, calendarId, CalendarDataType.YearMonths, out this.saYearMonths!);
EnumCalendarInfo(localeName, calendarId, CalendarDataType.DayNames, out this.saDayNames!);
EnumCalendarInfo(localeName, calendarId, CalendarDataType.AbbrevDayNames, out this.saAbbrevDayNames!);
EnumCalendarInfo(localeName, calendarId, CalendarDataType.SuperShortDayNames, out this.saSuperShortDayNames!);

string? leapHebrewMonthName = null;
saMonthNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.MonthNames).Split("||"), calendarId, ref leapHebrewMonthName);
EnumMonthNames(localeName, calendarId, CalendarDataType.MonthNames, out this.saMonthNames!, ref leapHebrewMonthName);
if (leapHebrewMonthName != null)
{
Debug.Assert(saMonthNames != null);
Expand All @@ -51,62 +42,19 @@ private bool LoadCalendarDataFromNative(string localeName, CalendarId calendarId
saMonthNames[6] = leapHebrewMonthName;

}
saAbbrevMonthNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.AbbrevMonthNames).Split("||"), calendarId, ref leapHebrewMonthName);
saMonthGenitiveNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.MonthGenitiveNames).Split("||"), calendarId, ref leapHebrewMonthName);
saAbbrevMonthGenitiveNames = NormalizeMonthArray(GetCalendarInfoNative(localeName, calendarId, CalendarDataType.AbbrevMonthGenitiveNames).Split("||"), calendarId, ref leapHebrewMonthName);
EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthNames, out this.saAbbrevMonthNames!, ref leapHebrewMonthName);
EnumMonthNames(localeName, calendarId, CalendarDataType.MonthGenitiveNames, out this.saMonthGenitiveNames!, ref leapHebrewMonthName);
EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthGenitiveNames, out this.saAbbrevMonthGenitiveNames!, ref leapHebrewMonthName);

saEraNames = NormalizeEraNames(calendarId, GetCalendarInfoNative(localeName, calendarId, CalendarDataType.EraNames).Split("||"));
saAbbrevEraNames = Array.Empty<string>();
EnumEraNames(localeName, calendarId, CalendarDataType.EraNames, out this.saEraNames!);
EnumEraNames(localeName, calendarId, CalendarDataType.AbbrevEraNames, out this.saAbbrevEraNames!);

return sNativeName != null && saShortDates != null && saLongDates != null && saYearMonths != null &&
saDayNames != null && saAbbrevDayNames != null && saSuperShortDayNames != null && saMonthNames != null &&
saAbbrevMonthNames != null && saMonthGenitiveNames != null && saAbbrevMonthGenitiveNames != null &&
saEraNames != null && saAbbrevEraNames != null;
mkhamoyan marked this conversation as resolved.
Show resolved Hide resolved
}

private static string[] NormalizeEraNames(CalendarId calendarId, string[]? eraNames)
{
// .NET expects that only the Japanese calendars have more than 1 era.
// So for other calendars, only return the latest era.
if (calendarId != CalendarId.JAPAN && calendarId != CalendarId.JAPANESELUNISOLAR && eraNames?.Length > 0)
return new string[] { eraNames![eraNames.Length - 1] };

return eraNames ?? Array.Empty<string>();
}

private static string[] NormalizeMonthArray(string[] months, CalendarId calendarId, ref string? leapHebrewMonthName)
{
if (months.Length == 13)
return months;

string[] normalizedMonths = new string[13];
// the month-name arrays are expected to have 13 elements. If only returns 12, add an
// extra empty string to fill the array.
if (months.Length == 12)
{
normalizedMonths[12] = "";
months.CopyTo(normalizedMonths, 0);
return normalizedMonths;
}

if (months.Length > 13)
{
Debug.Assert(calendarId == CalendarId.HEBREW && months.Length == 14);

if (calendarId == CalendarId.HEBREW)
{
leapHebrewMonthName = months[13];
}
for (int i = 0; i < 13; i++)
{
normalizedMonths[i] = months[i];
}
return normalizedMonths;
}

throw new Exception("CalendarData.GetCalendarInfoNative() returned an unexpected number of month names.");
}

private static string GetCalendarInfoNative(string localeName, CalendarId calendarId, CalendarDataType calendarDataType)
{
Debug.Assert(localeName != null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ public static IEnumerable<object[]> AbbreviatedDayNames_Set_TestData()
yield return new object[] { new string[] { "", "", "", "", "", "", "" } };
}

public static IEnumerable<object[]> AbbreviatedDayNames_Get_TestData_ICU()
{
yield return new object[] { new CultureInfo("en-US").DateTimeFormat, new string[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }, "en-US" };
matouskozak marked this conversation as resolved.
Show resolved Hide resolved
yield return new object[] { new CultureInfo("fr-FR").DateTimeFormat, new string[] { "dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam." }, "fr-FR" };
}

public static IEnumerable<object[]> AbbreviatedDayNames_Get_TestData_HybridGlobalization()
{
// see the comments on the right to check the non-Hybrid result, if it differs
Expand Down Expand Up @@ -86,6 +92,16 @@ public static IEnumerable<object[]> AbbreviatedDayNames_Get_TestData_HybridGloba
yield return new object[] { "zh-CN", new string[] { "周日", "周一", "周二", "周三", "周四", "周五", "周六" } };
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))]
[MemberData(nameof(AbbreviatedDayNames_Get_TestData_ICU))]
public void AbbreviatedDayNames_Get_ReturnsExpected_ICU(DateTimeFormatInfo format, string[] expected, string cultureName)
{
string[] result = format.AbbreviatedDayNames;
Assert.True(result.Length == expected.Length, $"Length comparison failed for culture: {cultureName}. Expected: {expected.Length}, Actual: {result.Length}");
for (int i = 0; i<result.Length; i++)
Assert.True(expected[i] == result[i], $"Failed for culture: {cultureName} on index: {i}. Expected: {expected[i]}, Actual: {result[i]}");
matouskozak marked this conversation as resolved.
Show resolved Hide resolved
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnBrowser))]
[MemberData(nameof(AbbreviatedDayNames_Get_TestData_HybridGlobalization))]
public void AbbreviatedDayNames_Get_ReturnsExpected_HybridGlobalization(string cultureName, string[] expected)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ namespace System.Globalization.Tests
{
public class DateTimeFormatInfoAbbreviatedMonthGenitiveNames
{
public static IEnumerable<object[]> AbbreviatedMonthGenitiveNames_Get_TestData_ICU()
{
yield return new object[] { new CultureInfo("en-US").DateTimeFormat, new string[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "" }, "en-US" };
yield return new object[] { new CultureInfo("fr-FR").DateTimeFormat, new string[] { "janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", "" }, "fr-FR" };
}
public static IEnumerable<object[]> AbbreviatedMonthGenitiveNames_Get_TestData_HybridGlobalization()
{
// see the comments on the right to check the non-Hybrid result, if it differs
Expand Down Expand Up @@ -209,6 +214,16 @@ public static IEnumerable<object[]> AbbreviatedMonthGenitiveNames_Get_TestData_H
yield return new object[] { "zh-TW", new string[] { "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月", "" } };
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))]
[MemberData(nameof(AbbreviatedMonthGenitiveNames_Get_TestData_ICU))]
public void AbbreviatedMonthGenitiveNames_Get_ReturnsExpected_ICU(DateTimeFormatInfo format, string[] expected, string cultureName)
{
var actual = format.AbbreviatedMonthGenitiveNames;
Assert.True(actual.Length == expected.Length, $"Length comparison failed for culture: {cultureName}. Expected: {expected.Length}, Actual: {actual.Length}");
for (int i = 0; i < actual.Length; i++)
Assert.True(expected[i] == actual[i], $"Failed for culture: {cultureName} on index: {i}. Expected: {expected[i]}, Actual: {actual[i]}");
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnBrowser))]
[MemberData(nameof(AbbreviatedMonthGenitiveNames_Get_TestData_HybridGlobalization))]
public void AbbreviatedMonthGenitiveNames_Get_ReturnsExpected_HybridGlobalization(string cultureName, string[] expected)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ public static IEnumerable<object[]> AbbreviatedMonthNames_Set_TestData()
yield return new object[] { new string[] { "", "", "", "", "", "", "", "", "", "", "", "", "" } };
}

public static IEnumerable<object[]> AbbreviatedMonthNames_Get_TestData_ICU()
{
yield return new object[] { new CultureInfo("en-US").DateTimeFormat, new string[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "" }, "en-US" };
yield return new object[] { new CultureInfo("fr-FR").DateTimeFormat, new string[] { "janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc.", "" }, "fr-FR" };
}


public static IEnumerable<object[]> AbbreviatedMonthNames_Get_TestData_HybridGlobalization()
{
// see the comments on the right to check the non-Hybrid result, if it differs
Expand Down Expand Up @@ -232,6 +239,16 @@ public static IEnumerable<object[]> AbbreviatedMonthNames_Get_TestData_HybridGlo
yield return new object[] { "zh-TW", new string[] { "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月", "" } };
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))]
[MemberData(nameof(AbbreviatedMonthNames_Get_TestData_ICU))]
public void AbbreviatedMonthNames_Get_ReturnsExpected_ICU(DateTimeFormatInfo format, string[] expected, string cultureName)
{
var actual = format.AbbreviatedMonthNames;
Assert.True(actual.Length == expected.Length, $"Length comparison failed for culture: {cultureName}. Expected: {expected.Length}, Actual: {actual.Length}");
for (int i = 0; i < actual.Length; i++)
Assert.True(expected[i] == actual[i], $"Failed for culture: {cultureName} on index: {i}. Expected: {expected[i]}, Actual: {actual[i]}");
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnBrowser))]
[MemberData(nameof(AbbreviatedMonthNames_Get_TestData_HybridGlobalization))]
public void AbbreviatedMonthNames_Get_ReturnsExpected_HybridGlobalization(string cultureName, string[] expected)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ public static IEnumerable<object[]> DayNames_Set_TestData()
yield return new object[] { new string[] { "", "", "", "", "", "", "" } };
}

public static IEnumerable<object[]> DayNames_Get_TestData_ICU()
{
yield return new object[] { new CultureInfo("en-US").DateTimeFormat, new string[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }, "en-US" };
yield return new object[] { new CultureInfo("fr-FR").DateTimeFormat, new string[] { "dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi" }, "fr-FR" };
}

public static IEnumerable<object[]> DayNames_Get_TestData_HybridGlobalization()
{
yield return new object[] { "ar-SA", new string[] { "الأحد", "الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت" } };
Expand Down Expand Up @@ -78,6 +84,16 @@ public static IEnumerable<object[]> DayNames_Get_TestData_HybridGlobalization()
yield return new object[] { "zh-TW", new string[] { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" } };
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))]
[MemberData(nameof(DayNames_Get_TestData_ICU))]
public void DayNames_Get_ReturnsExpected_ICU(DateTimeFormatInfo format, string[] expected, string cultureName)
{
string[] result = format.DayNames;
Assert.True(result.Length == expected.Length, $"Length comparison failed for culture: {cultureName}. Expected: {expected.Length}, Actual: {result.Length}");
for (int i = 0; i<result.Length; i++)
Assert.True(expected[i] == result[i], $"Failed for culture: {cultureName} on index: {i}. Expected: {expected[i]}, Actual: {result[i]}");
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnBrowser))]
[MemberData(nameof(DayNames_Get_TestData_HybridGlobalization))]
public void DayNames_Get_ReturnsExpected_HybridGlobalization(string cultureName, string[] expected)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ public static IEnumerable<object[]> LongDatePattern_Set_TestData()
yield return new object[] { "dddd, dd MMMM yyyy" };
}

public static IEnumerable<object[]> LongDatePattern_Get_TestData_ICU()
{
yield return new object[] { new CultureInfo("en-US").DateTimeFormat, "dddd, MMMM d, yyyy", "en-US" };
yield return new object[] { new CultureInfo("fr-FR").DateTimeFormat, "dddd d MMMM yyyy", "fr-FR" };
}

public static IEnumerable<object[]> LongDatePattern_Get_TestData_HybridGlobalization()
{
// see the comments on the right to check the non-Hybrid result, if it differs
Expand Down Expand Up @@ -218,6 +224,14 @@ public static IEnumerable<object[]> LongDatePattern_Get_TestData_HybridGlobaliza
yield return new object[] {"zh-TW", "yyyy年M月d日 dddd" };
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))]
[MemberData(nameof(LongDatePattern_Get_TestData_ICU))]
public void LongDatePattern_Get_ReturnsExpected_ICU(DateTimeFormatInfo format, string expected, string cultureName)
{
var result = format.LongDatePattern;
Assert.True(expected == result, $"Failed for {cultureName}, Expected: \"{expected}\", Actual: \"{result}\"");
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnBrowser))]
[MemberData(nameof(LongDatePattern_Get_TestData_HybridGlobalization))]
public void LongDatePattern_Get_ReturnsExpected_HybridGlobalization(string cultureName, string expected)
Expand Down
Loading
Loading