using System.Globalization;
using FluentAssertions;
using IBKRTrader.Core.Analytics;
using IBKRTrader.Core.Persistence.Entities;
using IBKRTrader.Core.Trading;
namespace IBKRTrader.Tests.Trading;
///
/// Zahlen und Zeitpunkte, die in Logs, Dossiers oder in die Datenbank gehen, dürfen nicht an der
/// Kultur des Hosts hängen. Wir betreiben Instanzen in EU und US und vergleichen deren Ausgaben
/// miteinander – "373,67" auf der einen und "373.67" auf der anderen wäre dasselbe Ereignis in
/// zwei Schreibweisen.
///
/// Die Tests setzen bewusst eine Kultur mit Dezimalkomma und prüfen, dass sich davon nichts
/// beeindrucken lässt. Der laufende Prozess stellt zusätzlich die invariante Kultur ein
/// (AppHostBuilder), aber genau darauf soll sich der einzelne Codepfad nicht verlassen.
///
[Trait("cat", "unit")]
public class CultureIndependenceTests
{
/// Führt die Prüfung unter einer Kultur mit Dezimalkomma aus.
private static void UnderGermanCulture(Action assert)
{
var previous = CultureInfo.CurrentCulture;
try
{
CultureInfo.CurrentCulture = new CultureInfo("de-DE");
assert();
}
finally
{
CultureInfo.CurrentCulture = previous;
}
}
private static BrokerPosition Position() => new()
{
Symbol = "GOOG",
SecType = "STK",
Currency = "USD",
ConId = 208813720,
Quantity = 10,
AvgCost = 373.67m
};
[Fact]
public void BrokerPosition_ToString_UsesInvariantNumbers()
{
UnderGermanCulture(() =>
Position().ToString().Should().Be("GOOG (STK) 10 @ 373.67 USD"));
}
[Fact]
public void BrokerExecution_ToString_UsesInvariantNumbers()
{
var execution = new BrokerExecution
{
ExecId = "0001",
Time = new DateTime(2026, 9, 3, 18, 26, 13, DateTimeKind.Utc),
Symbol = "AAPL",
SecType = "STK",
Side = TradeSide.Buy,
Quantity = 5,
Price = 327.27m
};
UnderGermanCulture(() =>
execution.ToString().Should().Be("2026-09-03 18:26:13 Buy 5x AAPL @ 327.27"));
}
[Fact]
public void Dossier_WritesInvariantNumbers()
{
var dossier = new TradeDossier(
SignalId: "sig-1",
Decisions: [],
OrderEvents: [],
Trades:
[
new CoreTrade
{
Module = "CT",
Symbol = "AAPL",
Action = "BUY",
Quantity = 3,
Price = 327.27m,
TotalValue = 981.81m,
Status = "Filled",
TradedAt = new DateTime(2026, 9, 3, 18, 26, 13, DateTimeKind.Utc)
}
],
LogLines: []);
UnderGermanCulture(() =>
{
var markdown = DossierBuilder.ToMarkdown(dossier);
markdown.Should().Contain("327.27").And.Contain("981.81");
markdown.Should().NotContain("327,27");
});
}
}