CI / build-and-test (push) Canceled after 0s
Neuer 4. Tab in der Klassenlehreransicht: bündelt Titel, Beschreibung, Schlagwörter, verknüpfte Dokumentation und angeheftete (eingefrorene) WebUntis-Klassenbucheinträge zu einem laufenden Problem mit einer/einem oder mehreren Schüler*innen. Anheften direkt aus dem Klassenbuch-Tab per Rechtsklick. Sync-fähig nach dem bestehenden Documentation-Muster. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
214 lines
8.6 KiB
C#
214 lines
8.6 KiB
C#
using LehrerApp.Core.Models;
|
|
using LehrerApp.Data.Repositories;
|
|
using Xunit;
|
|
|
|
namespace LehrerApp.Data.Tests;
|
|
|
|
// Baustein 4: pro öffentlichem Repository-Aufruf genau EIN Sync-Ereignis, auch wenn die
|
|
// eigentliche Kaskade mehrere Collections betrifft. Batch-Methoden feuern ein Ereignis pro
|
|
// betroffener Entität.
|
|
public sealed class ChangeHookCascadeTests
|
|
{
|
|
private static LiteDbContext NewInMemoryContext() => new(new MemoryStream());
|
|
|
|
[Fact]
|
|
public void GroupRepository_Delete_LoestGenauEinEreignisAusTrotzKaskade()
|
|
{
|
|
using var db = NewInMemoryContext();
|
|
var groupRepo = new GroupRepository(db);
|
|
var group = new LearningGroup { Name = "8a", SchoolYear = "2025/26" };
|
|
groupRepo.Save(group);
|
|
db.Grades.Insert(new Grade { GroupId = group.Id, StudentId = Guid.NewGuid() });
|
|
db.Exams.Insert(new Exam { GroupId = group.Id });
|
|
var calls = new List<(string EntityType, string Operation)>();
|
|
db.OnChange = (type, id, op, payload) => calls.Add((type, op));
|
|
|
|
groupRepo.Delete(group.Id);
|
|
|
|
var call = Assert.Single(calls);
|
|
Assert.Equal((nameof(LearningGroup), "Delete"), call);
|
|
}
|
|
|
|
[Fact]
|
|
public void ExamRepository_Delete_LoestGenauEinEreignisAusTrotzErgebnisKaskade()
|
|
{
|
|
using var db = NewInMemoryContext();
|
|
var repo = new ExamRepository(db);
|
|
var exam = new Exam { GroupId = Guid.NewGuid() };
|
|
repo.Save(exam);
|
|
db.ExamResults.Insert(new ExamResult { ExamId = exam.Id, StudentId = Guid.NewGuid() });
|
|
db.ExamResults.Insert(new ExamResult { ExamId = exam.Id, StudentId = Guid.NewGuid() });
|
|
var calls = new List<(string EntityType, string Operation)>();
|
|
db.OnChange = (type, id, op, payload) => calls.Add((type, op));
|
|
|
|
repo.Delete(exam.Id);
|
|
|
|
var call = Assert.Single(calls);
|
|
Assert.Equal((nameof(Exam), "Delete"), call);
|
|
}
|
|
|
|
[Fact]
|
|
public void ParticipationSessionRepository_Delete_LoestGenauEinEreignisAusTrotzEintragKaskade()
|
|
{
|
|
using var db = NewInMemoryContext();
|
|
var repo = new ParticipationSessionRepository(db);
|
|
var session = new ParticipationSession { GroupId = Guid.NewGuid() };
|
|
repo.Save(session);
|
|
db.ParticipationEntries.Insert(new ParticipationEntry { SessionId = session.Id, StudentId = Guid.NewGuid() });
|
|
var calls = new List<(string EntityType, string Operation)>();
|
|
db.OnChange = (type, id, op, payload) => calls.Add((type, op));
|
|
|
|
repo.Delete(session.Id);
|
|
|
|
var call = Assert.Single(calls);
|
|
Assert.Equal((nameof(ParticipationSession), "Delete"), call);
|
|
}
|
|
|
|
[Fact]
|
|
public void ExamResultRepository_SaveMany_LoestEinEreignisProEintragAus()
|
|
{
|
|
using var db = NewInMemoryContext();
|
|
var repo = new ExamResultRepository(db);
|
|
var results = new List<ExamResult>
|
|
{
|
|
new() { ExamId = Guid.NewGuid(), StudentId = Guid.NewGuid() },
|
|
new() { ExamId = Guid.NewGuid(), StudentId = Guid.NewGuid() },
|
|
new() { ExamId = Guid.NewGuid(), StudentId = Guid.NewGuid() },
|
|
};
|
|
var calls = new List<(string EntityType, string EntityId, string Operation)>();
|
|
db.OnChange = (type, id, op, payload) => calls.Add((type, id, op));
|
|
|
|
repo.SaveMany(results);
|
|
|
|
Assert.Equal(3, calls.Count);
|
|
Assert.All(calls, c => Assert.Equal((nameof(ExamResult), "Save"), (c.EntityType, c.Operation)));
|
|
Assert.Equal(results.Select(r => r.Id.ToString()).OrderBy(x => x), calls.Select(c => c.EntityId).OrderBy(x => x));
|
|
}
|
|
|
|
[Fact]
|
|
public void ParticipationRepository_SaveMany_LoestEinEreignisProEintragAus()
|
|
{
|
|
using var db = NewInMemoryContext();
|
|
var repo = new ParticipationRepository(db);
|
|
var sessionId = Guid.NewGuid();
|
|
var entries = new List<ParticipationEntry>
|
|
{
|
|
new() { SessionId = sessionId, StudentId = Guid.NewGuid() },
|
|
new() { SessionId = sessionId, StudentId = Guid.NewGuid() },
|
|
};
|
|
var calls = new List<(string EntityType, string Operation)>();
|
|
db.OnChange = (type, id, op, payload) => calls.Add((type, op));
|
|
|
|
repo.SaveMany(entries);
|
|
|
|
Assert.Equal(2, calls.Count);
|
|
Assert.All(calls, c => Assert.Equal((nameof(ParticipationEntry), "Save"), c));
|
|
}
|
|
|
|
[Fact]
|
|
public void ParticipationRepository_DeleteBySession_LoestEinEreignisProEintragAus()
|
|
{
|
|
using var db = NewInMemoryContext();
|
|
var repo = new ParticipationRepository(db);
|
|
var sessionId = Guid.NewGuid();
|
|
repo.Save(new ParticipationEntry { SessionId = sessionId, StudentId = Guid.NewGuid() });
|
|
repo.Save(new ParticipationEntry { SessionId = sessionId, StudentId = Guid.NewGuid() });
|
|
var calls = new List<(string EntityType, string Operation)>();
|
|
db.OnChange = (type, id, op, payload) => calls.Add((type, op));
|
|
|
|
repo.DeleteBySession(sessionId);
|
|
|
|
Assert.Equal(2, calls.Count);
|
|
Assert.All(calls, c => Assert.Equal((nameof(ParticipationEntry), "Delete"), c));
|
|
}
|
|
|
|
[Fact]
|
|
public void CompetencyDomainRepository_ReplaceForSubjectAndGrade_LoestDeleteFuerAlteUndSaveFuerNeueAus()
|
|
{
|
|
using var db = NewInMemoryContext();
|
|
var repo = new CompetencyDomainRepository(db);
|
|
var subjectId = Guid.NewGuid();
|
|
repo.Save(new CompetencyDomain { SubjectId = subjectId, GradeLevel = 8, Name = "Alt" });
|
|
var calls = new List<(string EntityType, string Operation)>();
|
|
db.OnChange = (type, id, op, payload) => calls.Add((type, op));
|
|
|
|
repo.ReplaceForSubjectAndGrade(subjectId, 8,
|
|
[
|
|
new CompetencyDomain { Name = "Neu 1" },
|
|
new CompetencyDomain { Name = "Neu 2" },
|
|
]);
|
|
|
|
Assert.Equal(3, calls.Count);
|
|
Assert.Equal(1, calls.Count(c => c.Operation == "Delete"));
|
|
Assert.Equal(2, calls.Count(c => c.Operation == "Save"));
|
|
Assert.All(calls, c => Assert.Equal(nameof(CompetencyDomain), c.EntityType));
|
|
}
|
|
|
|
[Fact]
|
|
public void CompetencyDomainRepository_DeleteBySubjectAndGrade_LoestEinEreignisProDomaenAus()
|
|
{
|
|
using var db = NewInMemoryContext();
|
|
var repo = new CompetencyDomainRepository(db);
|
|
var subjectId = Guid.NewGuid();
|
|
repo.Save(new CompetencyDomain { SubjectId = subjectId, GradeLevel = 8, Name = "A" });
|
|
repo.Save(new CompetencyDomain { SubjectId = subjectId, GradeLevel = 8, Name = "B" });
|
|
var calls = new List<(string EntityType, string Operation)>();
|
|
db.OnChange = (type, id, op, payload) => calls.Add((type, op));
|
|
|
|
repo.DeleteBySubjectAndGrade(subjectId, 8);
|
|
|
|
Assert.Equal(2, calls.Count);
|
|
Assert.All(calls, c => Assert.Equal((nameof(CompetencyDomain), "Delete"), c));
|
|
}
|
|
|
|
[Fact]
|
|
public void DocumentationRepository_Delete_LoestSaveMitIsDeletedAus()
|
|
{
|
|
using var db = NewInMemoryContext();
|
|
var repo = new DocumentationRepository(db);
|
|
var doc = new Documentation { StudentId = Guid.NewGuid(), Title = "Gespräch" };
|
|
repo.Save(doc);
|
|
var calls = new List<(string EntityType, string Operation, object? Payload)>();
|
|
db.OnChange = (type, id, op, payload) => calls.Add((type, op, payload));
|
|
|
|
repo.Delete(doc.Id);
|
|
|
|
var call = Assert.Single(calls);
|
|
Assert.Equal((nameof(Documentation), "Save"), (call.EntityType, call.Operation));
|
|
Assert.True(((Documentation)call.Payload!).IsDeleted);
|
|
}
|
|
|
|
[Fact]
|
|
public void DocumentationRepository_HardDelete_LoestDeleteAus()
|
|
{
|
|
using var db = NewInMemoryContext();
|
|
var repo = new DocumentationRepository(db);
|
|
var doc = new Documentation { StudentId = Guid.NewGuid(), Title = "Gespräch" };
|
|
repo.Save(doc);
|
|
var calls = new List<(string EntityType, string Operation)>();
|
|
db.OnChange = (type, id, op, payload) => calls.Add((type, op));
|
|
|
|
repo.HardDelete(doc.Id);
|
|
|
|
var call = Assert.Single(calls);
|
|
Assert.Equal((nameof(Documentation), "Delete"), call);
|
|
}
|
|
|
|
[Fact]
|
|
public void VorgangRepository_Delete_LoestSaveMitIsDeletedAus()
|
|
{
|
|
using var db = NewInMemoryContext();
|
|
var repo = new VorgangRepository(db);
|
|
var vorgang = new Vorgang { Title = "Konflikt" };
|
|
repo.Save(vorgang);
|
|
var calls = new List<(string EntityType, string Operation, object? Payload)>();
|
|
db.OnChange = (type, id, op, payload) => calls.Add((type, op, payload));
|
|
|
|
repo.Delete(vorgang.Id);
|
|
|
|
var call = Assert.Single(calls);
|
|
Assert.Equal((nameof(Vorgang), "Save"), (call.EntityType, call.Operation));
|
|
Assert.True(((Vorgang)call.Payload!).IsDeleted);
|
|
}
|
|
}
|