Minimale Liste im Tab "Synchronisation" - Entitaet, Zeitpunkt, welche Seite ConflictResolver gewaehlt hat, mit "Gesehen"-Aktion. Kein Feld-Diff fuer v1: die Payloads sind clientseitig verschluesselt, ein Diff wuerde ohnehin nur rohes JSON zeigen. Neu EventQueue.MarkReviewed(id) - bisher gab es AddConflict/ GetUnreviewed/ConflictCount, aber keinen Weg, einen Konflikt als gesehen zu markieren. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
409 lines
19 KiB
C#
409 lines
19 KiB
C#
using LehrerApp.Core.Interfaces;
|
|
using LehrerApp.Core.Models;
|
|
using LehrerApp.Desktop.Services;
|
|
using LehrerApp.Sync;
|
|
|
|
namespace LehrerApp.Desktop.Tests;
|
|
|
|
// Einfache In-Memory-Fakes der Repository-Schnittstellen, damit ViewModel-Tests ohne echte
|
|
// LiteDB-Anbindung laufen. Bewusst schlank gehalten: nur was die getesteten ViewModels brauchen.
|
|
|
|
public static class TestSupport
|
|
{
|
|
/// Für Tests, die eine echte AiSettingsService-Instanz brauchen (dateibasiert wie
|
|
/// PeriodScheduleService & Co.) — eigenes Temp-Verzeichnis je Aufruf, damit Tests sich nicht
|
|
/// gegenseitig über dieselbe ai-settings.json/ai-token.key stören.
|
|
public static AiSettingsService BuildAiSettingsService()
|
|
{
|
|
var tempPath = Path.Combine(Path.GetTempPath(), $"lehrerapp-aisettings-tests-{Guid.NewGuid():N}");
|
|
Directory.CreateDirectory(tempPath);
|
|
return new AiSettingsService(tempPath);
|
|
}
|
|
|
|
/// Für Tests, die nur einen validen AiPlanningService zum Durchreichen brauchen (z.B. weil
|
|
/// SettingsViewModel/PlanningTabViewModel ihn im Konstruktor verlangen), nicht seine eigentliche
|
|
/// Funktionalität testen — leere Fakes genügen, es wird kein echter HTTP-Aufruf ausgelöst,
|
|
/// solange AiSettingsService.IsLoggedIn false ist.
|
|
public static AiPlanningService BuildAiPlanningService() => new(
|
|
new HttpClient(), new FakeLessons(), new FakeGroups([]), new FakeSubjects([]),
|
|
new FakeCompetencyDomains(), new FakeAlternativeLessonPaths([]));
|
|
|
|
/// Analog zu <see cref="BuildAiSettingsService"/>, eigenes Temp-Verzeichnis je Aufruf.
|
|
public static SyncSettingsService BuildSyncSettingsService()
|
|
{
|
|
var tempPath = Path.Combine(Path.GetTempPath(), $"lehrerapp-syncsettings-tests-{Guid.NewGuid():N}");
|
|
Directory.CreateDirectory(tempPath);
|
|
return new SyncSettingsService(tempPath);
|
|
}
|
|
|
|
/// Kein echter HTTP-Aufruf, solange SyncSettingsService.IsLoggedIn false ist (siehe
|
|
/// BuildAiPlanningService).
|
|
public static SyncAuthService BuildSyncAuthService() => new(new HttpClient());
|
|
|
|
/// Eigenes Temp-Verzeichnis je Aufruf (echte, dateibasierte LiteDB wie bei EventQueue üblich).
|
|
public static EventQueue BuildEventQueue()
|
|
{
|
|
var tempPath = Path.Combine(Path.GetTempPath(), $"lehrerapp-eventqueue-tests-{Guid.NewGuid():N}");
|
|
Directory.CreateDirectory(tempPath);
|
|
return new EventQueue(Path.Combine(tempPath, "queue.db"));
|
|
}
|
|
}
|
|
|
|
public class FakeStudents(List<Student> all) : IStudentRepository
|
|
{
|
|
private readonly Dictionary<Guid, StudentReferenceSummary> _references = [];
|
|
public Student? GetById(Guid id) => all.FirstOrDefault(s => s.Id == id);
|
|
public List<Student> GetAll(bool includeInactive = false) =>
|
|
includeInactive ? all.ToList() : all.Where(s => s.IsActive).ToList();
|
|
public List<Student> GetByGroup(Guid groupId) => all;
|
|
public StudentReferenceSummary GetReferenceSummary(Guid studentId) =>
|
|
_references.GetValueOrDefault(studentId, new StudentReferenceSummary(0, 0, 0, 0, 0, 0));
|
|
public void SetReferenceSummary(Guid studentId, StudentReferenceSummary summary) => _references[studentId] = summary;
|
|
public void Save(Student student) { all.RemoveAll(s => s.Id == student.Id); all.Add(student); }
|
|
public void Delete(Guid id)
|
|
{
|
|
if (GetReferenceSummary(id).HasReferences) throw new InvalidOperationException();
|
|
all.RemoveAll(s => s.Id == id);
|
|
}
|
|
}
|
|
|
|
public class FakeMemberships(List<GroupMembership> all) : IGroupMembershipRepository
|
|
{
|
|
public List<GroupMembership> GetByStudent(Guid studentId) => all.Where(m => m.StudentId == studentId).ToList();
|
|
public List<GroupMembership> GetByGroup(Guid groupId) => all.Where(m => m.GroupId == groupId).ToList();
|
|
public GroupMembership? GetByStudentAndGroup(Guid studentId, Guid groupId) =>
|
|
all.FirstOrDefault(m => m.StudentId == studentId && m.GroupId == groupId);
|
|
public void Save(GroupMembership membership)
|
|
{
|
|
all.RemoveAll(m => m.Id == membership.Id);
|
|
all.Add(membership);
|
|
}
|
|
public void Delete(Guid id) => all.RemoveAll(m => m.Id == id);
|
|
}
|
|
|
|
public class FakeSeatingPlans(List<SeatingPlan>? initial = null) : ISeatingPlanRepository
|
|
{
|
|
private readonly List<SeatingPlan> _all = initial ?? [];
|
|
public SeatingPlan? GetById(Guid id) => _all.FirstOrDefault(p => p.Id == id);
|
|
public List<SeatingPlan> GetByGroup(Guid groupId) =>
|
|
_all.Where(p => p.GroupId == groupId).OrderBy(p => p.Name).ToList();
|
|
public void Save(SeatingPlan plan)
|
|
{
|
|
_all.RemoveAll(p => p.Id == plan.Id);
|
|
_all.Add(plan);
|
|
}
|
|
public void Delete(Guid id) => _all.RemoveAll(p => p.Id == id);
|
|
}
|
|
|
|
public class FakeSessions(List<ParticipationSession> all) : IParticipationSessionRepository
|
|
{
|
|
public List<ParticipationSession> GetByGroup(Guid groupId) => all.Where(s => s.GroupId == groupId).ToList();
|
|
public ParticipationSession? GetById(Guid id) => all.FirstOrDefault(s => s.Id == id);
|
|
public void Save(ParticipationSession session)
|
|
{
|
|
all.RemoveAll(s => s.Id == session.Id);
|
|
all.Add(session);
|
|
}
|
|
public void Delete(Guid id) => all.RemoveAll(s => s.Id == id);
|
|
}
|
|
|
|
public class FakeEntries : IParticipationRepository
|
|
{
|
|
private readonly List<ParticipationEntry> _all = [];
|
|
public void Add(ParticipationEntry e) => _all.Add(e);
|
|
public List<ParticipationEntry> GetBySession(Guid sessionId) => _all.Where(e => e.SessionId == sessionId).ToList();
|
|
public List<ParticipationEntry> GetByStudent(Guid studentId) => _all.Where(e => e.StudentId == studentId).ToList();
|
|
public ParticipationEntry? GetBySessionAndStudent(Guid sessionId, Guid studentId) =>
|
|
_all.FirstOrDefault(e => e.SessionId == sessionId && e.StudentId == studentId);
|
|
public void Save(ParticipationEntry entry)
|
|
{
|
|
_all.RemoveAll(e => e.Id == entry.Id);
|
|
_all.Add(entry);
|
|
}
|
|
public void SaveMany(List<ParticipationEntry> entries) { foreach (var e in entries) Save(e); }
|
|
public void DeleteBySession(Guid sessionId) => _all.RemoveAll(e => e.SessionId == sessionId);
|
|
}
|
|
|
|
public class FakeAspects : IParticipationAspectRepository
|
|
{
|
|
private readonly List<ParticipationAspect> _all = [];
|
|
public List<ParticipationAspect> GetDefaults() =>
|
|
_all.Where(a => a.GroupId == null && a.IsActive).OrderBy(a => a.SortOrder).ToList();
|
|
public List<ParticipationAspect> GetByGroup(Guid groupId) =>
|
|
_all.Where(a => a.GroupId == groupId && a.IsActive).OrderBy(a => a.SortOrder).ToList();
|
|
public List<ParticipationAspect> GetAllByGroup(Guid groupId) =>
|
|
_all.Where(a => a.GroupId == groupId).OrderBy(a => a.SortOrder).ToList();
|
|
public void Save(ParticipationAspect a)
|
|
{
|
|
a.Key = a.Key.Trim(); a.Label = a.Label.Trim();
|
|
if (a.Key.Length == 0) throw new ArgumentException("Der Schlüssel darf nicht leer sein.");
|
|
if (a.Label.Length == 0) throw new ArgumentException("Die Bezeichnung darf nicht leer sein.");
|
|
var duplicate = _all.Where(x => x.GroupId == null || x.GroupId == a.GroupId)
|
|
.FirstOrDefault(x => x.Id != a.Id && string.Equals(x.Key, a.Key, StringComparison.OrdinalIgnoreCase));
|
|
if (duplicate is not null) throw new InvalidOperationException("Ein Aspekt mit diesem Schlüssel existiert für diese Gruppe bereits.");
|
|
_all.RemoveAll(x => x.Id == a.Id);
|
|
_all.Add(a);
|
|
}
|
|
public void Delete(Guid id) => _all.RemoveAll(a => a.Id == id);
|
|
}
|
|
|
|
public class FakeGrades : IGradeRepository
|
|
{
|
|
private readonly List<Grade> _all = [];
|
|
public void Add(Grade g) => _all.Add(g);
|
|
public List<Grade> GetByStudentAndGroup(Guid studentId, Guid groupId) =>
|
|
_all.Where(g => g.StudentId == studentId && g.GroupId == groupId).ToList();
|
|
public List<Grade> GetByGroup(Guid groupId) => _all.Where(g => g.GroupId == groupId).ToList();
|
|
public void Save(Grade grade)
|
|
{
|
|
_all.RemoveAll(g => g.Id == grade.Id);
|
|
_all.Add(grade);
|
|
}
|
|
public void Delete(Guid id) => _all.RemoveAll(g => g.Id == id);
|
|
}
|
|
|
|
public class FakeExams(List<Exam> all) : IExamRepository
|
|
{
|
|
public Exam? GetById(Guid id) => all.FirstOrDefault(e => e.Id == id);
|
|
public List<Exam> GetAll() => all;
|
|
public List<Exam> GetByGroup(Guid groupId) => all.Where(e => e.GroupId == groupId).ToList();
|
|
public void Save(Exam exam) { }
|
|
public void Delete(Guid id) { }
|
|
}
|
|
|
|
public class FakeResults : IExamResultRepository
|
|
{
|
|
private readonly List<ExamResult> _all = [];
|
|
// Upsert-Semantik nach ExamId+StudentId, wie der reale unique Index es erzwingt.
|
|
public void Add(ExamResult r)
|
|
{
|
|
_all.RemoveAll(x => x.ExamId == r.ExamId && x.StudentId == r.StudentId);
|
|
_all.Add(r);
|
|
}
|
|
public List<ExamResult> GetByExam(Guid examId) => _all.Where(r => r.ExamId == examId).ToList();
|
|
public List<ExamResult> GetByStudent(Guid studentId) => _all.Where(r => r.StudentId == studentId).ToList();
|
|
public ExamResult? GetByExamAndStudent(Guid examId, Guid studentId) =>
|
|
_all.FirstOrDefault(r => r.ExamId == examId && r.StudentId == studentId);
|
|
public void Save(ExamResult result) { }
|
|
public void SaveMany(List<ExamResult> results) { }
|
|
}
|
|
|
|
public class FakeGradingKeyTemplates : IGradingKeyTemplateRepository
|
|
{
|
|
private readonly List<GradingKeyTemplate> _all = [];
|
|
public List<GradingKeyTemplate> GetAll() => _all;
|
|
public List<GradingKeyTemplate> GetByGradingSystem(GradingSystem system) =>
|
|
_all.Where(t => t.GradingSystem == system).ToList();
|
|
public GradingKeyTemplate? GetById(Guid id) => _all.FirstOrDefault(t => t.Id == id);
|
|
public void Save(GradingKeyTemplate template) { _all.RemoveAll(t => t.Id == template.Id); _all.Add(template); }
|
|
public void Delete(Guid id) => _all.RemoveAll(t => t.Id == id);
|
|
}
|
|
|
|
public class FakeSchemes : IGradingSchemeRepository
|
|
{
|
|
private readonly Dictionary<Guid, GradingScheme> _byGroup = [];
|
|
private readonly Dictionary<GroupType, GradingScheme> _byType = [];
|
|
public void SetForGroup(Guid groupId, GradingScheme s) => _byGroup[groupId] = s;
|
|
public void SetDefault(GroupType type, GradingScheme s) => _byType[type] = s;
|
|
public GradingScheme? GetByGroup(Guid groupId) => _byGroup.GetValueOrDefault(groupId);
|
|
public GradingScheme? GetDefaultForType(GroupType type) => _byType.GetValueOrDefault(type);
|
|
public void Save(GradingScheme scheme) { }
|
|
public void Delete(Guid id) { }
|
|
}
|
|
|
|
public class FakeGroups(List<LearningGroup> all) : IGroupRepository
|
|
{
|
|
public LearningGroup? GetById(Guid id) => all.FirstOrDefault(g => g.Id == id);
|
|
public List<LearningGroup> GetAll(bool includeInactive = false) => all;
|
|
public List<LearningGroup> GetBySchoolYear(string schoolYear, bool includeInactive = false) => all;
|
|
public void Save(LearningGroup group) { }
|
|
public void Delete(Guid id) { }
|
|
}
|
|
|
|
public class FakeDocumentation : IDocumentationRepository
|
|
{
|
|
private readonly List<Documentation> _all = [];
|
|
public void Add(Documentation d) => _all.Add(d);
|
|
public List<Documentation> GetByStudent(Guid studentId) =>
|
|
_all.Where(d => d.StudentId == studentId && !d.IsDeleted).ToList();
|
|
public List<Documentation> GetByStudentAndType(Guid studentId, DocumentationType type) =>
|
|
_all.Where(d => d.StudentId == studentId && d.Type == type && !d.IsDeleted).ToList();
|
|
public List<Documentation> GetAll() => _all.Where(d => !d.IsDeleted).ToList();
|
|
public void Save(Documentation doc) { _all.RemoveAll(d => d.Id == doc.Id); _all.Add(doc); }
|
|
public void Delete(Guid id) { var d = _all.FirstOrDefault(x => x.Id == id); if (d is not null) d.IsDeleted = true; }
|
|
public void HardDelete(Guid id) => _all.RemoveAll(d => d.Id == id);
|
|
}
|
|
|
|
public class FakeAttachmentStorage : IAttachmentStorage
|
|
{
|
|
private readonly Dictionary<string, byte[]> _blobs = [];
|
|
public string Upload(string fileName, Stream content)
|
|
{
|
|
using var ms = new MemoryStream();
|
|
content.CopyTo(ms);
|
|
var id = Guid.NewGuid().ToString("N");
|
|
_blobs[id] = ms.ToArray();
|
|
return id;
|
|
}
|
|
public Stream? OpenRead(string storageId) => _blobs.TryGetValue(storageId, out var b) ? new MemoryStream(b) : null;
|
|
public void Delete(string storageId) => _blobs.Remove(storageId);
|
|
}
|
|
|
|
public class FakeUnits : IUnitRepository
|
|
{
|
|
private readonly List<Unit> _all = [];
|
|
public void Add(Unit u) => _all.Add(u);
|
|
public Unit? GetById(Guid id) => _all.FirstOrDefault(u => u.Id == id);
|
|
public List<Unit> GetByGroup(Guid groupId) =>
|
|
_all.Where(u => u.GroupId == groupId).OrderBy(u => u.StartDate).ToList();
|
|
public void Save(Unit unit) { _all.RemoveAll(u => u.Id == unit.Id); _all.Add(unit); }
|
|
public void Delete(Guid id) => _all.RemoveAll(u => u.Id == id);
|
|
}
|
|
|
|
public class FakeLessons : ILessonRepository
|
|
{
|
|
private readonly List<Lesson> _all = [];
|
|
public void Add(Lesson l) => _all.Add(l);
|
|
public List<Lesson> GetByUnit(Guid unitId) =>
|
|
_all.Where(l => l.UnitId == unitId).OrderBy(l => l.Date).ThenBy(l => l.LessonNumber).ToList();
|
|
public List<Lesson> GetByGroupAndDate(Guid groupId, DateOnly date) =>
|
|
_all.Where(l => l.GroupId == groupId && l.Date == date).ToList();
|
|
public List<Lesson> GetByGroupAndRange(Guid groupId, DateOnly from, DateOnly to) =>
|
|
_all.Where(l => l.GroupId == groupId && l.Date >= from && l.Date <= to).OrderBy(l => l.Date).ToList();
|
|
public void Save(Lesson lesson) { _all.RemoveAll(l => l.Id == lesson.Id); _all.Add(lesson); }
|
|
public void Delete(Guid id) => _all.RemoveAll(l => l.Id == id);
|
|
}
|
|
|
|
public class FakeSubjects(List<Subject> all) : ISubjectRepository
|
|
{
|
|
public List<Subject> GetAll() => all;
|
|
public Subject? GetById(Guid id) => all.FirstOrDefault(s => s.Id == id);
|
|
public Subject? GetByName(string name) => all.FirstOrDefault(s => s.Name == name);
|
|
public void Save(Subject subject) { }
|
|
public void Delete(Guid id) { }
|
|
}
|
|
|
|
public class FakeCompetencyDomains : ICompetencyDomainRepository
|
|
{
|
|
private readonly List<CompetencyDomain> _all = [];
|
|
public void Add(CompetencyDomain d) => _all.Add(d);
|
|
public List<CompetencyDomain> GetBySubjectAndGrade(Guid subjectId, int gradeLevel) =>
|
|
_all.Where(d => d.SubjectId == subjectId && d.GradeLevel == gradeLevel)
|
|
.OrderBy(d => d.SortOrder).ToList();
|
|
public CompetencyDomain? GetById(Guid id) => _all.FirstOrDefault(d => d.Id == id);
|
|
public void Save(CompetencyDomain domain) { _all.RemoveAll(d => d.Id == domain.Id); _all.Add(domain); }
|
|
public void Delete(Guid id) => _all.RemoveAll(d => d.Id == id);
|
|
public void DeleteBySubjectAndGrade(Guid subjectId, int gradeLevel) =>
|
|
_all.RemoveAll(d => d.SubjectId == subjectId && d.GradeLevel == gradeLevel);
|
|
public void ReplaceForSubjectAndGrade(Guid subjectId, int gradeLevel, List<CompetencyDomain> domains)
|
|
{
|
|
DeleteBySubjectAndGrade(subjectId, gradeLevel);
|
|
_all.AddRange(domains);
|
|
}
|
|
}
|
|
|
|
public class FakeShorthandCodes(List<ShorthandCode> all) : IShorthandCodeRepository
|
|
{
|
|
public List<ShorthandCode> GetAll() => all;
|
|
public void Save(ShorthandCode code) { }
|
|
public void Delete(Guid id) { }
|
|
}
|
|
|
|
public class FakeAlternativeLessonPaths(List<AlternativeLessonPath> all) : IAlternativeLessonPathRepository
|
|
{
|
|
public List<AlternativeLessonPath> GetAll() => all;
|
|
public AlternativeLessonPath? GetById(Guid id) => all.FirstOrDefault(p => p.Id == id);
|
|
public void Save(AlternativeLessonPath path) { all.RemoveAll(p => p.Id == path.Id); all.Add(path); }
|
|
public void Delete(Guid id) => all.RemoveAll(p => p.Id == id);
|
|
}
|
|
|
|
public class FakeTimetableSlots : ITimetableSlotRepository
|
|
{
|
|
private readonly List<TimetableSlot> _all = [];
|
|
public void Add(TimetableSlot s) => _all.Add(s);
|
|
public List<TimetableSlot> GetAll() => _all.ToList();
|
|
public List<TimetableSlot> GetByGroup(Guid groupId) => _all.Where(s => s.GroupId == groupId).ToList();
|
|
public void Save(TimetableSlot slot)
|
|
{
|
|
var occupied = _all.FirstOrDefault(s => s.Weekday == slot.Weekday && s.PeriodNumber == slot.PeriodNumber);
|
|
if (occupied is not null && occupied.Id != slot.Id)
|
|
throw new InvalidOperationException("Diese Stunde ist bereits belegt.");
|
|
_all.RemoveAll(s => s.Id == slot.Id);
|
|
_all.Add(slot);
|
|
}
|
|
public void Delete(Guid id) => _all.RemoveAll(s => s.Id == id);
|
|
}
|
|
|
|
public class FakeSchoolHolidays : ISchoolHolidayRepository
|
|
{
|
|
private readonly List<SchoolHoliday> _all = [];
|
|
public void Add(SchoolHoliday h) => _all.Add(h);
|
|
public List<SchoolHoliday> GetAll() => _all.ToList();
|
|
public void Save(SchoolHoliday holiday) { _all.RemoveAll(h => h.Id == holiday.Id); _all.Add(holiday); }
|
|
public void Delete(Guid id) => _all.RemoveAll(h => h.Id == id);
|
|
}
|
|
|
|
public class FakeSupervisionDuties : ISupervisionDutyRepository
|
|
{
|
|
private readonly List<SupervisionDuty> _all = [];
|
|
public void Add(SupervisionDuty d) => _all.Add(d);
|
|
public List<SupervisionDuty> GetAll() => _all.ToList();
|
|
public void Save(SupervisionDuty duty)
|
|
{
|
|
var occupied = _all.FirstOrDefault(d => d.Weekday == duty.Weekday && d.AfterPeriod == duty.AfterPeriod);
|
|
if (occupied is not null && occupied.Id != duty.Id)
|
|
throw new InvalidOperationException("Für diese Pause ist bereits eine Aufsicht eingetragen.");
|
|
_all.RemoveAll(d => d.Id == duty.Id);
|
|
_all.Add(duty);
|
|
}
|
|
public void Delete(Guid id) => _all.RemoveAll(d => d.Id == id);
|
|
}
|
|
|
|
public class FakeSubstitutionEntries : ISubstitutionEntryRepository
|
|
{
|
|
private readonly List<SubstitutionEntry> _all = [];
|
|
public void Add(SubstitutionEntry e) => _all.Add(e);
|
|
public List<SubstitutionEntry> GetAll() => _all.ToList();
|
|
public List<SubstitutionEntry> GetByDate(DateOnly date) => _all.Where(e => e.Date == date).ToList();
|
|
public void Save(SubstitutionEntry entry) { _all.RemoveAll(e => e.Id == entry.Id); _all.Add(entry); }
|
|
public void Delete(Guid id) => _all.RemoveAll(e => e.Id == id);
|
|
}
|
|
|
|
public class FakeWorkTasks : IWorkTaskRepository
|
|
{
|
|
private readonly List<WorkTask> _all = [];
|
|
public void Add(WorkTask t) => _all.Add(t);
|
|
public List<WorkTask> GetByStatus(WorkTaskStatus status) => _all.Where(t => t.Status == status).ToList();
|
|
public List<WorkTask> GetAll() => _all.ToList();
|
|
public void Save(WorkTask task) { _all.RemoveAll(t => t.Id == task.Id); _all.Add(task); }
|
|
public void Delete(Guid id) => _all.RemoveAll(t => t.Id == id);
|
|
}
|
|
|
|
public class FakeTimeEntries : ITimeEntryRepository
|
|
{
|
|
private readonly List<TimeEntry> _all = [];
|
|
public void Add(TimeEntry e) => _all.Add(e);
|
|
public List<TimeEntry> GetByDate(DateOnly date) => _all.Where(e => e.Date == date).ToList();
|
|
public List<TimeEntry> GetByDateRange(DateOnly from, DateOnly to) =>
|
|
_all.Where(e => e.Date >= from && e.Date <= to).ToList();
|
|
public List<TimeEntry> GetByTask(Guid taskId) => _all.Where(e => e.TaskId == taskId).ToList();
|
|
public void Save(TimeEntry entry) { _all.RemoveAll(e => e.Id == entry.Id); _all.Add(entry); }
|
|
public void Delete(Guid id) => _all.RemoveAll(e => e.Id == id);
|
|
}
|
|
|
|
public class FakeReportGrades : IReportGradeRepository
|
|
{
|
|
private readonly List<ReportGrade> _all = [];
|
|
public int SavedCount { get; private set; }
|
|
public List<ReportGrade> GetByGroup(Guid groupId) => _all.Where(r => r.GroupId == groupId).ToList();
|
|
public ReportGrade? GetByStudentGroupPeriod(Guid studentId, Guid groupId, string period) =>
|
|
_all.FirstOrDefault(r => r.StudentId == studentId && r.GroupId == groupId && r.Period == period);
|
|
public void Save(ReportGrade grade)
|
|
{
|
|
_all.RemoveAll(r => r.Id == grade.Id);
|
|
_all.Add(grade);
|
|
SavedCount++;
|
|
}
|
|
public void Delete(Guid id) => _all.RemoveAll(r => r.Id == id);
|
|
}
|