using Omika.Diagnostics.Tasks; namespace Omika.Diagnostics.Tests.Fakes; /// /// Fake en mémoire de pour les tests sans /// PostgreSQL. Reproduit la sémantique du repository Npgsql : unicité par signature /// (group_url_identifier), statut normalisé, date de résolution dérivée du statut. /// public sealed class FakeDiagnosticTaskRepository : IDiagnosticTaskRepository { private readonly List _tasks = []; private long _nextId = 1; public IReadOnlyList Seed(params DiagnosticTaskRecord[] tasks) { foreach (DiagnosticTaskRecord t in tasks) { if (t.Id == 0) { t.Id = _nextId++; } else { _nextId = Math.Max(_nextId, t.Id + 1); } _tasks.Add(t); } return _tasks; } public Task> ListAsync( CancellationToken cancellationToken = default) { IReadOnlyList ordered = _tasks .OrderByDescending(t => t.UpdatedAtUtc) .ThenByDescending(t => t.Id) .ToList(); return Task.FromResult(ordered); } public Task GetByIdAsync( long id, CancellationToken cancellationToken = default) => Task.FromResult(_tasks.FirstOrDefault(t => t.Id == id)); public Task GetByGroupAsync( string groupUrlIdentifier, CancellationToken cancellationToken = default) => Task.FromResult(_tasks.FirstOrDefault(t => t.GroupUrlIdentifier == groupUrlIdentifier)); public Task CreateAsync( string groupUrlIdentifier, string title, string? description, string? cause, string status, string createdByUsername, string? assigneeUsername, CancellationToken cancellationToken = default) { string? group = Normalize(groupUrlIdentifier); string? normalizedTitle = Normalize(title); if (group is null || normalizedTitle is null) { return Task.FromResult(null); } if (_tasks.Any(t => t.GroupUrlIdentifier == group)) { return Task.FromResult(null); // doublon. } string normalizedStatus = DiagnosticTaskStatuses.Normalize(status); DateTimeOffset now = DateTimeOffset.UtcNow; var record = new DiagnosticTaskRecord { Id = _nextId++, GroupUrlIdentifier = group, Title = normalizedTitle, Description = Normalize(description), Cause = Normalize(cause), Status = normalizedStatus, CreatedByUsername = createdByUsername, AssigneeUsername = Normalize(assigneeUsername), CreatedAtUtc = now, UpdatedAtUtc = now, ResolvedAtUtc = DiagnosticTaskStatuses.IsTerminal(normalizedStatus) ? now : null }; _tasks.Add(record); return Task.FromResult(record); } public Task UpdateAsync( long id, string title, string? description, string? cause, string status, string? assigneeUsername, CancellationToken cancellationToken = default) { DiagnosticTaskRecord? task = _tasks.FirstOrDefault(t => t.Id == id); string? normalizedTitle = Normalize(title); if (task is null || normalizedTitle is null) { return Task.FromResult(false); } string normalizedStatus = DiagnosticTaskStatuses.Normalize(status); task.Title = normalizedTitle; task.Description = Normalize(description); task.Cause = Normalize(cause); task.Status = normalizedStatus; task.AssigneeUsername = Normalize(assigneeUsername); task.UpdatedAtUtc = DateTimeOffset.UtcNow; task.ResolvedAtUtc = DiagnosticTaskStatuses.IsTerminal(normalizedStatus) ? task.ResolvedAtUtc ?? DateTimeOffset.UtcNow : null; return Task.FromResult(true); } public Task DeleteAsync( long id, CancellationToken cancellationToken = default) { int removed = _tasks.RemoveAll(t => t.Id == id); return Task.FromResult(removed > 0); } private static string? Normalize(string? value) => string.IsNullOrWhiteSpace(value) ? null : value.Trim(); }