using DocumentOperator.Application.Common.Interfaces; using DocumentOperator.Application.Features.Documents.ExtractSwissQrCode; using DocumentOperator.Domain.Models.ValueObjects; using DocumentOperator.Domain.ValueObjects; using FluentAssertions; using Moq; using Xunit; namespace DocumentOperator.Tests.Unit.Application.Features.ExtractSwissQrCode; public sealed class ExtractSwissQrCodeHandlerTests { private readonly Mock _mockQrCodeProcessor; private readonly ExtractSwissQrCodeHandler _handler; public ExtractSwissQrCodeHandlerTests() { _mockQrCodeProcessor = new Mock(); _handler = new ExtractSwissQrCodeHandler(_mockQrCodeProcessor.Object); } [Fact] public async Task Handle_ValidRequest_ReturnsQrCodeDataAndReferences() { // Arrange var references = new List { "REF-001", "REF-002" }; var pdfBase64 = "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIKPj4KZW5kb2JqCjIgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9LaWRzIFszIDAgUl0KL0NvdW50IDEKPj4KZW5kb2JqCjMgMCBvYmoKPDwKL1R5cGUgL1BhZ2UKL1BhcmVudCAyIDAgUgovTWVkaWFCb3ggWzAgMCA2MTIgNzkyXQovQ29udGVudHMgNCAwIFIKPj4KZW5kb2JqCjQgMCBvYmoKPDwKL0xlbmd0aCAzMgo+PgpzdHJlYW0KQlQKL0YxIDEyIFRmCjEwMCA3MDAgVGQKKEhlbGxvKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjEgMDAwMDAgbiAKMDAwMDAwMDIxMyAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9TaXplIDUKL1Jvb3QgMSAwIFIKPj4Kc3RhcnR4cmVmCjI5NAolJUVPRgo="; var base64String = Base64String.Create(pdfBase64); var query = new ExtractSwissQrCodeQuery(references, base64String); var expectedQrCodeData = new SwissQrCodeData { QrType = "SPC", Version = "0200", CodingType = "1", Iban = "CH4431999123000889012", Creditor = new AddressData { AddressType = "S", Name = "Robert Schneider AG", Street = "Rue du Lac", BuildingNumber = "1268", PostalCode = "2501", City = "Biel", Country = "CH" }, UltimateCreditor = null, Amount = 1949.75m, Currency = "CHF", UltimateDebtor = null, ReferenceType = "QRR", Reference = "210000000003139471430009017", UnstructuredMessage = "Order from 15.01.2025", BillInformation = null, AlternativeProcedureParameters = null }; _mockQrCodeProcessor .Setup(x => x.ExtractSwissQrCodeAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(expectedQrCodeData); // Act var result = await _handler.Handle(query, CancellationToken.None); // Assert result.Should().NotBeNull(); result.References.Should().BeEquivalentTo(references); result.QrCodeData.Should().BeEquivalentTo(expectedQrCodeData); _mockQrCodeProcessor.Verify( x => x.ExtractSwissQrCodeAsync(It.IsAny(), It.IsAny()), Times.Once); } [Fact] public async Task Handle_QrCodeProcessorThrowsException_PropagatesException() { // Arrange var references = new List { "REF-001" }; var pdfBase64 = "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIKPj4KZW5kb2JqCjIgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9LaWRzIFszIDAgUl0KL0NvdW50IDEKPj4KZW5kb2JqCjMgMCBvYmoKPDwKL1R5cGUgL1BhZ2UKL1BhcmVudCAyIDAgUgovTWVkaWFCb3ggWzAgMCA2MTIgNzkyXQovQ29udGVudHMgNCAwIFIKPj4KZW5kb2JqCjQgMCBvYmoKPDwKL0xlbmd0aCAzMgo+PgpzdHJlYW0KQlQKL0YxIDEyIFRmCjEwMCA3MDAgVGQKKEhlbGxvKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwMDY0IDAwMDAwIG4gCjAwMDAwMDAxMjEgMDAwMDAgbiAKMDAwMDAwMDIxMyAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9TaXplIDUKL1Jvb3QgMSAwIFIKPj4Kc3RhcnR4cmVmCjI5NAolJUVPRgo="; var base64String = Base64String.Create(pdfBase64); var query = new ExtractSwissQrCodeQuery(references, base64String); _mockQrCodeProcessor .Setup(x => x.ExtractSwissQrCodeAsync(It.IsAny(), It.IsAny())) .ThrowsAsync(new InvalidOperationException("QR Code processing failed")); // Act Func act = async () => await _handler.Handle(query, CancellationToken.None); // Assert await act.Should().ThrowAsync() .WithMessage("QR Code processing failed"); } }