Files
hrynco-notification-service/HrynCo.NotificationService.Services.Tests/EmailProcessing/EmailTemplateServiceTests.cs
T
agrynco 81654c0d33 feat(templates): add service language template management
Add normalized service and template catalogs, scoped administration, migration, validation, and regression coverage.

Ref: IT-1601
2026-10-17 22:02:43 +03:00

98 lines
4.3 KiB
C#

namespace HrynCo.NotificationService.Services.Tests.EmailProcessing;
using HrynCo.NotificationService.DAL.Abstract.Repositories;
using HrynCo.NotificationService.DAL.Abstract.Templates;
using HrynCo.NotificationService.Worker.Services.EmailProcessing;
using NSubstitute;
public sealed class EmailTemplateServiceTests
{
[Theory]
[InlineData("RU")]
[InlineData(" ru ")]
[InlineData(" RU ")]
public async Task GetAsync_WhenExactVersionIsMissing_RetriesLegacyTrimmedLowercaseCode(string requestedCode)
{
IEmailTemplateRepository repository = Substitute.For<IEmailTemplateRepository>();
var expected = Template("ru");
repository.GetAsync("TestService", "Welcome", "ru", Arg.Any<CancellationToken>()).Returns(expected);
var service = new EmailTemplateService(repository);
Assert.Same(expected, await service.GetAsync("TestService", "Welcome", requestedCode, default));
Assert.Equal(new[] { requestedCode, "ru" }, RequestedCodes(repository));
}
[Fact]
public async Task GetAsync_WhenBothExactAndLowercaseVersionsExist_PrefersExactVersion()
{
IEmailTemplateRepository repository = Substitute.For<IEmailTemplateRepository>();
var expected = Template("RU");
repository.GetAsync("TestService", "Welcome", "RU", Arg.Any<CancellationToken>()).Returns(expected);
repository.GetAsync("TestService", "Welcome", "ru", Arg.Any<CancellationToken>()).Returns(Template("ru"));
var service = new EmailTemplateService(repository);
Assert.Same(expected, await service.GetAsync("TestService", "Welcome", "RU", default));
Assert.Equal(new[] { "RU" }, RequestedCodes(repository));
}
[Fact]
public async Task GetAsync_WhenExactRegionalVersionExists_DoesNotNormalizeIt()
{
IEmailTemplateRepository repository = Substitute.For<IEmailTemplateRepository>();
var expected = Template("ru-RU");
repository.GetAsync("TestService", "Welcome", "ru-RU", Arg.Any<CancellationToken>()).Returns(expected);
var service = new EmailTemplateService(repository);
Assert.Same(expected, await service.GetAsync("TestService", "Welcome", "ru-RU", default));
Assert.Equal(new[] { "ru-RU" }, RequestedCodes(repository));
}
[Fact]
public async Task GetAsync_WhenMissingCodeIsAlreadyCanonical_QueriesOnlyOnce()
{
IEmailTemplateRepository repository = Substitute.For<IEmailTemplateRepository>();
var service = new EmailTemplateService(repository);
var error = await Assert.ThrowsAsync<InvalidOperationException>(() => service.GetAsync("TestService", "Welcome", "zz", default));
Assert.Contains("language='zz'", error.Message);
Assert.Equal(new[] { "zz" }, RequestedCodes(repository));
}
[Fact]
public async Task GetAsync_WhenRegionalLookupMisses_DoesNotScanOtherCaseOrRegionalVariants()
{
IEmailTemplateRepository repository = Substitute.For<IEmailTemplateRepository>();
repository.GetAsync("TestService", "Welcome", "ru-RU", Arg.Any<CancellationToken>()).Returns(Template("ru-RU"));
repository.GetAsync("TestService", "Welcome", "ru", Arg.Any<CancellationToken>()).Returns(Template("ru"));
var service = new EmailTemplateService(repository);
await Assert.ThrowsAsync<InvalidOperationException>(() => service.GetAsync("TestService", "Welcome", "RU-ru", default));
Assert.Equal(new[] { "RU-ru", "ru-ru" }, RequestedCodes(repository));
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public async Task GetAsync_WhenCodeIsBlank_RejectsBeforeRepositoryLookup(string? code)
{
IEmailTemplateRepository repository = Substitute.For<IEmailTemplateRepository>();
var service = new EmailTemplateService(repository);
await Assert.ThrowsAsync<InvalidDataException>(() => service.GetAsync("TestService", "Welcome", code, default));
Assert.Empty(repository.ReceivedCalls());
}
private static EmailTemplate Template(string code) => new()
{
ServiceName = "TestService", Key = "Welcome", LanguageCode = code, Subject = "Subject " + code,
HtmlBody = "<p>Hello</p>", TextBody = "Hello"
};
private static string[] RequestedCodes(IEmailTemplateRepository repository) => repository.ReceivedCalls()
.Select(call => (string)call.GetArguments()[2]!).ToArray();
}