Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ private static IServiceCollection AddExternalServices(this IServiceCollection se
_ = services.Scan(scan =>
scan.FromAssembliesOf(typeof(IGmailServiceWrapper))
.AddClasses(classes => classes.InNamespaces(namespaces))
.UsingRegistrationStrategy(RegistrationStrategy.Skip)
.UsingRegistrationStrategy(RegistrationStrategy.Append)
.AsImplementedInterfaces()
.WithScopedLifetime()
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using InvoiceReminder.Domain.Entities;
using InvoiceReminder.Domain.Enums;
using System.Text.RegularExpressions;

namespace InvoiceReminder.ExternalServices.BarcodeReader;

public class AccountInvoiceBarcodeHandler : IInvoiceBarcodeHandler
{
public InvoiceType InvoiceType => InvoiceType.AccountInvoice;

public Invoice CreateInvoice(string content, string beneficiary)
{
ArgumentException.ThrowIfNullOrWhiteSpace(content);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using InvoiceReminder.Domain.Entities;
using InvoiceReminder.Domain.Enums;
using System.Globalization;
using System.Text.RegularExpressions;

Expand All @@ -8,6 +9,8 @@ public class BankInvoiceBarcodeHandler : IInvoiceBarcodeHandler
{
private readonly Dictionary<int, string> knowBanks;

public InvoiceType InvoiceType => InvoiceType.BankInvoice;

public BankInvoiceBarcodeHandler()
{
knowBanks = new()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using InvoiceReminder.Domain.Enums;

namespace InvoiceReminder.ExternalServices.BarcodeReader;

public class BarcodeHandlerFactory : IBarcodeHandlerFactory
{
private readonly Dictionary<InvoiceType, IInvoiceBarcodeHandler> _handlers;

public BarcodeHandlerFactory(IEnumerable<IInvoiceBarcodeHandler> handlers)
{
var duplicatedTypes = handlers
.GroupBy(h => h.InvoiceType)
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.ToArray();

if (duplicatedTypes.Length > 0)
{
throw new InvalidOperationException(
$"Duplicate barcode handlers registered for: {string.Join(", ", duplicatedTypes)}");
}

_handlers = handlers.ToDictionary(h => h.InvoiceType, h => h);
}

public IInvoiceBarcodeHandler GetHandler(InvoiceType invoiceType)
{
return _handlers.TryGetValue(invoiceType, out var handler)
? handler
: throw new NotSupportedException($"No barcode handler found for invoice type: {invoiceType}");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ namespace InvoiceReminder.ExternalServices.BarcodeReader;
public class BarcodeReaderService : IBarcodeReaderService
{
private readonly ILogger<BarcodeReaderService> _logger;
private IInvoiceBarcodeHandler _barcodeHandler;
private readonly IBarcodeHandlerFactory _factory;

public BarcodeReaderService(ILogger<BarcodeReaderService> logger)
public BarcodeReaderService(ILogger<BarcodeReaderService> logger, IBarcodeHandlerFactory factory)
{
_logger = logger;
_factory = factory;
}

public Invoice ReadTextContentFromPdf(byte[] byteStream, string beneficiary, string password, InvoiceType invoiceType)
Expand Down Expand Up @@ -45,6 +46,7 @@ public Invoice ReadTextContentFromPdf(byte[] byteStream, string beneficiary, str

StringBuilder content = new();
var numberOfPages = pdfDoc.GetNumberOfPages();
var barcodeHandler = _factory.GetHandler(invoiceType);

for (var page = 1; page <= numberOfPages; page++)
{
Expand All @@ -57,18 +59,6 @@ public Invoice ReadTextContentFromPdf(byte[] byteStream, string beneficiary, str
_ = content.Append(currentText).Replace(" \n", "\n").Replace(" \r\n", "\r\n");
}

SetBarcodeHandler(invoiceType);

return _barcodeHandler.CreateInvoice(content.ToString(), beneficiary);
}

private void SetBarcodeHandler(InvoiceType invoiceType)
{
_barcodeHandler = invoiceType switch
{
InvoiceType.BankInvoice => new BankInvoiceBarcodeHandler(),
InvoiceType.AccountInvoice => new AccountInvoiceBarcodeHandler(),
_ => default
};
return barcodeHandler.CreateInvoice(content.ToString(), beneficiary);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using InvoiceReminder.Domain.Enums;

namespace InvoiceReminder.ExternalServices.BarcodeReader;

public interface IBarcodeHandlerFactory
{
IInvoiceBarcodeHandler GetHandler(InvoiceType invoiceType);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using InvoiceReminder.Domain.Entities;
using InvoiceReminder.Domain.Enums;

namespace InvoiceReminder.ExternalServices.BarcodeReader;

public interface IInvoiceBarcodeHandler
{
InvoiceType InvoiceType { get; }

Invoice CreateInvoice(string content, string beneficiary);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using InvoiceReminder.Domain.Enums;
using InvoiceReminder.ExternalServices.BarcodeReader;
using NSubstitute;
using Shouldly;

namespace InvoiceReminder.UnitTests.ExternalServices.BarcodeReader;

[TestClass]
public sealed class BarcodeHandlerFactoryTests
{
private readonly IInvoiceBarcodeHandler _accountInvoiceHandler;
private readonly IInvoiceBarcodeHandler _bankInvoiceHandler;
private BarcodeHandlerFactory _barcodeHandlerFactory;

public BarcodeHandlerFactoryTests()
{
_accountInvoiceHandler = Substitute.For<IInvoiceBarcodeHandler>();
_bankInvoiceHandler = Substitute.For<IInvoiceBarcodeHandler>();

_ = _accountInvoiceHandler.InvoiceType.Returns(InvoiceType.AccountInvoice);
_ = _bankInvoiceHandler.InvoiceType.Returns(InvoiceType.BankInvoice);
}

[TestMethod]
public void Constructor_ShouldRegisterHandlers_WhenMultipleHandlersProvided()
{
// Arrange
var handlers = new List<IInvoiceBarcodeHandler> { _accountInvoiceHandler, _bankInvoiceHandler };

// Act
_barcodeHandlerFactory = new BarcodeHandlerFactory(handlers);

// Assert
_ = _barcodeHandlerFactory.ShouldNotBeNull();
}

[TestMethod]
public void GetHandler_ShouldReturnAccountInvoiceHandler_WhenAccountInvoiceTypeRequested()
{
// Arrange
var handlers = new List<IInvoiceBarcodeHandler> { _accountInvoiceHandler, _bankInvoiceHandler };
_barcodeHandlerFactory = new BarcodeHandlerFactory(handlers);

// Act
var handler = _barcodeHandlerFactory.GetHandler(InvoiceType.AccountInvoice);

// Assert
handler.ShouldBeSameAs(_accountInvoiceHandler);
}

[TestMethod]
public void GetHandler_ShouldReturnBankInvoiceHandler_WhenBankInvoiceTypeRequested()
{
// Arrange
var handlers = new List<IInvoiceBarcodeHandler> { _accountInvoiceHandler, _bankInvoiceHandler };
_barcodeHandlerFactory = new BarcodeHandlerFactory(handlers);

// Act
var handler = _barcodeHandlerFactory.GetHandler(InvoiceType.BankInvoice);

// Assert
handler.ShouldBeSameAs(_bankInvoiceHandler);
}

[TestMethod]
public void GetHandler_ShouldThrowNotSupportedException_WhenInvoiceTypeNotFound()
{
// Arrange
var handlers = new List<IInvoiceBarcodeHandler> { _accountInvoiceHandler };
_barcodeHandlerFactory = new BarcodeHandlerFactory(handlers);

// Act && Assert
var exception = Should.Throw<NotSupportedException>(() =>
_barcodeHandlerFactory.GetHandler(InvoiceType.BankInvoice));

exception.Message.ShouldContain("No barcode handler found for invoice type:");
}

[TestMethod]
public void GetHandler_ShouldThrowNotSupportedException_WhenNoHandlersProvided()
{
// Arrange
var handlers = new List<IInvoiceBarcodeHandler>();
_barcodeHandlerFactory = new BarcodeHandlerFactory(handlers);

// Act && Assert
var exception = Should.Throw<NotSupportedException>(() =>
_barcodeHandlerFactory.GetHandler(InvoiceType.AccountInvoice));

exception.Message.ShouldContain("No barcode handler found for invoice type:");
}

[TestMethod]
public void Constructor_ShouldThrowInvalidOperationException_WhenDuplicateHandlersProvidedForSameType()
{
// Arrange
var duplicateAccountHandler = Substitute.For<IInvoiceBarcodeHandler>();
_ = duplicateAccountHandler.InvoiceType.Returns(InvoiceType.AccountInvoice);

var handlers = new List<IInvoiceBarcodeHandler>
{
_accountInvoiceHandler,
duplicateAccountHandler,
_bankInvoiceHandler
};

// Act && Assert
var exception = Should.Throw<InvalidOperationException>(() =>
new BarcodeHandlerFactory(handlers));

exception.Message.ShouldContain("Duplicate barcode handlers registered for:");
exception.Message.ShouldContain(InvoiceType.AccountInvoice.ToString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public sealed class BarcodeReaderServiceTests
{
private readonly ILogger<BarcodeReaderService> _logger;
private readonly IInvoiceBarcodeHandler _barcodeHandler;
private readonly IBarcodeHandlerFactory _barcodeHandlerFactory;
private readonly BarcodeReaderService _barcodeReaderService;
private readonly Faker<Invoice> _invoiceFaker;
private readonly Faker _faker;
Expand All @@ -26,7 +27,8 @@ public BarcodeReaderServiceTests()
{
_logger = Substitute.For<ILogger<BarcodeReaderService>>();
_barcodeHandler = Substitute.For<IInvoiceBarcodeHandler>();
_barcodeReaderService = new BarcodeReaderService(_logger);
_barcodeHandlerFactory = Substitute.For<IBarcodeHandlerFactory>();
_barcodeReaderService = new BarcodeReaderService(_logger, _barcodeHandlerFactory);
_faker = new Faker();

_invoiceFaker = new Faker<Invoice>()
Expand Down Expand Up @@ -83,6 +85,9 @@ public void ReadTextContentFromPdf_ShouldCreateValidAccountInvoice_WhenPdfContai
var expectedInvoice = _invoiceFaker.Generate();
var password = string.Empty;

_ = _barcodeHandlerFactory.GetHandler(InvoiceType.AccountInvoice)
.Returns(_barcodeHandler);

_ = _barcodeHandler.CreateInvoice(Arg.Any<string>(), Arg.Any<string>())
.Returns(expectedInvoice);

Expand Down Expand Up @@ -111,6 +116,9 @@ public void ReadTextContentFromPdf_ShouldCreateValidBankInvoice_WhenPdfContainsB
var expectedInvoice = _invoiceFaker.Generate();
var password = string.Empty;

_ = _barcodeHandlerFactory.GetHandler(InvoiceType.BankInvoice)
.Returns(_barcodeHandler);

_ = _barcodeHandler.CreateInvoice(Arg.Any<string>(), Arg.Any<string>())
.Returns(expectedInvoice);

Expand Down