Files
Omika/tests/Omika.Tests/Services/EmailCreationServiceTests.cs
2026-10-23 18:46:50 +02:00

176 lines
6.9 KiB
C#

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using Omika.Core.Contracts.Common;
using Omika.Core.Contracts.Documents;
using Omika.Core.Contracts.Interventions;
using Omika.Core.Domain;
using Omika.Core.Domain.Entities.Documents;
using Omika.Core.Interfaces;
using Omika.Core.Services;
namespace Omika.Tests.Services;
/// <summary>
/// Vérifie que la sortie du repository Omika (champ simple + champ « Tableau »
/// avec <c>ListeMembre</c> et données JSON) est correctement substituée par
/// <see cref="EmailCreationService"/> : champ simple remplacé, tableau formaté,
/// aucune chaîne JSON brute injectée.
/// </summary>
public class EmailCreationServiceTests
{
[Fact]
public async Task ApercuAsync_TableauEtSimple_SubstitutionSansJsonBrut()
{
var modeleMailRepository = new FakeModeleMailRepository
{
Modele = new ModeleMail { Sujet = "$REFINTERNE$ - $TABRENDEZVOUS$" },
CorpsDocx = CreerDocx("Réf: $REFINTERNE$\nTableau: $TABRENDEZVOUS$")
};
var rapportChampService = new FakeRapportChampService
{
Champs =
[
new RapportChampDto { Rubrique = "$REFINTERNE$", ListeDonnesBD = "ABC-123" },
new RapportChampDto
{
Rubrique = "$TABRENDEZVOUS$",
Type = "Tableau",
ListeDonnesBD = "[{\"objet\":\"Objet A\"}]",
ListeMembre =
[
new RapportChampSousElementDto { Rubrique = "$TABRDV.OBJET$", MembreMob = "saObjet" }
]
}
]
};
var service = new EmailCreationService(
modeleMailRepository,
rapportChampService,
new FakeInterventionService());
EmailModeleApercuDto? apercu = await service.ApercuAsync(
new CreateEmailModeleRequest { ModeleId = "1", InterventionId = "guid" });
Assert.NotNull(apercu);
Assert.Equal("ABC-123 - Objet A", apercu!.Sujet);
Assert.Contains("ABC-123", apercu.Corps);
Assert.Contains("Objet A", apercu.Corps);
Assert.DoesNotContain("[{", apercu.Corps);
Assert.DoesNotContain("$REFINTERNE$", apercu.Corps);
Assert.DoesNotContain("$TABRENDEZVOUS$", apercu.Corps);
}
private static byte[] CreerDocx(string texte)
{
using var stream = new MemoryStream();
using (WordprocessingDocument doc = WordprocessingDocument.Create(stream, WordprocessingDocumentType.Document))
{
MainDocumentPart mainPart = doc.AddMainDocumentPart();
mainPart.Document = new DocumentFormat.OpenXml.Wordprocessing.Document();
Body body = new Body();
body.Append(new Paragraph(new Run(new Text(texte))));
mainPart.Document.Append(body);
mainPart.Document.Save();
}
return stream.ToArray();
}
private sealed class FakeModeleMailRepository : IModeleMailRepository
{
public ModeleMail? Modele { get; set; }
public byte[]? CorpsDocx { get; set; }
public Task<IReadOnlyList<ModeleMail>> GetAllAsync(CancellationToken cancellationToken = default)
=> Task.FromResult<IReadOnlyList<ModeleMail>>(Modele is null ? [] : [Modele]);
public Task<ModeleMail?> GetByIdAsync(string id, CancellationToken cancellationToken = default)
=> Task.FromResult(Modele);
public Task<byte[]?> GetCorpsDocxAsync(long modeleMailId, CancellationToken cancellationToken = default)
=> Task.FromResult(CorpsDocx);
}
private sealed class FakeRapportChampService : IRapportChampService
{
public IReadOnlyList<RapportChampDto> Champs { get; set; } = [];
public Task<IReadOnlyList<RapportChampDto>> GetChampsAsync(
GetRapportChampsRequest request,
bool toutesRub = false,
CancellationToken cancellationToken = default)
=> Task.FromResult(Champs);
public Task<IReadOnlyList<RapportChampDto>> GetChampsMailAsync(
GetRapportChampsRequest request,
CancellationToken cancellationToken = default)
=> Task.FromResult(Champs);
}
private sealed class FakeInterventionService : IInterventionService
{
public Task<PagedResult<InterventionSummaryDto>> SearchAsync(
SearchInterventionsRequest request,
CancellationToken cancellationToken = default)
=> throw new NotSupportedException();
public Task<PagedResult<InterventionDetailsDto>> SearchDetailsAsync(
SearchInterventionsRequest request,
CancellationToken cancellationToken = default)
=> throw new NotSupportedException();
public Task<InterventionDetailsDto?> GetByIdAsync(
string id,
CancellationToken cancellationToken = default)
=> Task.FromResult<InterventionDetailsDto?>(null);
public Task<InterventionDetailsDto> CreateAsync(
CreateInterventionRequest request,
CancellationToken cancellationToken = default,
AuditActor? auteur = null)
=> throw new NotSupportedException();
public Task<InterventionDetailsDto?> UpdateAsync(
string id,
UpdateInterventionRequest request,
CancellationToken cancellationToken = default,
AuditActor? auteur = null)
=> throw new NotSupportedException();
public Task<bool> ArchiveAsync(string id, CancellationToken cancellationToken = default)
=> throw new NotSupportedException();
public Task<IReadOnlyList<NoteInterneDto>> GetNotesAsync(
string interventionId,
CancellationToken cancellationToken = default)
=> Task.FromResult<IReadOnlyList<NoteInterneDto>>([]);
public Task<IReadOnlyList<NoteInterneDto>> GetNotesAdministrativesAsync(
string interventionId,
CancellationToken cancellationToken = default)
=> Task.FromResult<IReadOnlyList<NoteInterneDto>>([]);
public Task<NoteInterneDto> AddNoteAsync(
string interventionId,
string contenu,
AuditActor? auteur,
CancellationToken cancellationToken = default)
=> throw new NotSupportedException();
public Task<IReadOnlyList<EmailInterventionDto>> GetEmailsAsync(
string interventionId,
CancellationToken cancellationToken = default)
=> Task.FromResult<IReadOnlyList<EmailInterventionDto>>([]);
public Task<EmailInterventionDto> AddEmailAsync(
string interventionId,
CreateEmailInterventionRequest request,
AuditActor? auteur,
CancellationToken cancellationToken = default)
=> throw new NotSupportedException();
}
}