using LehrerApp.Core.Models; using LehrerApp.Desktop.ViewModels.Planning; using Xunit; namespace LehrerApp.Desktop.Tests; public sealed class SchoolDayWeatherSummaryTests { private static readonly DateOnly Day = new(2026, 8, 24); [Fact] public void From_GewitterHatVorrangVorSturmUndRegen() { var snapshot = Snapshot( Hour(8, code: 61, rain: 2, gust: 70), Hour(10, code: 95, rain: 1, gust: 80)); var summary = SchoolDayWeatherSummary.From(snapshot, Day); Assert.Equal(SchoolDayWeatherKind.Thunderstorm, summary!.Kind); Assert.Equal("⛈️", summary.Symbol); } [Fact] public void From_BoeAbBeaufortAcht_WirdAlsSturmAngezeigt() { var summary = SchoolDayWeatherSummary.From(Snapshot(Hour(10, gust: 62)), Day); Assert.Equal(SchoolDayWeatherKind.Storm, summary!.Kind); Assert.Equal("💨", summary.Symbol); } [Fact] public void From_NaechtlicheBoeBeeinflusstSchultagNicht() { var snapshot = Snapshot(Hour(10, cloud: 10), Hour(23, gust: 90)); var summary = SchoolDayWeatherSummary.From(snapshot, Day); Assert.Equal(20, summary!.MaxWindGustKmh); Assert.Equal(SchoolDayWeatherKind.Sunny, summary!.Kind); } [Fact] public void From_VerwendetFuerKennzahlenNurAchtBisSechzehnUhr() { var snapshot = Snapshot( Hour(7, temperature: 5, rain: 3, probability: 95, sunshineMinutes: 0), Hour(8, temperature: 12, probability: 20, sunshineMinutes: 30), Hour(16, temperature: 17, probability: 65, sunshineMinutes: 45), Hour(17, temperature: 25, rain: 4, probability: 99, sunshineMinutes: 60)); var summary = SchoolDayWeatherSummary.From(snapshot, Day); Assert.Equal(12, summary!.MinTemperatureC); Assert.Equal(17, summary.MaxTemperatureC); Assert.Equal(0, summary.PrecipitationMm); Assert.Equal(65, summary.MaxHourlyPrecipitationProbabilityPercent); Assert.Equal(1.3, summary.SunshineDurationHours); Assert.Contains("08–16 Uhr", summary.Tooltip); Assert.Contains("Regenwahrscheinlichkeit: bis 65 % (stündlich)", summary.Tooltip); Assert.Contains($"Sonnenschein: {summary.SunshineDurationHours:0.#} h", summary.Tooltip); } [Fact] public void From_AmtlicheGewitterwarnung_PraegtSymbolUndTooltip() { var snapshot = Snapshot(Hour(10, cloud: 20)); snapshot.Warnings.Add(new WeatherWarning { Identifier = "w1", Event = "GEWITTER", Headline = "Amtliche Warnung vor Gewitter", Instruction = "Aufenthalt im Freien vermeiden.", Severity = "Severe", Onset = Day.ToDateTime(new TimeOnly(12, 0)), Expires = Day.ToDateTime(new TimeOnly(16, 0)), }); var summary = SchoolDayWeatherSummary.From(snapshot, Day); Assert.Equal(SchoolDayWeatherKind.Thunderstorm, summary!.Kind); Assert.Contains("Amtliche Warnung", summary.Tooltip); Assert.Contains("Aufenthalt im Freien", summary.Tooltip); } [Fact] public void From_RegenSummiertStundenUndZeigtTemperaturspanne() { var snapshot = Snapshot( Hour(8, temperature: 12, rain: 0.1), Hour(12, temperature: 17, rain: 0.4)); var summary = SchoolDayWeatherSummary.From(snapshot, Day); Assert.Equal(SchoolDayWeatherKind.Rain, summary!.Kind); Assert.Equal(0.5, summary.PrecipitationMm); Assert.Contains("12–17 °C", summary.Tooltip); } [Fact] public void WarningTouchesDate_MehrtaegigeVorwarnung_TrifftAlleUeberlapptenTage() { var warning = new WeatherWarning { Onset = Day.ToDateTime(new TimeOnly(18, 0)), Expires = Day.AddDays(2).ToDateTime(new TimeOnly(8, 0)), }; Assert.True(SchoolDayWeatherSummary.WarningTouchesDate(warning, Day.AddDays(1))); Assert.False(SchoolDayWeatherSummary.WarningTouchesDate(warning, Day.AddDays(3))); } [Fact] public void WeekCellItem_WetterOderWarnung_AktiviertGemeinsameHoverFlaeche() { var cell = WeekCellItem.WeekdayHeader(DayOfWeek.Monday, Day, false); Assert.False(cell.HasWeatherInformation); cell.SetWeather(SchoolDayWeatherSummary.From(Snapshot(Hour(10)), Day), []); Assert.True(cell.HasWeatherInformation); cell.SetWeather(null, [new WeatherWarning { Headline = "Amtliche Warnung" }]); Assert.True(cell.HasWeatherInformation); Assert.Contains("Amtliche Warnung", cell.WeatherTooltip); } private static WeatherSnapshot Snapshot(params WeatherForecastHour[] hours) => new() { RetrievedAt = DateTime.UtcNow, Forecast = hours.ToList(), }; private static WeatherForecastHour Hour(int hour, int? code = 0, double? temperature = 20, double? rain = 0, double? gust = 20, double? cloud = 20, double? probability = null, double? sunshineMinutes = null) => new() { ValidAt = Day.ToDateTime(new TimeOnly(hour, 0)), WeatherCode = code, TemperatureC = temperature, PrecipitationMm = rain, WindGustKmh = gust, CloudCoverPercent = cloud, PrecipitationProbabilityPercent = probability, SunshineDurationMinutes = sunshineMinutes, }; }