Logdateinamen haengen nicht mehr am Kalender der Host-Kultur
Im Logverzeichnis der Test-VM lagen neben 2026-09-03.jsonl auch 1405-06-12.jsonl und 2569-09-03.jsonl - dieselben Tage im Sonnen-Hidschra- und im buddhistischen Kalender. Eine interpolierte Zeichenkette formatiert mit CurrentCulture, und die bringt ihren Kalender mit. Betroffen waren beide Schreibpfade des LoggingService und die Lesestelle im DossierService, die denselben Namen wieder zusammensetzt. CA1305 greift hier nicht: die Regel sieht string.Format und ToString, nicht die interpolierte Form. Die .editorconfig deckt diesen Fall also nicht ab. FormattableString.Invariant an allen drei Stellen, dazu ein Regressionstest ueber fa-IR, th-TH und de-DE - mit Gegenbeweis, dass die naive Form tatsaechlich abweicht, damit der Test nicht eines Tages unbemerkt trivial wird. Ausserdem: Verweise auf die Bugtracker-Nummern richtiggestellt (488/489). 461 Tests gruen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -100,4 +100,54 @@ public class CultureIndependenceTests
|
||||
markdown.Should().NotContain("327,27");
|
||||
});
|
||||
}
|
||||
|
||||
// ─── Dateinamen (#489) ────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// Führt die Prüfung unter einer Kultur mit <b>anderem Kalender</b> aus. Das Dezimalkomma ist
|
||||
/// nur die halbe Gefahr: fa-IR rechnet im Sonnen-Hidschra-Kalender, th-TH im buddhistischen.
|
||||
/// </summary>
|
||||
private static void UnderCulture(string name, Action assert)
|
||||
{
|
||||
var previous = CultureInfo.CurrentCulture;
|
||||
try
|
||||
{
|
||||
CultureInfo.CurrentCulture = new CultureInfo(name);
|
||||
assert();
|
||||
}
|
||||
finally
|
||||
{
|
||||
CultureInfo.CurrentCulture = previous;
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("fa-IR")] // Sonnen-Hidschra: Jahr 1405 statt 2026
|
||||
[InlineData("th-TH")] // buddhistisch: Jahr 2569 statt 2026
|
||||
[InlineData("de-DE")]
|
||||
public void LogFileNames_DoNotDependOnTheHostCalendar(string culture)
|
||||
{
|
||||
// Am 2026-09-06 lagen auf der Test-VM neben 2026-09-06.jsonl auch 1405-06-12.jsonl und
|
||||
// 2569-09-03.jsonl. Eine interpolierte Zeichenkette formatiert mit CurrentCulture, und die
|
||||
// bringt ihren Kalender mit: Der Supervisor sucht dann eine Datei, die es nicht gibt, und
|
||||
// die Tagesrotation legt jeden Tag eine neue Reihe an.
|
||||
var day = new DateTime(2026, 9, 6, 14, 3, 0, DateTimeKind.Utc);
|
||||
|
||||
UnderCulture(culture, () =>
|
||||
{
|
||||
FormattableString.Invariant($"{day:yyyy-MM-dd}.jsonl").Should().Be("2026-09-06.jsonl");
|
||||
FormattableString.Invariant($"Info-{day:dd-MM-yy}.txt").Should().Be("Info-06-09-26.txt");
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TheNaiveInterpolation_IsWhatWentWrong()
|
||||
{
|
||||
// Der Gegenbeweis, damit dieser Test nicht versehentlich trivial wird: Ohne den
|
||||
// ausdruecklichen Formatanbieter geht es tatsaechlich schief. Faellt diese Zusicherung
|
||||
// eines Tages, ist die Gefahr weg - dann darf der Test verschwinden, nicht vorher.
|
||||
var day = new DateTime(2026, 9, 6, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
UnderCulture("fa-IR", () => $"{day:yyyy-MM-dd}".Should().NotBe("2026-09-06"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,10 +300,10 @@ public class ExecutionServiceTests
|
||||
Arg.Any<int>(), Arg.Any<decimal>(), Arg.Any<string>(), Arg.Any<string?>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
// ─── Die Order, die beim Broker liegt (#489) ─────────────────────────────
|
||||
// ─── Die Order, die beim Broker liegt (#488) ─────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// <b>Der Test, um den es bei #489 geht.</b> Am 2026-09-06 wurden 67 Orders bei geschlossener
|
||||
/// <b>Der Test, um den es bei #488 geht.</b> Am 2026-09-06 wurden 67 Orders bei geschlossener
|
||||
/// Börse angenommen und für Montag vorgemerkt, während der Adapter sie als abgelehnt meldete und
|
||||
/// jede Bindung freigegeben wurde. Das Geld war wieder im Topf, die Orders lebten weiter.
|
||||
/// </summary>
|
||||
@@ -346,7 +346,7 @@ public class ExecutionServiceTests
|
||||
public async Task RejectedOrder_StillReleasesTheCapital()
|
||||
{
|
||||
// Die Gegenprobe: Bei einer beweisbar abgelehnten Order MUSS das Geld zurück. Sonst hätte
|
||||
// der Fix aus #489 nur die eine Klemme gegen die andere getauscht.
|
||||
// der Fix aus #488 nur die eine Klemme gegen die andere getauscht.
|
||||
ArrangeHappyPath();
|
||||
_broker.PlaceOrderAsync(Arg.Any<OrderRequest>(), Arg.Any<CancellationToken>())
|
||||
.Returns(Task.FromResult(OrderResult.Fail("Order abgelehnt")));
|
||||
|
||||
@@ -397,7 +397,7 @@ public class IbkrMappingTests
|
||||
IbkrMapping.IsInformational(IbkrMapping.DelayedDataNotice).Should().BeTrue();
|
||||
}
|
||||
|
||||
// ─── Ordermeldungen (#489) ─────────────────────────────────────────
|
||||
// ─── Ordermeldungen (#488) ─────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// Der Fehler, der 67 Orders unsichtbar gemacht hat: IBKR schickt unter Code 399 Hinweise zu
|
||||
|
||||
Reference in New Issue
Block a user