Files
LehrerApp/LehrerApp.Desktop.Tests/WebUntisHomeworkComparisonViewModelTests.cs
T

168 lines
9.3 KiB
C#

using System.Net;
using System.Text;
using LehrerApp.Core.Models;
using LehrerApp.Core.Services;
using LehrerApp.Desktop.Services;
using LehrerApp.Desktop.ViewModels.Groups;
using LehrerApp.WebUntis;
using Xunit;
namespace LehrerApp.Desktop.Tests;
public sealed class WebUntisHomeworkComparisonViewModelTests
{
[Theory]
[InlineData("Fehlende HA", "Buch vergessen", "Negativ", true)]
[InlineData("Sonstiges", "HA nicht dabei", "Negativ", false)]
[InlineData(null, "HA nicht dabei", "Negativ", true)]
[InlineData("Hausaufgaben fehlen", null, "Negativ", true)]
[InlineData("Verhalten", "Schüler war unruhig", "Negativ", false)]
[InlineData("Hausaufgaben", "HA gemacht", "Positiv", false)]
[InlineData("Sonstiges", "Schach gespielt", "Negativ", false)]
public void IsMissingHomeworkEntry_ErkenntAuchDasWebUntisKuerzel(
string? category, string? entryText, string group, bool expected)
{
var entry = new UntisClassRegisterEventDto("10c", 20260925, "Che", "Gerste Amelia",
category, group, entryText);
Assert.Equal(expected, WebUntisHomeworkComparisonViewModel.IsMissingHomeworkEntry(entry));
}
[Fact]
public async Task Load_ZeigtFehlendeHaAuchOhneHausaufgabeImFreitext()
{
const string report = "Klasse\tDatum\tFach\tName\tBenutzer\tEintragskategorie\tKategoriegruppe\tText\r\n" +
"10c\t25.09.26\tChe\tGerste Amelia\tlehrkraft\tFehlende HA\tNegativ\tChe: Buch vergessen\r\n" +
"10c\t25.09.26\tChe\tGerste Amelia\tlehrkraft\tHausaufgaben\tPositiv\tChe: alles erledigt\r\n";
var handler = new QueueHandler(
Json("{\"result\":{\"sessionId\":\"s\"}}"),
Json("{\"result\":[{\"id\":1,\"name\":\"2026/27\",\"startDate\":20260801,\"endDate\":20270731}]}"),
Json("{\"data\":{\"finished\":true,\"error\":false," +
"\"reportParams\":\"get=rpt.tmp&name=ClassregEventPerStudent&format=csv\"}}"),
new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(Encoding.UTF8.GetBytes(report)),
});
var settings = TestSupport.BuildWebUntisSettingsService();
var credentials = new WebUntisCredentials("schule", "arche.webuntis.com", "lehrkraft", "geheim");
settings.SetApiCredentials(credentials);
await using var untis = new WebUntisIntegrationService(new HttpClient(handler), settings);
await untis.ConnectAsync(credentials);
var vm = new WebUntisHomeworkComparisonViewModel(untis, new FakeStudents([]),
new FakeGroups([]), new FakeSubjects([]), new FakeMemberships([]),
new FakeSessions([]), new FakeEntries(), new SchoolYearService())
{
StartDate = new DateTimeOffset(2026, 9, 24, 12, 0, 0, TimeSpan.Zero),
EndDate = new DateTimeOffset(2026, 9, 26, 12, 0, 0, TimeSpan.Zero),
};
await vm.LoadCommand.ExecuteAsync(null);
Assert.Equal("Gerste Amelia", Assert.Single(vm.Rows).UntisStudentName);
Assert.Contains("1 passende Einträge von 2", vm.Status);
}
[Fact]
public async Task LoadUndApply_TrenntBestehendenStatus_ZielstatusUndLokaleEintraege()
{
const string report = "Klasse\tDatum\tFach\tName\tBenutzer\tEintragskategorie\tKategoriegruppe\tText\r\n" +
"10c\t25.09.26\tChe\tGerste Amelia\tlehrkraft\tFehlende HA\tNegativ\tChe: nicht gemacht\r\n" +
"10c\t25.09.26\tChe\tMuster Ben\tlehrkraft\tFehlende HA\tNegativ\tChe: nicht gemacht\r\n";
var handler = new QueueHandler(
Json("{\"result\":{\"sessionId\":\"s\"}}"),
Json("{\"result\":[{\"id\":1,\"name\":\"2026/27\",\"startDate\":20260801,\"endDate\":20270731}]}"),
Json("{\"data\":{\"finished\":true,\"error\":false," +
"\"reportParams\":\"get=rpt.tmp&name=ClassregEventPerStudent&format=csv\"}}"),
new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(Encoding.UTF8.GetBytes(report)),
});
var settings = TestSupport.BuildWebUntisSettingsService();
var credentials = new WebUntisCredentials("schule", "arche.webuntis.com", "lehrkraft", "geheim");
settings.SetApiCredentials(credentials);
await using var untis = new WebUntisIntegrationService(new HttpClient(handler), settings);
await untis.ConnectAsync(credentials);
var date = new DateOnly(2026, 9, 25);
var schoolYear = new SchoolYearService();
var chemistry = new Subject { Name = "Chemie", ShortName = "Che" };
var biology = new Subject { Name = "Biologie", ShortName = "Bio" };
var classGroup = new LearningGroup { Name = "10c", Type = GroupType.Class,
SchoolYear = schoolYear.CurrentSchoolYear(date) };
var chemistryGroup = new LearningGroup { Name = "Chemie 10c", Type = GroupType.Course,
SubjectId = chemistry.Id, SchoolYear = classGroup.SchoolYear };
var biologyGroup = new LearningGroup { Name = "Biologie 10c", Type = GroupType.Course,
SubjectId = biology.Id, SchoolYear = classGroup.SchoolYear };
var amelia = new Student { FirstName = "Amelia", LastName = "Gerste" };
var ben = new Student { FirstName = "Ben", LastName = "Muster" };
var carl = new Student { FirstName = "Carl", LastName = "Beispiel" };
var chemistrySession = new ParticipationSession { GroupId = chemistryGroup.Id, Date = date };
var biologySession = new ParticipationSession { GroupId = biologyGroup.Id, Date = date };
var memberships = new FakeMemberships([
new GroupMembership { StudentId = amelia.Id, GroupId = chemistryGroup.Id },
new GroupMembership { StudentId = amelia.Id, GroupId = biologyGroup.Id },
new GroupMembership { StudentId = ben.Id, GroupId = chemistryGroup.Id },
new GroupMembership { StudentId = carl.Id, GroupId = chemistryGroup.Id },
]);
var participation = new FakeEntries();
participation.Add(new ParticipationEntry { SessionId = chemistrySession.Id, StudentId = amelia.Id,
Homework = HomeworkStatus.MissingOpen, HomeworkMissing = true });
participation.Add(new ParticipationEntry { SessionId = biologySession.Id, StudentId = amelia.Id,
Homework = HomeworkStatus.PartiallyCompleted, HomeworkMissing = true });
participation.Add(new ParticipationEntry { SessionId = chemistrySession.Id, StudentId = carl.Id,
Homework = HomeworkStatus.MissingOverdue, HomeworkMissing = true });
var vm = new WebUntisHomeworkComparisonViewModel(untis,
new FakeStudents([amelia, ben, carl]),
new FakeGroups([classGroup, chemistryGroup, biologyGroup]),
new FakeSubjects([chemistry, biology]), memberships,
new FakeSessions([chemistrySession, biologySession]), participation, schoolYear)
{
StartDate = new DateTimeOffset(2026, 9, 24, 12, 0, 0, TimeSpan.Zero),
EndDate = new DateTimeOffset(2026, 9, 26, 12, 0, 0, TimeSpan.Zero),
};
await vm.LoadCommand.ExecuteAsync(null);
var existing = Assert.Single(vm.Rows, r => r.AssignedStudent?.Id == amelia.Id);
Assert.False(existing.Selected);
Assert.Equal(HomeworkDisplay.Label(HomeworkStatus.MissingOpen), existing.LocalStatus);
Assert.Equal(HomeworkDisplay.Label(HomeworkStatus.MissingOpen), existing.SelectedStatusName);
var newRow = Assert.Single(vm.Rows, r => r.AssignedStudent?.Id == ben.Id);
Assert.True(newRow.Selected);
Assert.Equal("Noch kein Status erfasst", newRow.LocalStatus);
Assert.Equal(2, vm.LocalOnlyRows.Count);
Assert.Contains(vm.LocalOnlyRows, r => r.StudentName == amelia.FullName && r.GroupName == biologyGroup.Name);
Assert.Contains(vm.LocalOnlyRows, r => r.StudentName == carl.FullName && r.GroupName == chemistryGroup.Name);
newRow.AssignedStudent = carl;
Assert.Single(vm.LocalOnlyRows);
Assert.False(newRow.Selected);
newRow.AssignedStudent = ben;
Assert.Equal(2, vm.LocalOnlyRows.Count);
newRow.SelectedStatusName = HomeworkDisplay.Label(HomeworkStatus.SubmittedLate);
vm.ApplyCommand.Execute(null);
var saved = participation.GetBySessionAndStudent(chemistrySession.Id, ben.Id);
Assert.Equal(HomeworkStatus.SubmittedLate, saved?.Homework);
Assert.False(saved?.HomeworkMissing);
Assert.Equal(HomeworkDisplay.Label(HomeworkStatus.SubmittedLate), newRow.LocalStatus);
Assert.False(newRow.Selected);
Assert.Equal(HomeworkStatus.MissingOpen,
participation.GetBySessionAndStudent(chemistrySession.Id, amelia.Id)?.Homework);
}
private static HttpResponseMessage Json(string json) => new(HttpStatusCode.OK)
{
Content = new StringContent(json, Encoding.UTF8, "application/json"),
};
private sealed class QueueHandler(params HttpResponseMessage[] responses) : HttpMessageHandler
{
private readonly Queue<HttpResponseMessage> _responses = new(responses);
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken) => Task.FromResult(_responses.Dequeue());
}
}