using LCU.API.Internal.LoanRate.Services; using LCU.API.Internal.LoanRate.Services.LoanRateOperationServices; using LCU.Library.Internal.Exceptions; using LCU.Library.Internal.LcuClassPatterns.CrudTests.Utilities; using LCU.Library.Internal.LoanRateModels.Entities; using LCU.Library.Internal.LoanRateModels.Responses.Validation; using LCU.Library.Internal.LoanRateModels.Responses.Validation.RateSheetValidations; using LCU.Library.Internal.TypeExtensions.ObjectExtensions; namespace LCU.API.Internal.LoanRateTests.ServiceTests.LoanRateOperationServicesTests; public class RateValidationServiceTest { private readonly RateValidationService _rateValidationService; private readonly Mock _mockRateService; public RateValidationServiceTest() { _mockRateService = new Mock(); _rateValidationService = new RateValidationService(_mockRateService.Object); } [Fact] public async Task RateValidation_ValidateAsync_Success_AllPass() { var rates = FakeRates(); foreach (var rate in rates) { var originalRate = FakeNewRate(rate, decimal.ToInt32(rate.Value - new Random().Next(0, 10)), decimal.ToInt32(rate.Value)); var rateHistory = FakeRateHistory(rate, originalRate, decimal.ToInt32(rate.Value - new Random().Next(0, 10)), decimal.ToInt32(rate.Value + new Random().Next(0, 10))); _mockRateService.Setup(x => x.GetRateHistory(It.IsAny())).ReturnsAsync(rateHistory); _mockRateService.Setup(x => x.GetByIdAsync(It.IsAny())).ReturnsAsync(originalRate); } var result = await _rateValidationService.ValidateAsync(rates); Assert.NotNull(result); Assert.True(result.All(x => x.Pass)); Assert.True(result.All(x => x.Validations.Count > 0)); _mockRateService.Verify(x => x.GetRateHistory(It.IsAny()), Times.Exactly(rates.Count)); _mockRateService.Verify(x => x.GetByIdAsync(It.IsAny()), Times.Exactly(rates.Count)); } [Fact] public async Task RateValidation_ValidateAsync_Success_DoesNotPassRange() { var rates = FakeRates(); foreach (var rate in rates) { var originalRate = FakeNewRate(rate, decimal.ToInt32(rate.Value - new Random().Next(0, 10)), decimal.ToInt32(rate.Value)); var rateHistory = FakeRateHistory(rate, originalRate, decimal.ToInt32(rate.Value - new Random().Next(0, 10)), decimal.ToInt32(rate.Value + new Random().Next(0, 10))); originalRate.Value += 100; rate.Value += 100; _mockRateService.Setup(x => x.GetRateHistory(It.IsAny())).ReturnsAsync(rateHistory); _mockRateService.Setup(x => x.GetByIdAsync(It.IsAny())).ReturnsAsync(originalRate); } var result = await _rateValidationService.ValidateAsync(rates); Assert.NotNull(result); Assert.False(result.All(x => x.Pass)); Assert.True(result.All(x => x.Validations.Count > 0)); Assert.True(result.All(x => x.Validations.First(y => y.RateSheetValidationType == RateSheetValidationTypes.IsWithinTrendRange).Pass)); Assert.False(result.All(x => x.Validations.First(y => y.RateSheetValidationType == RateSheetValidationTypes.IsWithinRange).Pass)); _mockRateService.Verify(x => x.GetRateHistory(It.IsAny()), Times.Exactly(rates.Count)); _mockRateService.Verify(x => x.GetByIdAsync(It.IsAny()), Times.Exactly(rates.Count)); } [Fact] public async Task RateValidation_ValidateAsync_Success_DoesNotPassTrend() { var rates = FakeRates(); foreach (var rate in rates) { var originalRate = FakeNewRate(rate, decimal.ToInt32(rate.Value - new Random().Next(0, 10)), decimal.ToInt32(rate.Value)); var rateHistory = FakeRateHistory(rate, originalRate, decimal.ToInt32(rate.Value - new Random().Next(0, 10)), decimal.ToInt32(rate.Value + new Random().Next(0, 10))); rateHistory.First().Value += 100; _mockRateService.Setup(x => x.GetRateHistory(It.IsAny())).ReturnsAsync(rateHistory); _mockRateService.Setup(x => x.GetByIdAsync(It.IsAny())).ReturnsAsync(originalRate); } var result = await _rateValidationService.ValidateAsync(rates); Assert.NotNull(result); Assert.False(result.All(x => x.Pass)); Assert.True(result.All(x => x.Validations.Count > 0)); Assert.False(result.All(x => x.Validations.First(y => y.RateSheetValidationType == RateSheetValidationTypes.IsWithinTrendRange).Pass)); Assert.True(result.All(x => x.Validations.First(y => y.RateSheetValidationType == RateSheetValidationTypes.IsWithinRange).Pass)); _mockRateService.Verify(x => x.GetRateHistory(It.IsAny()), Times.Exactly(rates.Count)); _mockRateService.Verify(x => x.GetByIdAsync(It.IsAny()), Times.Exactly(rates.Count)); } [Fact] public async Task RateValidation_ValidateAsync_ThrowsException() { var rates = FakeRates(); _mockRateService.Setup(x => x.GetRateHistory(rates[0])).Throws(new Exception("Test")).Verifiable(); await Assert.ThrowsAsync(async () => await _rateValidationService.ValidateAsync(rates)); _mockRateService.Verify(x => x.GetRateHistory(It.IsAny()), Times.Once); _mockRateService.Verify(x => x.GetByIdAsync(It.IsAny()), Times.Never); } private List FakeRates(int count = 3) { var rates = new List(); for (var i = 0; i < count; i++) { var startDate = (DateTime)typeof(DateTime).GetRandomValue(); rates.Add(new Rate { RateId = (int)typeof(int).GetRandomValue(), Value = new Random().Next(20, 30), Row = (string)typeof(string).GetRandomValue(), Column = (string)typeof(string).GetRandomValue(), RateStartDate = startDate, RateEndDate = startDate.AddDays(10), RateSheetId = (int)typeof(int).GetRandomValue() }); } return rates; } private Rate FakeNewRate(Rate rate, int minValue = int.MinValue, int maxValue = int.MaxValue) { var newRate = rate.DeepCopy(); newRate.RateId = (int)typeof(int).GetRandomValue(); newRate.Value = new Random().Next(minValue, maxValue); return newRate; } private List FakeRateHistory(Rate rate, Rate originalRate, int minValue = int.MinValue, int maxValue = int.MaxValue) { var rates = new List { FakeNewRate(rate, minValue, decimal.ToInt32(rate.Value)), FakeNewRate(rate, minValue, maxValue), FakeNewRate(rate, decimal.ToInt32(rate.Value), maxValue) }; var trend = Math.Round(rate.Value / originalRate.Value, 2); rates[0].RateStartDate = rate.RateStartDate.AddDays(-30); rates[0].RateEndDate = rate.RateStartDate.AddDays(-20); rates[1].RateStartDate = rate.RateStartDate.AddDays(-20); rates[1].RateEndDate = rate.RateStartDate.AddDays(-10); rates[1].Value = Math.Round(rates[0].Value * (trend + 1), 2); rates[2].RateStartDate = rate.RateStartDate.AddDays(-10); rates[2].RateEndDate = rate.RateStartDate; rates[2].Value = Math.Round(rates[1].Value * (trend - 1), 2); return rates; } }