fix(worker): guard timestamp-format derivation against pathological culture patterns
This commit is contained in:
@@ -303,6 +303,55 @@ public sealed class MxAccessEventMapperTests
|
||||
Assert.Equal(DateTime.SpecifyKind(localWall, DateTimeKind.Local).ToUniversalTime(), utc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies format derivation survives a culture whose long-time pattern
|
||||
/// hides an "ss" inside quoted literal text — the case where blindly
|
||||
/// inserting ".fff" at the first "ss" produces a format that mangles the
|
||||
/// value or is outright malformed, and a malformed format makes exact
|
||||
/// parsing throw rather than report failure. Derivation must reject such
|
||||
/// a candidate at build time, so parsing here stays exception-free and
|
||||
/// the culture's own published shape still reads as local wall-clock
|
||||
/// time. Uses a culture no other test touches, because the format cache
|
||||
/// compares cultures by name.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void TryParseSourceTimestamp_WithLiteralSecondsInCulturePattern_ParsesWithoutThrowing()
|
||||
{
|
||||
CultureInfo pathological = new("en-ZA")
|
||||
{
|
||||
DateTimeFormat =
|
||||
{
|
||||
ShortDatePattern = "M/d/yyyy",
|
||||
LongTimePattern = "'sss' HH:mm:ss",
|
||||
},
|
||||
};
|
||||
|
||||
CultureInfo original = CultureInfo.CurrentCulture;
|
||||
try
|
||||
{
|
||||
CultureInfo.CurrentCulture = pathological;
|
||||
DateTime localWall = new(2026, 3, 26, 13, 38, 22, DateTimeKind.Unspecified);
|
||||
|
||||
// The culture's published shape: "3/26/2026 sss 13:38:22".
|
||||
string published = localWall.ToString(
|
||||
pathological.DateTimeFormat.ShortDatePattern + " " + pathological.DateTimeFormat.LongTimePattern,
|
||||
pathological);
|
||||
|
||||
Assert.True(MxAccessEventMapper.TryParseSourceTimestamp(published, out DateTime utc));
|
||||
Assert.Equal(DateTimeKind.Utc, utc.Kind);
|
||||
Assert.Equal(DateTime.SpecifyKind(localWall, DateTimeKind.Local).ToUniversalTime(), utc);
|
||||
|
||||
// Shapes this culture cannot describe must still fail quietly rather
|
||||
// than throw out of the derived formats.
|
||||
Assert.False(MxAccessEventMapper.TryParseSourceTimestamp("not a timestamp", out _));
|
||||
Assert.False(MxAccessEventMapper.TryParseSourceTimestamp("sss sss sss", out _));
|
||||
}
|
||||
finally
|
||||
{
|
||||
CultureInfo.CurrentCulture = original;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The parse chain exactly as it stood before PERF-20 added the
|
||||
/// exact-format stage, used as the parity oracle above.
|
||||
|
||||
Reference in New Issue
Block a user