Skip to content

Commit 27d8f20

Browse files
authored
Merge pull request #1461 from sillsdev/sp-2356-fix-flaky-date-tests
SP-2356: Fixed flaky DateTimeExtensionTests
2 parents 8c1f89c + 4de7a03 commit 27d8f20

File tree

2 files changed

+82
-23
lines changed

2 files changed

+82
-23
lines changed

SIL.Core.Tests/Extensions/DateTimeExtensionTests.cs

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -361,16 +361,18 @@ public void ParseModernPastDateTimePermissivelyWithException_WithThaiBuddhistCal
361361
[TestCase("dd/MM/yyyy")] // Thai/European-style numeric date, zero-padded (e.g. 14/05/2025)
362362
[TestCase("d/M/yyyy")] // Thai/European-style numeric date (e.g. 14/5/2025)
363363
[TestCase("d-M-yyyy")] // Thai/European-style numeric date with dashes (e.g. 14-5-2025)
364-
// Commenting out these test cases for now until they can be fixed.
365-
//[TestCase("d")] // Short date pattern (e.g. 14/5/2025)
366-
//[TestCase("M/d/yyyy")] // US-style numeric date (e.g. 5/14/2025)
367-
//[TestCase("M-d-yyyy")] // US-style numeric date with dashes (e.g. 5-14-2025)
368-
//[TestCase("MM/dd/yyyy")] // US-style numeric date, zero-padded (e.g. 05/14/2025)
369-
//[TestCase("MM-dd-yyyy")] // US-style numeric date with dashes, zero-padded (e.g. 05-14-2025)
370-
public void ParseDateTimePermissivelyWithException_NearFutureDatesWithThaiBuddhistCalendar_ReturnsDateWithPastYear(string inputFormat)
364+
[TestCase("d")] // Short date pattern (region-specific: 14/5/2025, 5/14/2025, 14/05/2025, etc.)
365+
[TestCase("M/d/yyyy")] // US-style numeric date (e.g. 5/14/2025)
366+
[TestCase("M-d-yyyy")] // US-style numeric date with dashes (e.g. 5-14-2025)
367+
[TestCase("MM/dd/yyyy")] // US-style numeric date, zero-padded (e.g. 05/14/2025)
368+
[TestCase("MM-dd-yyyy")] // US-style numeric date with dashes, zero-padded (e.g. 05-14-2025)
369+
public void ParseDateTimePermissivelyWithException_NearFutureDatesWithThaiBuddhistCalendar_ReturnsDateWithPastYear(
370+
string inputFormat)
371371
{
372-
var futureDate = DateTime.Today.AddDays(5);
373-
string input = futureDate.ToString(inputFormat);
372+
var futureDate = GetNextFutureDateWithPotentiallyAmbiguousDay(5);
373+
int maxDateOffset = (futureDate - DateTime.Today).Days - 1;
374+
var input = futureDate.ToString(inputFormat);
375+
Console.WriteLine($@"{nameof(input)} = {input}");
374376
int expectedYear = futureDate.Year - 543;
375377

376378
Exception isolatedTestException = null;
@@ -390,7 +392,7 @@ public void ParseDateTimePermissivelyWithException_NearFutureDatesWithThaiBuddhi
390392
Thread.CurrentThread.CurrentCulture = buddhistCulture;
391393

392394
var reasonableMin = new DateTime(1481, 1, 1);
393-
var reasonableMax = DateTime.Today + TimeSpan.FromDays(4);
395+
var reasonableMax = DateTime.Today.AddDays(maxDateOffset);
394396
result = input.ParseDateTimePermissivelyWithException(reasonableMin,
395397
reasonableMax);
396398
}
@@ -402,8 +404,25 @@ public void ParseDateTimePermissivelyWithException_NearFutureDatesWithThaiBuddhi
402404
thread.Start();
403405
thread.Join();
404406

407+
if (inputFormat == "d")
408+
{
409+
if (isolatedTestException != null)
410+
{
411+
Assert.Ignore("\"d\" test case (dependent on current culture) caused " +
412+
$"exception: {isolatedTestException.Message}. Input = {{input}}");
413+
}
414+
415+
if (result?.Year != expectedYear)
416+
{
417+
Assert.Ignore("\"d\" test case (dependent on current culture) year " +
418+
$"{result?.Year} != expected {expectedYear}. Input = {{input}}");
419+
}
420+
421+
return;
422+
}
423+
405424
Assert.That(isolatedTestException, Is.Null, "Test failed with unexpected exception");
406-
Assert.That(result?.Year, Is.EqualTo(expectedYear));
425+
Assert.That(result?.Year, Is.EqualTo(expectedYear), "Should have returned a past year");
407426
}
408427

409428
/// <summary>
@@ -418,16 +437,17 @@ public void ParseDateTimePermissivelyWithException_NearFutureDatesWithThaiBuddhi
418437
[TestCase("dd/MM/yyyy")] // Thai/European-style numeric date, zero-padded (e.g. 14/05/2025)
419438
[TestCase("d/M/yyyy")] // Thai/European-style numeric date (e.g. 14/5/2025)
420439
[TestCase("d-M-yyyy")] // Thai/European-style numeric date with dashes (e.g. 14-5-2025)
421-
// Commenting out these test cases for now until they can be fixed.
422-
//[TestCase("d")] // Short date pattern (e.g. 14/5/2025)
423-
//[TestCase("M/d/yyyy")] // US-style numeric date (e.g. 5/14/2025)
424-
//[TestCase("M-d-yyyy")] // US-style numeric date with dashes (e.g. 5-14-2025)
425-
//[TestCase("MM/dd/yyyy")] // US-style numeric date, zero-padded (e.g. 05/14/2025)
426-
//[TestCase("MM-dd-yyyy")] // US-style numeric date with dashes, zero-padded (e.g. 05-14-2025)
427-
public void ParsePastDateTimePermissivelyWithException_NearFutureDatesWithThaiBuddhistCalendar_ReturnsDateWithPastYear(string inputFormat)
440+
[TestCase("d")] // Short date pattern (region-specific: 14/5/2025, 5/14/2025, 14/05/2025)
441+
[TestCase("M/d/yyyy")] // US-style numeric date (e.g. 5/14/2025)
442+
[TestCase("M-d-yyyy")] // US-style numeric date with dashes (e.g. 5-14-2025)
443+
[TestCase("MM/dd/yyyy")] // US-style numeric date, zero-padded (e.g. 05/14/2025)
444+
[TestCase("MM-dd-yyyy")] // US-style numeric date with dashes, zero-padded (e.g. 05-14-2025)
445+
public void ParsePastDateTimePermissivelyWithException_NearFutureDatesWithThaiBuddhistCalendar_ReturnsDateWithPastYear(
446+
string inputFormat)
428447
{
429-
var futureDate = DateTime.Today.AddDays(2);
448+
var futureDate = GetNextFutureDateWithPotentiallyAmbiguousDay();
430449
var input = futureDate.ToString(inputFormat);
450+
Console.WriteLine($@"{nameof(input)} = {input}");
431451
var expectedYear = futureDate.Year - 543;
432452

433453
Exception isolatedTestException = null;
@@ -455,6 +475,23 @@ public void ParsePastDateTimePermissivelyWithException_NearFutureDatesWithThaiBu
455475
});
456476
thread.Start();
457477
thread.Join();
478+
479+
if (inputFormat == "d")
480+
{
481+
if (isolatedTestException != null)
482+
{
483+
Assert.Ignore("\"d\" test case (dependent on current culture) caused " +
484+
$"exception: {isolatedTestException.Message}. Input = {{input}}");
485+
}
486+
487+
if (result?.Year != expectedYear)
488+
{
489+
Assert.Ignore("\"d\" test case (dependent on current culture) year " +
490+
$"{result?.Year} != expected {expectedYear}. Input = {{input}}");
491+
}
492+
493+
return;
494+
}
458495

459496
Assert.That(isolatedTestException, Is.Null, "Test failed with unexpected exception");
460497
Assert.That(result?.Year, Is.EqualTo(expectedYear), "Should have returned a past year");
@@ -469,7 +506,8 @@ public void ParsePastDateTimePermissivelyWithException_NearFutureDatesWithThaiBu
469506
[TestCase("dddd, dd MMMM yyyy")] // Full long format (e.g. Wednesday, 14 May 2025)
470507
public void ParseDateTimePermissivelyWithException_NearFutureUSDatesWithThaiBuddhistCalendar_ReturnsDateWithFutureYear(string inputFormat)
471508
{
472-
var futureDate = DateTime.Today.AddDays(5);
509+
var futureDate = GetNextFutureDateWithPotentiallyAmbiguousDay(5);
510+
int maxDateOffset = (futureDate - DateTime.Today).Days - 1;
473511
string input = futureDate.ToString(inputFormat);
474512
int expectedYear = futureDate.Year;
475513

@@ -490,7 +528,7 @@ public void ParseDateTimePermissivelyWithException_NearFutureUSDatesWithThaiBudd
490528
Thread.CurrentThread.CurrentCulture = buddhistCulture;
491529

492530
var reasonableMin = new DateTime(1900, 1, 1);
493-
var reasonableMax = DateTime.Today + TimeSpan.FromDays(4);
531+
var reasonableMax = DateTime.Today.AddDays(maxDateOffset);
494532
result = input.ParseDateTimePermissivelyWithException(reasonableMin,
495533
reasonableMax);
496534
}
@@ -516,7 +554,7 @@ public void ParseDateTimePermissivelyWithException_NearFutureUSDatesWithThaiBudd
516554
[TestCase("dddd, dd MMMM yyyy")] // Full long format (e.g. Wednesday, 14 May 2025)
517555
public void ParsePastDateTimePermissivelyWithException_NearFutureUSDatesWithThaiBuddhistCalendar_ReturnsDateWithFutureYear(string inputFormat)
518556
{
519-
var futureDate = DateTime.Today.AddDays(2);
557+
var futureDate = GetNextFutureDateWithPotentiallyAmbiguousDay();
520558
string input = futureDate.ToString(inputFormat);
521559
int expectedYear = futureDate.Year;
522560

@@ -550,6 +588,25 @@ public void ParsePastDateTimePermissivelyWithException_NearFutureUSDatesWithThai
550588
Assert.That(result?.Year, Is.EqualTo(expectedYear));
551589
}
552590

591+
/// <summary>
592+
/// Helper method to find the next "near" future date with a day number less than or equal
593+
/// to 12, such that it that could potentially be mistaken for a month number if the date
594+
/// format is ambiguous.
595+
/// </summary>
596+
/// <param name="minDaysIntoFuture">Number of days in the future to start looking for a
597+
/// "near" date. Pass 2 or greater to avoid possible edge cases related to time zones.
598+
/// </param>
599+
private static DateTime GetNextFutureDateWithPotentiallyAmbiguousDay(int minDaysIntoFuture = 2)
600+
{
601+
var date = DateTime.Today.AddDays(minDaysIntoFuture);
602+
if (date.Day > 12)
603+
{
604+
var nextMonth = date.AddMonths(1);
605+
date = new DateTime(nextMonth.Year, nextMonth.Month, 1);
606+
}
607+
return date;
608+
}
609+
553610
[TestCase("19/10/2025 0:00:00", ExpectedResult = "2025-10-19")]
554611
[TestCase("14/4/1482", ExpectedResult = "1482-04-14")]
555612
[TestCase("13/3/1800 0:01:00", ExpectedResult = "1800-03-13")]

SIL.Core/Extensions/DateTimeExtensions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,9 @@ private static bool TryParseWithTheseCultures(string when, DateTime reasonableMi
203203
return true;
204204
}
205205

206-
// Try switching calendar
206+
// Try switching to Thai/Buddhist calendar. Note that other calendars (Hijri,
207+
// Hebrew, etc.) could also be tried, in order of likelihood, but we have never
208+
// seen evidence of data suggesting that it is necessary.
207209
var altCulture = (CultureInfo)cultureInfo.Clone();
208210
var originalCalendar = altCulture.DateTimeFormat.Calendar;
209211
try

0 commit comments

Comments
 (0)