Files
Omika/tests/Omika.Diagnostics.Tests/Fakes/FakeDiagnosticTaskRepository.cs
T
2026-10-23 18:46:50 +02:00

136 lines
4.5 KiB
C#

using Omika.Diagnostics.Tasks;
namespace Omika.Diagnostics.Tests.Fakes;
/// <summary>
/// Fake en mémoire de <see cref="IDiagnosticTaskRepository"/> 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.
/// </summary>
public sealed class FakeDiagnosticTaskRepository : IDiagnosticTaskRepository
{
private readonly List<DiagnosticTaskRecord> _tasks = [];
private long _nextId = 1;
public IReadOnlyList<DiagnosticTaskRecord> 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<IReadOnlyList<DiagnosticTaskRecord>> ListAsync(
CancellationToken cancellationToken = default)
{
IReadOnlyList<DiagnosticTaskRecord> ordered = _tasks
.OrderByDescending(t => t.UpdatedAtUtc)
.ThenByDescending(t => t.Id)
.ToList();
return Task.FromResult(ordered);
}
public Task<DiagnosticTaskRecord?> GetByIdAsync(
long id,
CancellationToken cancellationToken = default) =>
Task.FromResult(_tasks.FirstOrDefault(t => t.Id == id));
public Task<DiagnosticTaskRecord?> GetByGroupAsync(
string groupUrlIdentifier,
CancellationToken cancellationToken = default) =>
Task.FromResult(_tasks.FirstOrDefault(t => t.GroupUrlIdentifier == groupUrlIdentifier));
public Task<DiagnosticTaskRecord?> 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<DiagnosticTaskRecord?>(null);
}
if (_tasks.Any(t => t.GroupUrlIdentifier == group))
{
return Task.FromResult<DiagnosticTaskRecord?>(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<DiagnosticTaskRecord?>(record);
}
public Task<bool> 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<bool> 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();
}