using System.Net; using System.Text.Json; using LehrerApp.WebUntis; using Xunit; namespace LehrerApp.WebUntis.Tests; public sealed class WebUntisOpenPeriodsTests { [Theory] [InlineData(true, false, true, "", true, false)] [InlineData(false, true, true, "Bruchrechnung", false, true)] [InlineData(false, true, true, " ", true, true)] [InlineData(false, false, false, "", false, false)] public void MissingFlagsRespectRequirementsAndIgnoreTopicId(bool checkedAbs, bool neededAbs, bool neededTopic, string topic, bool missingTopic, bool missingAbs) { var json = JsonSerializer.SerializeToElement(new { periods = new[] { new { period = new { id = 123, hr = 2, dtRange = new { start = "2026-09-08T08:35:00", end = "2026-09-08T09:20:00" }, classes = new[] { new { el = new { id = 1, nameShort = "7a" } } }, teachers = new[] { new { el = new { id = 2, nameShort = "ABC" } } }, subject = new { el = new { name = "Mat" } } }, absChecked = checkedAbs, absCheckNeeded = neededAbs, topicNeeded = neededTopic, topicShort = topic, topicId = 999 } }, total = 80 }); var row = Assert.Single(WebUntisClient.ParseOpenPeriods(json)); Assert.Equal(missingTopic, row.TopicMissing); Assert.Equal(missingAbs, row.AttendanceMissing); Assert.Equal(DateTimeKind.Unspecified, row.Start.Kind); Assert.Equal("7a", row.Classes); } [Theory] [InlineData(true)] [InlineData(false)] public async Task RequestUsesExclusiveFilterAndSessionToken(bool teacher) { var handler = new Handler(); await using var client = new WebUntisClient(new HttpClient(handler), new WebUntisOptions { School = "test", Host = "test.webuntis.com", Username = "test", Password = "test" }); var meta = await client.GetOpenPeriodsMetaAsync(22, CancellationToken.None); Assert.Equal(2, meta.OwnTeacherId); Assert.Equal(1, Assert.Single(meta.MyClassIds)); var rows = await client.GetOpenPeriodsAsync(22, teacher ? 2 : null, teacher ? null : 1, new DateOnly(2026, 8, 13), new DateOnly(2026, 9, 8), CancellationToken.None); Assert.Empty(rows); using var body = JsonDocument.Parse(handler.Body!); Assert.Equal(teacher ? 2 : 1, body.RootElement.GetProperty(teacher ? "teacherId" : "classId").GetInt32()); Assert.False(body.RootElement.TryGetProperty(teacher ? "classId" : "teacherId", out _)); Assert.Equal("TOPIC_OR_ABSENCE_OPEN", body.RootElement.GetProperty("filter").GetString()); Assert.Equal("2026-08-13", body.RootElement.GetProperty("dateRange").GetProperty("start").GetString()); } private sealed class Handler : HttpMessageHandler { public string? Body { get; private set; } protected override async Task SendAsync(HttpRequestMessage request, CancellationToken token) { var path = request.RequestUri!.AbsolutePath; string response; if (path.EndsWith("jsonrpc.do")) response = "{\"result\":{\"sessionId\":\"test-session\",\"personId\":2}}"; else if (path.EndsWith("token/new")) { Assert.Contains("test-session", request.Headers.GetValues("Cookie").Single()); response = "test.token.value"; } else { Assert.Equal("Bearer", request.Headers.Authorization!.Scheme); Assert.Equal("test.token.value", request.Headers.Authorization.Parameter); Assert.Equal("22", request.Headers.GetValues("x-webuntis-api-school-year-id").Single()); if (path.EndsWith("/meta")) { Assert.Equal(HttpMethod.Get, request.Method); response = """ {"teachers":[{"el":{"id":2,"nameShort":"ABC"}}], "classes":[{"el":{"id":1,"nameShort":"7a"}}],"myClassIds":[1], "schoolYear":{"start":"2026-08-13","end":"2027-07-07"}} """; } else { Assert.Equal(HttpMethod.Post, request.Method); Body = await request.Content!.ReadAsStringAsync(token); response = "{\"periods\":[],\"total\":80}"; } } return new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(response) }; } } }