Fixed the last remaining failing test cases having to do with genitive month names. Turned out to be a bug in the .NET Framework that the test code now accomodates for.

This commit is contained in:
Daniel Stolt
2014-07-29 19:30:00 +02:00
parent 943d0f0e1b
commit 387425deb9
2 changed files with 25 additions and 11 deletions

View File

@@ -241,14 +241,6 @@ namespace Orchard.Framework.Tests.Localization {
var allCultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
Parallel.ForEach(allCultures, options, culture => { // All cultures on the machine.
//if (culture.Name.StartsWith("ca")
// || culture.Name.StartsWith("es")
// || culture.Name.StartsWith("mn")
// || culture.Name.StartsWith("oc")
// || culture.Name.StartsWith("wo")
// )
// return;
var container = InitializeContainer(culture.Name, "GregorianCalendar");
var formats = container.Resolve<IDateTimeFormatProvider>();
var target = container.Resolve<IDateFormatter>();
@@ -270,6 +262,20 @@ namespace Orchard.Framework.Tests.Localization {
try {
var result = target.FormatDate(dateParts, dateFormat);
var expected = date.ToString(dateFormat, cultureGregorian);
if (result != expected) {
// The .NET date formatting logic contains a bug that causes it to recognize 'd' and 'dd'
// as numerical day specifiers even when they are embedded in literals. Our implementation
// does not contain this bug. If we encounter an unexpected result and the .NET reference
// result contains the genitive month name, replace it with the non-genitive month name
// before asserting.
var numericalDayPattern = @"(\b|[^d])d{1,2}(\b|[^d])";
var containsNumericalDay = Regex.IsMatch(dateFormat, numericalDayPattern);
if (containsNumericalDay) {
var monthName = formats.MonthNames[month - 1];
var monthNameGenitive = formats.MonthNamesGenitive[month - 1];
expected = expected.Replace(monthNameGenitive, monthName);
}
}
Assert.AreEqual(expected, result);
}
catch (Exception ex) {

View File

@@ -113,8 +113,7 @@ namespace Orchard.Localization.Services {
}
public virtual string FormatDate(DateParts parts, string format) {
var formatWithoutLiterals = Regex.Replace(format, @"(?<!\\)'(.*?)(?<!\\)'|(?<!\\)""(.*?)(?<!\\)""", "");
var useMonthNameGenitive = formatWithoutLiterals.Contains('d'); // Use genitive month names if format contains a day component.
var useMonthNameGenitive = GetUseGenitiveMonthName(format);
var replacements = GetDateFormatReplacements(useMonthNameGenitive);
var formatString = ConvertToFormatString(format, replacements);
@@ -247,6 +246,13 @@ namespace Orchard.Localization.Services {
return new TimeParts(hour, minute, second, millisecond);
}
protected virtual bool GetUseGenitiveMonthName(string format) {
// Use genitive month name if the format (excluding literals) contains a numerical day component (d or dd).
var formatWithoutLiterals = Regex.Replace(format, @"(?<!\\)'(.*?)(?<!\\)'|(?<!\\)""(.*?)(?<!\\)""", "");
var numericalDayPattern = @"(\b|[^d])d{1,2}(\b|[^d])";
return Regex.IsMatch(formatWithoutLiterals, numericalDayPattern);
}
protected virtual Dictionary<string, string> GetDateParseReplacements() {
return new Dictionary<string, string>() {
{"dddd", String.Format("(?<dayName>{0})", String.Join("|", _dateTimeFormatProvider.DayNames.Select(x => EscapeForRegex(x))))},
@@ -297,7 +303,9 @@ namespace Orchard.Localization.Services {
{"dd", "{7:00}"},
{"d", "{7:##}"},
{"MMMM", useMonthNameGenitive ? "{5:MMMM}" : "{3:MMMM}"},
{"MMM", useMonthNameGenitive ? "{6:MMM}" : "{4:MMM}"},
// The .NET formatting logic never uses the abbreviated genitive month name; doing the same for compatibility.
//{"MMM", useMonthNameGenitive ? "{6:MMM}" : "{4:MMM}"},
{"MMM", "{4:MMM}"},
{"MM", "{2:00}"},
{"M", "{2:##}"},
{"yyyyy", "{0:00000}"},