using FinancialApi.Application.Commands; using FinancialApi.Application.Handlers; using FinancialApi.Application.Models; using FinancialApi.Domain.Entities; using FluentAssertions; using FluentAssertions.Execution; namespace FinancialApi.Application.UnitTests; public class ApplyFeeHandlerTests { [Fact] public void GivenValidAccounts_BasicFee_ShouldValidateEverything() { // Arrange var command = new ApplyFeeCommand(1, 100); var account = new Account(1, 100, AccountType.Debit); var revenueAccount = new Account(99999, 0, AccountType.Credit); var pair = new FeeContext(account, revenueAccount, TimeProvider.System.GetUtcNow()); // Act var intents = ApplyFeeHandler.Handle(command, pair); // Assert using var _ = new AssertionScope(); intents.CustomerWrite.Entity.Balance.Should() .Be(account.Balance - command.Amount); intents.RevenueWrite.Entity.Balance.Should() .Be(revenueAccount.Balance + command.Amount); intents.JournalWrite.Entity.Lines.Count.Should() .BeGreaterThanOrEqualTo(2); intents.Event.AccountId.Should() .Be(account.Id); intents.Event.Amount.Should() .Be(command.Amount); } public class LiabilityAccount { [Theory] [InlineData(100.0, 20.0, 80.0)] [InlineData(199.78, 10.0, 189.78)] [InlineData(200000, 0.09, 199999.91)] [InlineData(1000, 1000, 0)] public void GivenStartingBalanceGreaterThanFee_ApplyFee_ShouldBeExpectedBalance( decimal startingBalance, decimal feeAmount, decimal expectedBalance ) { // Arrange var command = new ApplyFeeCommand(1, feeAmount); var account = new Account(1, startingBalance, AccountType.Liability); var revenueAccount = new Account(99999, 0, AccountType.Credit); var pair = new FeeContext(account, revenueAccount, TimeProvider.System.GetUtcNow()); // Act var intents = ApplyFeeHandler.Handle(command, pair); // Assert using var _ = new AssertionScope(); intents.CustomerWrite.Entity.Balance.Should() .Be(expectedBalance); } [Theory] [InlineData(100.0, 110.0)] [InlineData(199.78, 200.0)] [InlineData(200000, 200000.01)] [InlineData(1000, 1999999)] public void GivenStartingBalanceLessThanFee_ApplyFee_ShouldFail(decimal startingBalance, decimal feeAmount) { var command = new ApplyFeeCommand(1, feeAmount); var account = new Account(1, startingBalance, AccountType.Liability); var revenueAccount = new Account(99999, 0, AccountType.Credit); var pair = new FeeContext(account, revenueAccount, TimeProvider.System.GetUtcNow()); // Act var act = () => ApplyFeeHandler.Handle(command, pair); // Assert using var _ = new AssertionScope(); act.Should() .Throw(); } } public class CreditAccount { [Theory] [InlineData(100.0, 20.0, 80.0)] [InlineData(199.78, 10.0, 189.78)] [InlineData(200000, 0.09, 199999.91)] [InlineData(1000, 1000, 0)] public void GivenStartingBalanceGreaterThanFee_ApplyFee_ShouldBeExpectedBalance( decimal startingBalance, decimal feeAmount, decimal expectedBalance ) { var command = new ApplyFeeCommand(1, feeAmount); var account = new Account(1, startingBalance, AccountType.Credit); var revenueAccount = new Account(99999, 0, AccountType.Credit); var pair = new FeeContext(account, revenueAccount, TimeProvider.System.GetUtcNow()); // Act var intents = ApplyFeeHandler.Handle(command, pair); // Assert using var _ = new AssertionScope(); intents.CustomerWrite.Entity.Balance.Should() .Be(expectedBalance); } [Theory] [InlineData(100.0, 110.0, -10.0)] [InlineData(199.78, 200.0, -0.22)] [InlineData(200000, 200000.01, -0.01)] [InlineData(1000, 1999999, -1998999)] public void GivenStartingBalanceLessThanFee_ApplyFee_ShouldBeExpectedBalance( decimal startingBalance, decimal feeAmount, decimal expectedBalance ) { var command = new ApplyFeeCommand(1, feeAmount); var account = new Account(1, startingBalance, AccountType.Credit); var revenueAccount = new Account(99999, 0, AccountType.Credit); var pair = new FeeContext(account, revenueAccount, TimeProvider.System.GetUtcNow()); // Act var intents = ApplyFeeHandler.Handle(command, pair); // Assert using var _ = new AssertionScope(); intents.CustomerWrite.Entity.Balance.Should() .Be(expectedBalance); } } }