From ccc72910d2a76ac42f23e885c33c66adcdcf797b Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 25 Oct 2024 15:38:06 +0100 Subject: [PATCH 01/44] WIP --- .../Performance/ValidatorsPerformanceTests.cs | 11 +- .../Services/ValidationServiceTests.cs | 14 +- .../Clients/CompanyDetailsApiClient.cs | 171 ++++++++++++++++++ .../Clients/ICompanyDetailsApiClient.cs | 18 ++ .../ConfigureServices.cs | 2 + .../Constants/ErrorCode.cs | 2 + .../Constants/FeatureFlags.cs | 7 + ...oducerContentValidation.Application.csproj | 7 + .../CompanyDetailsApiClientException.cs | 23 +++ .../CompanyDetailsApiAuthorisationHandler.cs | 39 ++++ .../ISubsidiaryDetailsRequestBuilder.cs | 10 + .../SubsidiaryDetailsRequestBuilder.cs | 29 +++ .../Services/ValidationService.cs | 94 +++++++++- .../SubsidiaryIdExistenceValidator.cs | 16 ++ .../SubsidiaryIdOrganisationCheck.cs | 16 ++ .../SubsidiaryIdValidator.cs | 1 - .../Config/CompanyDetailsApiConfig.cs | 16 ++ .../EPR.ProducerContentValidation.Data.csproj | 13 ++ .../CompanyDetailsDataItem.cs | 13 ++ .../CompanyDetailsDataResult.cs | 10 + .../Models/Subsidiary/SubsidiaryDetail.cs | 14 ++ .../Subsidiary/SubsidiaryDetailsRequest.cs | 10 + .../Subsidiary/SubsidiaryDetailsResponse.cs | 10 + .../SubsidiaryOrganisationDetail.cs | 12 ++ ...oducerContentValidation.FunctionApp.csproj | 2 +- .../StartUp.cs | 16 ++ .../settings.json | 3 +- src/EPR.ProducerContentValidation.sln | 31 +++- 28 files changed, 596 insertions(+), 14 deletions(-) create mode 100644 src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Exceptions/CompanyDetailsApiClientException.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Config/CompanyDetailsApiConfig.cs create mode 100644 src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj create mode 100644 src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsRequest.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsResponse.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryOrganisationDetail.cs diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs index acdfc7d..a7e5f13 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using Bogus; +using EPR.ProducerContentValidation.Application.Clients; using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; @@ -7,12 +8,14 @@ using EPR.ProducerContentValidation.Application.ReferenceData; using EPR.ProducerContentValidation.Application.Services; using EPR.ProducerContentValidation.Application.Services.Interfaces; +using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators; using EPR.ProducerContentValidation.Application.Validators.Factories; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.FeatureManagement; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -28,6 +31,9 @@ public ValidatorsPerformanceTests() Mock> validationOptionsMock = new(); Mock errorCountServiceMock = new(); Mock> loggerMock = new(); + Mock featureManagerMock = new(); + Mock subsidiaryDetailsRequestBuilderMock = new(); + Mock companyDetailsApiClientMock = new(); var submissionConfigOptions = new Mock>>(); @@ -54,7 +60,10 @@ public ValidatorsPerformanceTests() compositeValidatorUnderTest, AutoMapperHelpers.GetMapper(), errorCountServiceMock.Object, - Microsoft.Extensions.Options.Options.Create(new StorageAccountOptions { PomContainer = "ContainerName" })); + Microsoft.Extensions.Options.Options.Create(new StorageAccountOptions { PomContainer = "ContainerName" }), + featureManagerMock.Object, + subsidiaryDetailsRequestBuilderMock.Object, + companyDetailsApiClientMock.Object); } [TestMethod] diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 53aa310..635d0b0 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -1,14 +1,17 @@ using AutoMapper; +using EPR.ProducerContentValidation.Application.Clients; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Profiles; using EPR.ProducerContentValidation.Application.Services; using EPR.ProducerContentValidation.Application.Services.Interfaces; +using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.Extensions.Logging; +using Microsoft.FeatureManagement; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -29,6 +32,9 @@ public class ValidationServiceTests private Mock _compositeValidatorMock; private Mock _issueCountServiceMock; private Mock> _loggerMock; + private Mock _featureManagerMock; + private Mock _subsidiaryDetailsRequestBuilderMock; + private Mock _companyDetailsApiClientMock; [TestInitialize] public void TestInitialize() @@ -37,6 +43,9 @@ public void TestInitialize() _loggerMock = new Mock>(); _issueCountServiceMock = new Mock(); _mapper = AutoMapperHelpers.GetMapper(); + _featureManagerMock = new Mock(); + _subsidiaryDetailsRequestBuilderMock = new Mock(); + _companyDetailsApiClientMock = new Mock(); _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(ErrorStoreKey)) .ReturnsAsync(100); @@ -88,5 +97,8 @@ private ValidationService CreateSystemUnderTest() => _compositeValidatorMock.Object, _mapper, _issueCountServiceMock.Object, - Microsoft.Extensions.Options.Options.Create(new StorageAccountOptions { PomContainer = ContainerName })); + Microsoft.Extensions.Options.Options.Create(new StorageAccountOptions { PomContainer = ContainerName }), + _featureManagerMock.Object, + _subsidiaryDetailsRequestBuilderMock.Object, + _companyDetailsApiClientMock.Object); } \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs b/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs new file mode 100644 index 0000000..d1827ec --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs @@ -0,0 +1,171 @@ +using System.Net; +using EPR.ProducerContentValidation.Application.Exceptions; +using EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; + +namespace EPR.ProducerContentValidation.Application.Clients +{ + public class CompanyDetailsApiClient : ICompanyDetailsApiClient + { + private readonly HttpClient _httpClient; + private readonly ILogger _logger; + + public CompanyDetailsApiClient( + HttpClient httpClient, + ILogger logger) + { + _httpClient = httpClient; + _logger = logger; + } + + public async Task GetCompanyDetails(string organisationId) + { + try + { + var uriString = $"api/company-details/{organisationId}"; + var response = await _httpClient.GetAsync(uriString); + + if (HttpStatusCode.NotFound.Equals(response.StatusCode)) + { + return null; + } + + response.EnsureSuccessStatusCode(); + + return await DeserializeCompanyDetailsData(response); + } + catch (HttpRequestException exception) + { + const string message = "A success status code was not received when requesting company details"; + _logger.LogError(exception, message); + throw new CompanyDetailsApiClientException(message, exception); + } + } + + public async Task GetCompanyDetailsByProducer(string producerOrganisationId) + { + try + { + var uriString = $"api/company-details-by-producer/{producerOrganisationId}"; + var response = await _httpClient.GetAsync(uriString); + + if (HttpStatusCode.NotFound.Equals(response.StatusCode)) + { + return null; + } + + response.EnsureSuccessStatusCode(); + + return await DeserializeCompanyDetailsData(response); + } + catch (HttpRequestException exception) + { + const string message = "A success status code was not received when requesting company details"; + _logger.LogError(exception, message); + throw new CompanyDetailsApiClientException(message, exception); + } + } + + public async Task GetSubsidiaryDetails(SubsidiaryDetailsRequest subsidiaryDetailsRequest) + { + try + { + var uriString = "api/subsidiary-details"; + var httpContent = CreateHttpContent(subsidiaryDetailsRequest); + + var response = await _httpClient.PostAsync(uriString, httpContent); + + response.EnsureSuccessStatusCode(); + + return await DeserializeResponseData(response); + } + catch (HttpRequestException ex) + { + _logger.LogError(ex, "Error occurred while requesting subsidiary details"); + throw; + } + } + + public async Task GetComplianceSchemeMembers(string organisationId, string complianceSchemeId) + { + try + { + var uriString = $"api/company-details/{organisationId}/compliance-scheme/{complianceSchemeId}"; + var response = await _httpClient.GetAsync(uriString); + + if (HttpStatusCode.NotFound.Equals(response.StatusCode)) + { + return null; + } + + response.EnsureSuccessStatusCode(); + + return await DeserializeCompanyDetailsData(response); + } + catch (HttpRequestException exception) + { + const string message = "A success status code was not received when requesting compliance scheme member list"; + _logger.LogError(exception, message); + throw new CompanyDetailsApiClientException(message, exception); + } + } + + public async Task GetRemainingProducerDetails(IEnumerable referenceNumbers) + { + try + { + var uriString = $"api/company-details"; + + var json = JsonConvert.SerializeObject(referenceNumbers); + var httpContent = new StringContent(json, System.Text.Encoding.UTF8, "application/json"); + + var response = await _httpClient.PostAsync(uriString, httpContent); + + if (HttpStatusCode.NotFound.Equals(response.StatusCode)) + { + return null; + } + + response.EnsureSuccessStatusCode(); + + return await DeserializeCompanyDetailsData(response); + } + catch (HttpRequestException exception) + { + const string message = "A success status code was not received when requesting remaining producer company details"; + _logger.LogError(exception, message); + throw new CompanyDetailsApiClientException(message, exception); + } + } + + private static async Task DeserializeCompanyDetailsData(HttpResponseMessage response) + { + if (!string.IsNullOrEmpty(await response.Content.ReadAsStringAsync())) + { + return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + } + + return new CompanyDetailsDataResult(); + } + + private static async Task DeserializeResponseData(HttpResponseMessage response) + { + var content = await response.Content.ReadAsStringAsync(); + + if (!string.IsNullOrEmpty(content)) + { + return JsonConvert.DeserializeObject(content); + } + + return default; + } + + private StringContent CreateHttpContent(object data) + { + var json = JsonConvert.SerializeObject(data); + return new StringContent(json, System.Text.Encoding.UTF8, "application/json"); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs b/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs new file mode 100644 index 0000000..82d171e --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs @@ -0,0 +1,18 @@ +using EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Clients +{ + public interface ICompanyDetailsApiClient + { + Task GetCompanyDetails(string organisationId); + + Task GetCompanyDetailsByProducer(string producerOrganisationId); + + Task GetComplianceSchemeMembers(string organisationId, string complianceSchemeId); + + Task GetRemainingProducerDetails(IEnumerable referenceNumbers); + + Task GetSubsidiaryDetails(SubsidiaryDetailsRequest subsidiaryDetailsRequest); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs index fd38cbb..a8583b9 100644 --- a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs +++ b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs @@ -5,6 +5,7 @@ using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Services; using EPR.ProducerContentValidation.Application.Services.Interfaces; +using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators; using EPR.ProducerContentValidation.Application.Validators.Factories; using EPR.ProducerContentValidation.Application.Validators.Factories.Interfaces; @@ -88,6 +89,7 @@ private static IServiceCollection RegisterValidators(this IServiceCollection ser services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); return services; } diff --git a/src/EPR.ProducerContentValidation.Application/Constants/ErrorCode.cs b/src/EPR.ProducerContentValidation.Application/Constants/ErrorCode.cs index 56bac4f..e96214f 100644 --- a/src/EPR.ProducerContentValidation.Application/Constants/ErrorCode.cs +++ b/src/EPR.ProducerContentValidation.Application/Constants/ErrorCode.cs @@ -54,6 +54,8 @@ public static class ErrorCode public const string WarningOnlyOnePackagingMaterialReported = "62"; public const string WarningPackagingTypePackagingMaterial = "63"; public const string WarningPackagingTypeQuantityUnitsLessThanQuantityKgs = "64"; + public const string SubsidiaryIdDoesNotExist = "70"; + public const string SubsidiaryIdIsAssignedToADifferentOrganisation = "71"; /* Issue codes 80 through 89 should be reserved for Issues from the Check Splitter API */ public const string UncaughtExceptionErrorCode = "99"; diff --git a/src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs b/src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs new file mode 100644 index 0000000..72ef6a1 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs @@ -0,0 +1,7 @@ +namespace EPR.ProducerContentValidation.Application.Constants +{ + public static class FeatureFlags + { + public const string EnableSubsidiaryValidation = "EnableSubsidiaryValidation"; + } +} diff --git a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj index 401dfd8..eda8453 100644 --- a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj +++ b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj @@ -8,6 +8,8 @@ + + @@ -18,8 +20,13 @@ + + + + + \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Application/Exceptions/CompanyDetailsApiClientException.cs b/src/EPR.ProducerContentValidation.Application/Exceptions/CompanyDetailsApiClientException.cs new file mode 100644 index 0000000..6f415be --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Exceptions/CompanyDetailsApiClientException.cs @@ -0,0 +1,23 @@ +using System.Diagnostics.CodeAnalysis; + +namespace EPR.ProducerContentValidation.Application.Exceptions +{ + [ExcludeFromCodeCoverage] + [Serializable] + public class CompanyDetailsApiClientException : Exception + { + public CompanyDetailsApiClientException() + { + } + + public CompanyDetailsApiClientException(string message) + : base(message) + { + } + + public CompanyDetailsApiClientException(string message, Exception inner) + : base(message, inner) + { + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs b/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs new file mode 100644 index 0000000..8513db8 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs @@ -0,0 +1,39 @@ +using System.Diagnostics.CodeAnalysis; +using System.Net.Http.Headers; +using Azure.Core; +using Azure.Identity; +using EPR.ProducerContentValidation.Data.Config; +using Microsoft.Extensions.Options; + +namespace EPR.ProducerContentValidation.Application.Handlers +{ + [ExcludeFromCodeCoverage(Justification = "Dependency on Azure to acquire token, will be assured via end to end testing.")] + public class CompanyDetailsApiAuthorisationHandler : DelegatingHandler + { + private const string BearerScheme = "Bearer"; + private readonly TokenRequestContext _tokenRequestContext; + private readonly DefaultAzureCredential? _credentials; + + public CompanyDetailsApiAuthorisationHandler(IOptions options) + { + if (string.IsNullOrEmpty(options.Value.ClientId)) + { + return; + } + + _tokenRequestContext = new TokenRequestContext(new[] { options.Value.ClientId }); + _credentials = new DefaultAzureCredential(); + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + if (_credentials != null) + { + var tokenResult = await _credentials.GetTokenAsync(_tokenRequestContext, cancellationToken); + request.Headers.Authorization = new AuthenticationHeaderValue(BearerScheme, tokenResult.Token); + } + + return await base.SendAsync(request, cancellationToken); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs new file mode 100644 index 0000000..c4eda28 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs @@ -0,0 +1,10 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Subsidiary +{ + public interface ISubsidiaryDetailsRequestBuilder + { + SubsidiaryDetailsRequest CreateRequest(List rows); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs new file mode 100644 index 0000000..c5e794f --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs @@ -0,0 +1,29 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Subsidiary +{ + public class SubsidiaryDetailsRequestBuilder : ISubsidiaryDetailsRequestBuilder + { + public SubsidiaryDetailsRequest CreateRequest(List rows) + { + var subsidiaryDetailsRequest = new SubsidiaryDetailsRequest + { + SubsidiaryOrganisationDetails = rows + .GroupBy(row => row.ProducerId) + .Select(group => new SubsidiaryOrganisationDetail + { + OrganisationReference = group.Key, + SubsidiaryDetails = group + .Where(row => !string.IsNullOrEmpty(row.SubsidiaryId)) + .Select(row => new SubsidiaryDetail + { + ReferenceNumber = row.SubsidiaryId, + }).ToList(), + }) + .ToList(), + }; + return subsidiaryDetailsRequest; + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index a2893ed..39378c3 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -1,13 +1,16 @@ using AutoMapper; +using EPR.ProducerContentValidation.Application.Clients; using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Extensions; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Services.Interfaces; +using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Microsoft.FeatureManagement; namespace EPR.ProducerContentValidation.Application.Services; @@ -18,19 +21,28 @@ public class ValidationService : IValidationService private readonly IMapper _mapper; private readonly IIssueCountService _issueCountService; private readonly StorageAccountOptions _storageAccountOptions; + private readonly ISubsidiaryDetailsRequestBuilder _subsidiaryDetailsRequestBuilder; + private readonly ICompanyDetailsApiClient _companyDetailsApiClient; + private IFeatureManager _featureManager; public ValidationService( ILogger logger, ICompositeValidator compositeValidator, IMapper mapper, IIssueCountService issueCountService, - IOptions storageAccountOptions) + IOptions storageAccountOptions, + IFeatureManager featureManager, + ISubsidiaryDetailsRequestBuilder subsidiaryDetailsRequestBuilder, + ICompanyDetailsApiClient companyDetailsApiClient) { _logger = logger; _compositeValidator = compositeValidator; _mapper = mapper; _issueCountService = issueCountService; _storageAccountOptions = storageAccountOptions.Value; + _featureManager = featureManager; + _subsidiaryDetailsRequestBuilder = subsidiaryDetailsRequestBuilder; + _companyDetailsApiClient = companyDetailsApiClient; } public async Task ValidateAsync(Producer producer) @@ -63,8 +75,88 @@ public async Task ValidateAsync(Producer producer) producerValidationOutRequest.ValidationErrors.AddRange(errors); producerValidationOutRequest.ValidationWarnings.AddRange(warnings); + if (await _featureManager.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)) + { + List subValidationResult = await ValidateSubsidiary(producer.Rows); + producerValidationOutRequest.ValidationErrors.AddRange(subValidationResult.Take(remainingErrorCapacity - errors.Count)); + } + _logger.LogExit(); return producerValidationOutRequest; } + + public async Task> ValidateSubsidiary(List rows) + { + List validationErrors = new(); + try + { + var subsidiaryDetailsRequest = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + if (subsidiaryDetailsRequest == null || subsidiaryDetailsRequest.SubsidiaryOrganisationDetails == null || !subsidiaryDetailsRequest.SubsidiaryOrganisationDetails.Any()) + { + return validationErrors; + } + + var result = await _companyDetailsApiClient.GetSubsidiaryDetails(subsidiaryDetailsRequest); + + for (int i = 0; i < rows.Count; i++) + { + var matchingOrg = result.SubsidiaryOrganisationDetails + .FirstOrDefault(org => org.OrganisationReference == rows[i].ProducerId); + + if (matchingOrg == null) + { + continue; + } + + var matchingSub = matchingOrg.SubsidiaryDetails + .FirstOrDefault(sub => sub.ReferenceNumber == rows[i].SubsidiaryId); + + if (matchingSub == null) + { + continue; + } + + if (!matchingSub.SubsidiaryExists) + { + var error = CreateSubValidationError(rows[i], ErrorCode.SubsidiaryIdDoesNotExist); + var errorMessage = $"Subsidiary ID does not exist"; + + LogValidationWarning(i + 1, errorMessage, ErrorCode.SubsidiaryIdDoesNotExist); // Idris - remove? + validationErrors.Add(error); + continue; + } + + if (!matchingSub.SubsidiaryBelongsToOrganisation) + { + var error = CreateSubValidationError(rows[i], ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); + var errorMessage = $"Subsidiary ID is assigned to a different organisation"; + + LogValidationWarning(i + 1, errorMessage, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); + validationErrors.Add(error); + } + } + + return validationErrors; + } + catch (HttpRequestException exception) + { + _logger.LogError(exception, "Error Subsidiary validation"); + return validationErrors; + } + } + + private void LogValidationWarning(int rowNumber, string errorMessage, string errorCode) + { + _logger.LogWarning( + "Validation error on row {Row} {ErrorMessage} Error code {ErrorCode}", + rowNumber, + errorMessage, + errorCode); + } + + private ProducerValidationEventIssueRequest CreateSubValidationError(ProducerRow row, object subsidiaryIdDoesNotExist) + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs new file mode 100644 index 0000000..f725052 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs @@ -0,0 +1,16 @@ +using EPR.ProducerContentValidation.Application.Constants; +using EPR.ProducerContentValidation.Application.Models; +using FluentValidation; + +namespace EPR.ProducerContentValidation.Application.Validators.PropertyValidators +{ + public class SubsidiaryIdExistenceValidator : AbstractValidator + { + public SubsidiaryIdExistenceValidator() + { + RuleFor(x => x.SubsidiaryId) + .NotEqual("true") + .WithErrorCode(ErrorCode.SubsidiaryIdDoesNotExist); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs new file mode 100644 index 0000000..c92235e --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs @@ -0,0 +1,16 @@ +using EPR.ProducerContentValidation.Application.Constants; +using EPR.ProducerContentValidation.Application.Models; +using FluentValidation; + +namespace EPR.ProducerContentValidation.Application.Validators.PropertyValidators +{ + public class SubsidiaryIdOrganisationCheck : AbstractValidator + { + public SubsidiaryIdOrganisationCheck() + { + RuleFor(x => x.SubsidiaryId) + .NotEqual("true") + .WithErrorCode(ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdValidator.cs b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdValidator.cs index 2fd393b..880e482 100644 --- a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdValidator.cs @@ -1,7 +1,6 @@ namespace EPR.ProducerContentValidation.Application.Validators.PropertyValidators; using Constants; -using CustomValidators; using FluentValidation; using Models; diff --git a/src/EPR.ProducerContentValidation.Data/Config/CompanyDetailsApiConfig.cs b/src/EPR.ProducerContentValidation.Data/Config/CompanyDetailsApiConfig.cs new file mode 100644 index 0000000..d890038 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Config/CompanyDetailsApiConfig.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; + +namespace EPR.ProducerContentValidation.Data.Config +{ + public class CompanyDetailsApiConfig + { + public const string Section = "CompanyDetailsApi"; + + [Required] + public string BaseUrl { get; init; } + + public string? ClientId { get; set; } + + public int Timeout { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj b/src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj new file mode 100644 index 0000000..3b5b170 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs new file mode 100644 index 0000000..3e7df3e --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi +{ + public class CompanyDetailsDataItem + { + [JsonProperty("RN")] + public string ReferenceNumber { get; set; } + + [JsonProperty("CHN")] + public string CompaniesHouseNumber { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs new file mode 100644 index 0000000..0650e48 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi +{ + public class CompanyDetailsDataResult + { + [JsonProperty(nameof(Organisations))] + public IEnumerable Organisations { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs new file mode 100644 index 0000000..cb92f85 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs @@ -0,0 +1,14 @@ +using System.Diagnostics.CodeAnalysis; + +namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +{ + [ExcludeFromCodeCoverage] + public class SubsidiaryDetail + { + public string ReferenceNumber { get; set; } + + public bool SubsidiaryExists { get; set; } + + public bool SubsidiaryBelongsToOrganisation { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsRequest.cs b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsRequest.cs new file mode 100644 index 0000000..c3a3f47 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsRequest.cs @@ -0,0 +1,10 @@ +using System.Diagnostics.CodeAnalysis; + +namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +{ + [ExcludeFromCodeCoverage] + public class SubsidiaryDetailsRequest + { + public List SubsidiaryOrganisationDetails { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsResponse.cs b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsResponse.cs new file mode 100644 index 0000000..7a82d14 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsResponse.cs @@ -0,0 +1,10 @@ +using System.Diagnostics.CodeAnalysis; + +namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +{ + [ExcludeFromCodeCoverage] + public class SubsidiaryDetailsResponse + { + public List SubsidiaryOrganisationDetails { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryOrganisationDetail.cs b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryOrganisationDetail.cs new file mode 100644 index 0000000..c467b0c --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryOrganisationDetail.cs @@ -0,0 +1,12 @@ +using System.Diagnostics.CodeAnalysis; + +namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +{ + [ExcludeFromCodeCoverage] + public class SubsidiaryOrganisationDetail + { + public string OrganisationReference { get; set; } + + public List SubsidiaryDetails { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.FunctionApp/EPR.ProducerContentValidation.FunctionApp.csproj b/src/EPR.ProducerContentValidation.FunctionApp/EPR.ProducerContentValidation.FunctionApp.csproj index 7377347..efecc77 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/EPR.ProducerContentValidation.FunctionApp.csproj +++ b/src/EPR.ProducerContentValidation.FunctionApp/EPR.ProducerContentValidation.FunctionApp.csproj @@ -5,7 +5,7 @@ net8.0 - + diff --git a/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs b/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs index 978e3db..60826d1 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs +++ b/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs @@ -6,9 +6,15 @@ namespace EPR.ProducerContentValidation.FunctionApp; using System.Diagnostics.CodeAnalysis; +using System.Net.Http.Headers; using Application; +using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Application.Handlers; +using EPR.ProducerContentValidation.Data.Config; using Microsoft.Azure.Functions.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Microsoft.FeatureManagement; [ExcludeFromCodeCoverage] public class StartUp : FunctionsStartup @@ -17,8 +23,18 @@ public override void Configure(IFunctionsHostBuilder builder) { var services = builder.Services; + services.AddFeatureManagement(); services.AddApplicationServices(); services.AddFunctionServices(); services.AddApplicationInsightsTelemetry(); + + services.AddHttpClient((sp, c) => + { + var companyDetailsApiConfig = sp.GetRequiredService>().Value; + c.BaseAddress = new Uri(companyDetailsApiConfig.BaseUrl); + c.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + c.Timeout = TimeSpan.FromSeconds(companyDetailsApiConfig.Timeout); + }) + .AddHttpMessageHandler(); } } \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.FunctionApp/settings.json b/src/EPR.ProducerContentValidation.FunctionApp/settings.json index 8cb97f3..2fe27a2 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/settings.json +++ b/src/EPR.ProducerContentValidation.FunctionApp/settings.json @@ -9,6 +9,7 @@ "StorageAccount:PomContainer": "pom-upload-container", "Validation:MaxIssuesToProcess": 1000, "Redis:ConnectionString": "https://localhost:1234", - "Validation:IsLatest": false + "Validation:IsLatest": false, + "FeatureManagement:EnableSubsidiaryValidation": false } } diff --git a/src/EPR.ProducerContentValidation.sln b/src/EPR.ProducerContentValidation.sln index d454113..c7705fe 100644 --- a/src/EPR.ProducerContentValidation.sln +++ b/src/EPR.ProducerContentValidation.sln @@ -1,24 +1,29 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.FunctionApp", "EPR.ProducerContentValidation.FunctionApp\EPR.ProducerContentValidation.FunctionApp.csproj", "{28E03AA1-AB29-41C5-9749-8E657B523677}" +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.FunctionApp", "EPR.ProducerContentValidation.FunctionApp\EPR.ProducerContentValidation.FunctionApp.csproj", "{28E03AA1-AB29-41C5-9749-8E657B523677}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.FunctionApp.UnitTests", "EPR.ProducerContentValidation.FunctionApp.UnitTests\EPR.ProducerContentValidation.FunctionApp.UnitTests.csproj", "{B320427A-D6E5-4526-850A-4CD6395B40A3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.FunctionApp.UnitTests", "EPR.ProducerContentValidation.FunctionApp.UnitTests\EPR.ProducerContentValidation.FunctionApp.UnitTests.csproj", "{B320427A-D6E5-4526-850A-4CD6395B40A3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.Application", "EPR.ProducerContentValidation.Application\EPR.ProducerContentValidation.Application.csproj", "{05AFF197-3A91-4785-A053-C949984A0168}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.Application", "EPR.ProducerContentValidation.Application\EPR.ProducerContentValidation.Application.csproj", "{05AFF197-3A91-4785-A053-C949984A0168}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.Application.UnitTests", "EPR.ProducerContentValidation.Application.UnitTests\EPR.ProducerContentValidation.Application.UnitTests.csproj", "{41F0031E-EFF7-4C25-9934-5C5D9A95C85C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.Application.UnitTests", "EPR.ProducerContentValidation.Application.UnitTests\EPR.ProducerContentValidation.Application.UnitTests.csproj", "{41F0031E-EFF7-4C25-9934-5C5D9A95C85C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.TestSupport", "EPR.ProducerContentValidation.TestSupport\EPR.ProducerContentValidation.TestSupport.csproj", "{3CFB967D-D84E-44E0-91A4-55B44EEC5215}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.TestSupport", "EPR.ProducerContentValidation.TestSupport\EPR.ProducerContentValidation.TestSupport.csproj", "{3CFB967D-D84E-44E0-91A4-55B44EEC5215}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0408BD47-B8AF-4972-9D34-41078B6EE09E}" ProjectSection(SolutionItems) = preProject - Directory.Build.props = Directory.Build.props - stylecop.ruleset = stylecop.ruleset - ..\README.md = ..\README.md ..\CONTRIBUTING.md = ..\CONTRIBUTING.md + Directory.Build.props = Directory.Build.props ..\LICENCE.md = ..\LICENCE.md + ..\README.md = ..\README.md + stylecop.ruleset = stylecop.ruleset EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.Data", "EPR.ProducerContentValidation.Data\EPR.ProducerContentValidation.Data.csproj", "{0944BDFE-6DD0-48E0-8A08-A36203138D43}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,5 +50,15 @@ Global {3CFB967D-D84E-44E0-91A4-55B44EEC5215}.Debug|Any CPU.Build.0 = Debug|Any CPU {3CFB967D-D84E-44E0-91A4-55B44EEC5215}.Release|Any CPU.ActiveCfg = Release|Any CPU {3CFB967D-D84E-44E0-91A4-55B44EEC5215}.Release|Any CPU.Build.0 = Release|Any CPU + {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0DBBE26A-4E2C-4007-8F12-99D10A5FB5BC} EndGlobalSection EndGlobal From 96f35bf3f8c8cc3b354ca1d2cd409888342d3e69 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 25 Oct 2024 17:38:41 +0100 Subject: [PATCH 02/44] WIP --- .gitignore | 1 + .../Clients/CompanyDetailsApiClient.cs | 115 +----------------- .../Clients/ICompanyDetailsApiClient.cs | 11 +- .../CompanyDetailsDataItem.cs | 13 -- .../CompanyDetailsDataResult.cs | 10 -- .../settings.json | 3 + 6 files changed, 6 insertions(+), 147 deletions(-) delete mode 100644 src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs delete mode 100644 src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs diff --git a/.gitignore b/.gitignore index d342c2f..b72df34 100644 --- a/.gitignore +++ b/.gitignore @@ -414,3 +414,4 @@ FodyWeavers.xsd # AppSettings Development file **/appSettings.Development.json /src/EPR.ProducerContentValidation.FunctionApp/localSettings.json +/src/EPR.ProducerContentValidation.FunctionApp/local.settings 18.json diff --git a/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs b/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs index d1827ec..05c886b 100644 --- a/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs +++ b/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs @@ -1,7 +1,4 @@ -using System.Net; -using EPR.ProducerContentValidation.Application.Exceptions; -using EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; using Microsoft.Extensions.Logging; using Newtonsoft.Json; @@ -20,54 +17,6 @@ public CompanyDetailsApiClient( _logger = logger; } - public async Task GetCompanyDetails(string organisationId) - { - try - { - var uriString = $"api/company-details/{organisationId}"; - var response = await _httpClient.GetAsync(uriString); - - if (HttpStatusCode.NotFound.Equals(response.StatusCode)) - { - return null; - } - - response.EnsureSuccessStatusCode(); - - return await DeserializeCompanyDetailsData(response); - } - catch (HttpRequestException exception) - { - const string message = "A success status code was not received when requesting company details"; - _logger.LogError(exception, message); - throw new CompanyDetailsApiClientException(message, exception); - } - } - - public async Task GetCompanyDetailsByProducer(string producerOrganisationId) - { - try - { - var uriString = $"api/company-details-by-producer/{producerOrganisationId}"; - var response = await _httpClient.GetAsync(uriString); - - if (HttpStatusCode.NotFound.Equals(response.StatusCode)) - { - return null; - } - - response.EnsureSuccessStatusCode(); - - return await DeserializeCompanyDetailsData(response); - } - catch (HttpRequestException exception) - { - const string message = "A success status code was not received when requesting company details"; - _logger.LogError(exception, message); - throw new CompanyDetailsApiClientException(message, exception); - } - } - public async Task GetSubsidiaryDetails(SubsidiaryDetailsRequest subsidiaryDetailsRequest) { try @@ -88,68 +37,6 @@ public async Task GetSubsidiaryDetails(SubsidiaryDeta } } - public async Task GetComplianceSchemeMembers(string organisationId, string complianceSchemeId) - { - try - { - var uriString = $"api/company-details/{organisationId}/compliance-scheme/{complianceSchemeId}"; - var response = await _httpClient.GetAsync(uriString); - - if (HttpStatusCode.NotFound.Equals(response.StatusCode)) - { - return null; - } - - response.EnsureSuccessStatusCode(); - - return await DeserializeCompanyDetailsData(response); - } - catch (HttpRequestException exception) - { - const string message = "A success status code was not received when requesting compliance scheme member list"; - _logger.LogError(exception, message); - throw new CompanyDetailsApiClientException(message, exception); - } - } - - public async Task GetRemainingProducerDetails(IEnumerable referenceNumbers) - { - try - { - var uriString = $"api/company-details"; - - var json = JsonConvert.SerializeObject(referenceNumbers); - var httpContent = new StringContent(json, System.Text.Encoding.UTF8, "application/json"); - - var response = await _httpClient.PostAsync(uriString, httpContent); - - if (HttpStatusCode.NotFound.Equals(response.StatusCode)) - { - return null; - } - - response.EnsureSuccessStatusCode(); - - return await DeserializeCompanyDetailsData(response); - } - catch (HttpRequestException exception) - { - const string message = "A success status code was not received when requesting remaining producer company details"; - _logger.LogError(exception, message); - throw new CompanyDetailsApiClientException(message, exception); - } - } - - private static async Task DeserializeCompanyDetailsData(HttpResponseMessage response) - { - if (!string.IsNullOrEmpty(await response.Content.ReadAsStringAsync())) - { - return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - } - - return new CompanyDetailsDataResult(); - } - private static async Task DeserializeResponseData(HttpResponseMessage response) { var content = await response.Content.ReadAsStringAsync(); diff --git a/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs b/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs index 82d171e..79086d9 100644 --- a/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs +++ b/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs @@ -1,18 +1,9 @@ -using EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Clients { public interface ICompanyDetailsApiClient { - Task GetCompanyDetails(string organisationId); - - Task GetCompanyDetailsByProducer(string producerOrganisationId); - - Task GetComplianceSchemeMembers(string organisationId, string complianceSchemeId); - - Task GetRemainingProducerDetails(IEnumerable referenceNumbers); - Task GetSubsidiaryDetails(SubsidiaryDetailsRequest subsidiaryDetailsRequest); } } diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs deleted file mode 100644 index 3e7df3e..0000000 --- a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Newtonsoft.Json; - -namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi -{ - public class CompanyDetailsDataItem - { - [JsonProperty("RN")] - public string ReferenceNumber { get; set; } - - [JsonProperty("CHN")] - public string CompaniesHouseNumber { get; set; } - } -} diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs deleted file mode 100644 index 0650e48..0000000 --- a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi -{ - public class CompanyDetailsDataResult - { - [JsonProperty(nameof(Organisations))] - public IEnumerable Organisations { get; set; } - } -} diff --git a/src/EPR.ProducerContentValidation.FunctionApp/settings.json b/src/EPR.ProducerContentValidation.FunctionApp/settings.json index 2fe27a2..9d0d533 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/settings.json +++ b/src/EPR.ProducerContentValidation.FunctionApp/settings.json @@ -5,6 +5,9 @@ "ServiceBus:ConnectionString": "Endpoint=sb://devrwdinfsb1401.servicebus.windows.net/", "ServiceBus:SplitQueueName": "defra.epr.producer.data", "SubmissionApi:BaseUrl": "https://localhost:1234", + "CompanyDetailsApi:BaseUrl": "http://localhost:7076/", + "CompanyDetailsApi:Timeout": 10, + "CompanyDetailsApi:ClientId": "", "Validation:Disabled": false, "StorageAccount:PomContainer": "pom-upload-container", "Validation:MaxIssuesToProcess": 1000, From 05d9eb356f28e30e3629dd408b121b86ed815873 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Sun, 27 Oct 2024 21:08:41 +0000 Subject: [PATCH 03/44] Unit tests for subsidiary validation --- .../Services/ValidationServiceTests.cs | 168 ++++++++++++++++++ .../Services/ValidationService.cs | 2 +- ...ProducerContentValidation.UnitTests.csproj | 50 ++++++ .../Properties/AssemblyInfo.cs | 20 +++ .../UnitTest1.cs | 14 ++ src/EPR.ProducerContentValidation.sln | 2 +- 6 files changed, 254 insertions(+), 2 deletions(-) create mode 100644 src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj create mode 100644 src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs create mode 100644 src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 635d0b0..a1fbafc 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -1,5 +1,6 @@ using AutoMapper; using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; @@ -8,6 +9,7 @@ using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.Extensions.Logging; @@ -91,6 +93,172 @@ public async Task ValidateAsync_ValidatesForErrorsAndWarnings_DoesNotCallComposi _compositeValidatorMock.Verify(x => x.ValidateDuplicatesAndGroupedData(producerRows, new List(), It.IsAny>(), BlobName), Times.Never); } + [TestMethod] + public async Task ValidateSubsidiary_SuccessfulValidation_ReturnsEmptyList() + { + // Arrange + var rows = new List { /* example ProducerRow data */ }; + var subsidiaryDetailsRequest = new SubsidiaryDetailsRequest(); + var subsidiaryDetailsResponse = new SubsidiaryDetailsResponse + { + SubsidiaryOrganisationDetails = new List + { + new SubsidiaryOrganisationDetail + { + OrganisationReference = "OrgRef", + SubsidiaryDetails = new List + { + new SubsidiaryDetail + { + ReferenceNumber = "SubRef", + SubsidiaryExists = true, + SubsidiaryBelongsToOrganisation = true + } + } + } + } + }; + + _subsidiaryDetailsRequestBuilderMock + .Setup(x => x.CreateRequest(rows)) + .Returns(subsidiaryDetailsRequest); + + _companyDetailsApiClientMock + .Setup(x => x.GetSubsidiaryDetails(subsidiaryDetailsRequest)) + .ReturnsAsync(subsidiaryDetailsResponse); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateSubsidiary(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); + } + + [TestMethod] + public async Task ValidateSubsidiary_NullSubsidiaryDetailsResponse_ReturnsEmptyList() + { + // Arrange + var rows = new List { /* example ProducerRow data */ }; + _subsidiaryDetailsRequestBuilderMock + .Setup(x => x.CreateRequest(rows)) + .Returns((SubsidiaryDetailsRequest)null); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateSubsidiary(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); + } + + [TestMethod] + public async Task ValidateSubsidiary_HttpRequestException_LogsErrorAndReturnsEmptyList() + { + // Arrange + var rows = new List { /* example ProducerRow data */ }; + var exception = new HttpRequestException("An error occurred while creating the request."); + + _subsidiaryDetailsRequestBuilderMock + .Setup(x => x.CreateRequest(It.IsAny>())) + .Throws(exception); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateSubsidiary(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); + _loggerMock.Verify( + x => x.Log( + LogLevel.Error, + It.IsAny(), + It.Is((v, t) => v.ToString().Contains("Error Subsidiary validation")), + It.Is(ex => ex == exception), + It.IsAny>()), + Times.Once); + } + + [TestMethod] + public async Task ValidateAsync_WithSubsidiaryValidationEnabled_PerformsSubsidiaryValidation() + { + // Arrange + var producerRows = new List { ModelGenerator.CreateProducerRow(1) }; + var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); + + var validationErrors = new List(); + + _featureManagerMock + .Setup(fm => fm.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)) + .ReturnsAsync(true); + + _subsidiaryDetailsRequestBuilderMock + .Setup(x => x.CreateRequest(producer.Rows)) + .Returns(new SubsidiaryDetailsRequest() + { + SubsidiaryOrganisationDetails = new List() + { + new SubsidiaryOrganisationDetail() + { } + } + }); + + var subsidiaryOrganisationDetails = new List(); + subsidiaryOrganisationDetails.Add(new SubsidiaryOrganisationDetail + { + OrganisationReference = "sds", + SubsidiaryDetails = new List() + }); + var subsidiaryDetailsResponse = new SubsidiaryDetailsResponse(); + subsidiaryDetailsResponse.SubsidiaryOrganisationDetails = subsidiaryOrganisationDetails; + + _companyDetailsApiClientMock + .Setup(x => x.GetSubsidiaryDetails(It.IsAny())) + .ReturnsAsync(subsidiaryDetailsResponse); + + _issueCountServiceMock + .Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())) + .ReturnsAsync(1); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(producer.Rows), Times.Once); + _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Once); + } + + [TestMethod] + public async Task ValidateAsync_WithSubsidiaryValidationDisabled_SkipsSubsidiaryValidation() + { + // Arrange + var producerRows = new List { ModelGenerator.CreateProducerRow(1) }; + var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); + + // Mock feature flag to disable subsidiary validation + _featureManagerMock + .Setup(fm => fm.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)) + .ReturnsAsync(false); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(It.IsAny>()), Times.Never); + _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Never); + result.ValidationErrors.Should().BeEmpty(); + } + private ValidationService CreateSystemUnderTest() => new( _loggerMock.Object, diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index 39378c3..4056839 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -122,7 +122,7 @@ public async Task> ValidateSubsidiary( var error = CreateSubValidationError(rows[i], ErrorCode.SubsidiaryIdDoesNotExist); var errorMessage = $"Subsidiary ID does not exist"; - LogValidationWarning(i + 1, errorMessage, ErrorCode.SubsidiaryIdDoesNotExist); // Idris - remove? + LogValidationWarning(i + 1, errorMessage, ErrorCode.SubsidiaryIdDoesNotExist); validationErrors.Add(error); continue; } diff --git a/src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj b/src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj new file mode 100644 index 0000000..6783e83 --- /dev/null +++ b/src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj @@ -0,0 +1,50 @@ + + + + + Debug + AnyCPU + {E7C40F24-549B-494A-AEF1-325C5658C9A0} + Library + Properties + EPR.ProducerContentValidation.UnitTests + EPR.ProducerContentValidation.UnitTests + v4.7.2 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs b/src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..917489b --- /dev/null +++ b/src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("EPR.ProducerContentValidation.UnitTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("EPR.ProducerContentValidation.UnitTests")] +[assembly: AssemblyCopyright("Copyright © 2024")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: Guid("e7c40f24-549b-494a-aef1-325c5658c9a0")] + +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs b/src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs new file mode 100644 index 0000000..0f13eca --- /dev/null +++ b/src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs @@ -0,0 +1,14 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; + +namespace EPR.ProducerContentValidation.UnitTests +{ + [TestClass] + public class UnitTest1 + { + [TestMethod] + public void TestMethod1() + { + } + } +} diff --git a/src/EPR.ProducerContentValidation.sln b/src/EPR.ProducerContentValidation.sln index c7705fe..d092b76 100644 --- a/src/EPR.ProducerContentValidation.sln +++ b/src/EPR.ProducerContentValidation.sln @@ -22,7 +22,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution stylecop.ruleset = stylecop.ruleset EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.Data", "EPR.ProducerContentValidation.Data\EPR.ProducerContentValidation.Data.csproj", "{0944BDFE-6DD0-48E0-8A08-A36203138D43}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.Data", "EPR.ProducerContentValidation.Data\EPR.ProducerContentValidation.Data.csproj", "{0944BDFE-6DD0-48E0-8A08-A36203138D43}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From 8d5253b2e65e44ce89f690ffa4458b49925f7e24 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Mon, 28 Oct 2024 00:37:01 +0000 Subject: [PATCH 04/44] Unit tests --- .../SubsidiaryDetailsRequestBuilder.cs | 1 + .../SubsidiaryIdExistenceValidator.cs | 16 - .../SubsidiaryIdOrganisationCheck.cs | 16 - .../Clients/CompanyDetailsApiClientTests.cs | 109 +++++++ ....ProducerContentValidation.UnitTest.csproj | 30 ++ .../SubsidiaryDetailsRequestBuilderTests.cs | 291 ++++++++++++++++++ ...ProducerContentValidation.UnitTests.csproj | 50 --- .../Properties/AssemblyInfo.cs | 20 -- .../UnitTest1.cs | 14 - src/EPR.ProducerContentValidation.sln | 6 + 10 files changed, 437 insertions(+), 116 deletions(-) delete mode 100644 src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs delete mode 100644 src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs create mode 100644 src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs create mode 100644 src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj create mode 100644 src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs delete mode 100644 src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj delete mode 100644 src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs delete mode 100644 src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs diff --git a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs index c5e794f..8084dcb 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs @@ -11,6 +11,7 @@ public SubsidiaryDetailsRequest CreateRequest(List rows) { SubsidiaryOrganisationDetails = rows .GroupBy(row => row.ProducerId) + .Where(group => group.Any(row => !string.IsNullOrEmpty(row.SubsidiaryId))) .Select(group => new SubsidiaryOrganisationDetail { OrganisationReference = group.Key, diff --git a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs deleted file mode 100644 index f725052..0000000 --- a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdExistenceValidator.cs +++ /dev/null @@ -1,16 +0,0 @@ -using EPR.ProducerContentValidation.Application.Constants; -using EPR.ProducerContentValidation.Application.Models; -using FluentValidation; - -namespace EPR.ProducerContentValidation.Application.Validators.PropertyValidators -{ - public class SubsidiaryIdExistenceValidator : AbstractValidator - { - public SubsidiaryIdExistenceValidator() - { - RuleFor(x => x.SubsidiaryId) - .NotEqual("true") - .WithErrorCode(ErrorCode.SubsidiaryIdDoesNotExist); - } - } -} diff --git a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs b/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs deleted file mode 100644 index c92235e..0000000 --- a/src/EPR.ProducerContentValidation.Application/Validators/PropertyValidators/SubsidiaryIdOrganisationCheck.cs +++ /dev/null @@ -1,16 +0,0 @@ -using EPR.ProducerContentValidation.Application.Constants; -using EPR.ProducerContentValidation.Application.Models; -using FluentValidation; - -namespace EPR.ProducerContentValidation.Application.Validators.PropertyValidators -{ - public class SubsidiaryIdOrganisationCheck : AbstractValidator - { - public SubsidiaryIdOrganisationCheck() - { - RuleFor(x => x.SubsidiaryId) - .NotEqual("true") - .WithErrorCode(ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); - } - } -} diff --git a/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs b/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs new file mode 100644 index 0000000..59c6c17 --- /dev/null +++ b/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs @@ -0,0 +1,109 @@ +using System.Net; +using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Data.Config; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using FluentAssertions; +using Microsoft.Extensions.Logging.Abstractions; +using Moq; +using Moq.Protected; +using Newtonsoft.Json; + +namespace EPR.ProducerContentValidation.UnitTest.Clients +{ + [TestClass] + public class CompanyDetailsApiClientTests + { + private CompanyDetailsApiConfig? _config; + + [TestInitialize] + public void Setup() + { + _config = new CompanyDetailsApiConfig + { + BaseUrl = "https://www.testurl.com", + ClientId = "test-client-id", + Timeout = 5, + }; + } + + [TestMethod] + public async Task GetSubsidiaryDetails_ShouldReturnSubsidiaryDetailsRequest_OnSuccess() + { + // Arrange + var request = new SubsidiaryDetailsRequest(); + var content = JsonConvert.SerializeObject(request); + var responseMessage = new HttpResponseMessage + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(content), + }; + var handlerMock = new Mock(MockBehavior.Strict); + handlerMock + .Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(content), + }) + .Verifiable(); + var httpClient = new HttpClient(handlerMock.Object) + { + BaseAddress = new Uri(_config.BaseUrl), + Timeout = TimeSpan.FromSeconds(_config.Timeout), + }; + var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); + + // Act + var result = await sut.GetSubsidiaryDetails(request); + + // Assert + result.Should().BeEquivalentTo(request); + handlerMock.Protected().Verify( + "SendAsync", + Times.Once(), + ItExpr.Is(req => + req.Method == HttpMethod.Post && + req.RequestUri.ToString().EndsWith("api/subsidiary-details")), + ItExpr.IsAny()); + } + + [DataRow(HttpStatusCode.Conflict)] + [DataRow(HttpStatusCode.BadRequest)] + [DataRow(HttpStatusCode.BadGateway)] + [DataRow(HttpStatusCode.Unauthorized)] + [TestMethod] + public async Task GetSubsidiaryDetails_WhenSendAsyncNotSuccessful_ThrowsError(HttpStatusCode statusCode) + { + // Arrange + var handlerMock = new Mock(MockBehavior.Strict); + handlerMock + .Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = statusCode, + }) + .Verifiable(); + + var httpClient = new HttpClient(handlerMock.Object) + { + BaseAddress = new Uri(_config.BaseUrl), + Timeout = TimeSpan.FromSeconds(_config.Timeout), + }; + var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); + + // Act + Func act = () => sut.GetSubsidiaryDetails(new SubsidiaryDetailsRequest()); + + // Assert + await act.Should().ThrowAsync(); + } + } +} diff --git a/src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj b/src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj new file mode 100644 index 0000000..36e4698 --- /dev/null +++ b/src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj @@ -0,0 +1,30 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + diff --git a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs new file mode 100644 index 0000000..00cf5fc --- /dev/null +++ b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs @@ -0,0 +1,291 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Subsidiary; + +namespace EPR.ProducerContentValidation.UnitTest.Services.Subsidiary +{ + [TestClass] + public class SubsidiaryDetailsRequestBuilderTests + { + private SubsidiaryDetailsRequestBuilder _subsidiaryDetailsRequestBuilder; + + [TestInitialize] + public void Setup() + { + _subsidiaryDetailsRequestBuilder = new SubsidiaryDetailsRequestBuilder(); + } + + [TestMethod] + public void CreateRequest_ShouldReturnEmptyRequest_WhenRowsIsEmpty() + { + // Arrange + var rows = new List(); + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.IsNotNull(result.SubsidiaryOrganisationDetails); + Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); + } + + [TestMethod] + public void CreateRequest_ShouldGroupByOrganisationReference_AndCreateSubsidiaryDetails() + { + // Arrange + var rows = new List + { + new ProducerRow( + SubsidiaryId: "Subsidiary Id 1", + DataSubmissionPeriod: "Submission Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Producer Type 1", + ProducerSize: "Producer Size 1", + WasteType: "Waste Type 1", + PackagingCategory: "Packaging Category 1", + MaterialType: "Material Type 1", + MaterialSubType: "Material SubType 1", + FromHomeNation: "From Nation 1", + ToHomeNation: "To Home Nation 1", + QuantityKg: "132", + QuantityUnits: "53243", + SubmissionPeriod: "Submission Period 1", + TransitionalPackagingUnits: "Transitional Packaging Units 1"), + new ProducerRow( + SubsidiaryId: "Subsidiary Id 2", + DataSubmissionPeriod: "Submission Period 2", + ProducerId: "2", + RowNumber: 2, + ProducerType: "Producer Type 2", + ProducerSize: "Producer Size 2", + WasteType: "Waste Type 2", + PackagingCategory: "Packaging Category 2", + MaterialType: "Material Type 2", + MaterialSubType: "Material SubType 2", + FromHomeNation: "From Nation 2", + ToHomeNation: "To Home Nation 2", + QuantityKg: "57567", + QuantityUnits: "95982", + SubmissionPeriod: "Submission Period 2", + TransitionalPackagingUnits: "Transitional Packaging Units 2"), + new ProducerRow( + SubsidiaryId: "Subsidiary Id 3", + DataSubmissionPeriod: "Submission Period 3", + ProducerId: "3", + RowNumber: 3, + ProducerType: "Producer Type 3", + ProducerSize: "Producer Size 3", + WasteType: "Waste Type 3", + PackagingCategory: "Packaging Category 3", + MaterialType: "Material Type 3", + MaterialSubType: "Material SubType 3", + FromHomeNation: "From Nation 3", + ToHomeNation: "To Home Nation 3", + QuantityKg: "57563467", + QuantityUnits: "9598345432", + SubmissionPeriod: "Submission Period 2", + TransitionalPackagingUnits: "Transitional Packaging Units 2"), + }; + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(3, result.SubsidiaryOrganisationDetails.Count); + + var org1 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "1"); + Assert.IsNotNull(org1); + Assert.AreEqual(1, org1.SubsidiaryDetails.Count); + Assert.IsTrue(org1.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); + Assert.IsTrue(org1.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); + + var org2 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "2"); + Assert.IsNotNull(org2); + Assert.AreEqual(1, org2.SubsidiaryDetails.Count); + Assert.IsTrue(org2.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 2")); + } + + [TestMethod] + public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() + { + // Arrange + var rows = new List + { + new ProducerRow( + SubsidiaryId: "Subsidiary Id 1", + DataSubmissionPeriod: "Submission Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Producer Type 1", + ProducerSize: "Producer Size 1", + WasteType: "Waste Type 1", + PackagingCategory: "Packaging Category 1", + MaterialType: "Material Type 1", + MaterialSubType: "Material SubType 1", + FromHomeNation: "From Nation 1", + ToHomeNation: "To Home Nation 1", + QuantityKg: "132", + QuantityUnits: "53243", + SubmissionPeriod: "Submission Period 1", + TransitionalPackagingUnits: "Transitional Packaging Units 1"), + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Submission Period 2", + ProducerId: "1", + RowNumber: 2, + ProducerType: "Producer Type 2", + ProducerSize: "Producer Size 2", + WasteType: "Waste Type 2", + PackagingCategory: "Packaging Category 2", + MaterialType: "Material Type 2", + MaterialSubType: "Material SubType 2", + FromHomeNation: "From Nation 2", + ToHomeNation: "To Home Nation 2", + QuantityKg: "57567", + QuantityUnits: "95982", + SubmissionPeriod: "Submission Period 2", + TransitionalPackagingUnits: "Transitional Packaging Units 2"), + new ProducerRow( + SubsidiaryId: "Subsidiary Id 2", + DataSubmissionPeriod: "Submission Period 3", + ProducerId: "2", + RowNumber: 3, + ProducerType: "Producer Type 3", + ProducerSize: "Producer Size 3", + WasteType: "Waste Type 3", + PackagingCategory: "Packaging Category 3", + MaterialType: "Material Type 3", + MaterialSubType: "Material SubType 3", + FromHomeNation: "From Nation 3", + ToHomeNation: "To Home Nation 3", + QuantityKg: "57563467", + QuantityUnits: "9598345432", + SubmissionPeriod: "Submission Period 2", + TransitionalPackagingUnits: "Transitional Packaging Units 2"), + }; + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(2, result.SubsidiaryOrganisationDetails.Count); + + var org1 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "1"); + Assert.IsNotNull(org1); + Assert.AreEqual(1, org1.SubsidiaryDetails.Count); + Assert.IsTrue(org1.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); + + var org2 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "2"); + Assert.IsNotNull(org2); + Assert.AreEqual(1, org2.SubsidiaryDetails.Count); + Assert.IsTrue(org2.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 2")); + } + + [TestMethod] + public void CreateRequest_WhenSingleSubIsEmptyRecord_ThenReturnCorrectRequest() + { + // Arrange + var rows = new List + { + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Submission Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Producer Type 1", + ProducerSize: "Producer Size 1", + WasteType: "Waste Type 1", + PackagingCategory: "Packaging Category 1", + MaterialType: "Material Type 1", + MaterialSubType: "Material SubType 1", + FromHomeNation: "From Nation 1", + ToHomeNation: "To Home Nation 1", + QuantityKg: "132", + QuantityUnits: "53243", + SubmissionPeriod: "Submission Period 1", + TransitionalPackagingUnits: "Transitional Packaging Units 1") + }; + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); + } + + [TestMethod] + public void CreateRequest_ShouldHandleMultipleOrganisations() + { + // Arrange + var rows = new List + { + new ProducerRow( + SubsidiaryId: "Subsidiary Id 1", + DataSubmissionPeriod: "Submission Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Producer Type 1", + ProducerSize: "Producer Size 1", + WasteType: "Waste Type 1", + PackagingCategory: "Packaging Category 1", + MaterialType: "Material Type 1", + MaterialSubType: "Material SubType 1", + FromHomeNation: "From Nation 1", + ToHomeNation: "To Home Nation 1", + QuantityKg: "132", + QuantityUnits: "53243", + SubmissionPeriod: "Submission Period 1", + TransitionalPackagingUnits: "Transitional Packaging Units 1"), + new ProducerRow( + SubsidiaryId: "Subsidiary Id 2", + DataSubmissionPeriod: "Submission Period 2", + ProducerId: "2", + RowNumber: 2, + ProducerType: "Producer Type 2", + ProducerSize: "Producer Size 2", + WasteType: "Waste Type 2", + PackagingCategory: "Packaging Category 2", + MaterialType: "Material Type 2", + MaterialSubType: "Material SubType 2", + FromHomeNation: "From Nation 2", + ToHomeNation: "To Home Nation 2", + QuantityKg: "57567", + QuantityUnits: "95982", + SubmissionPeriod: "Submission Period 2", + TransitionalPackagingUnits: "Transitional Packaging Units 2"), + new ProducerRow( + SubsidiaryId: "SubsidiaryId", + DataSubmissionPeriod: "Submission Period 3", + ProducerId: "3", + RowNumber: 3, + ProducerType: "Producer Type 3", + ProducerSize: "Producer Size 3", + WasteType: "Waste Type 3", + PackagingCategory: "Packaging Category 3", + MaterialType: "Material Type 3", + MaterialSubType: "Material SubType 3", + FromHomeNation: "From Nation 3", + ToHomeNation: "To Home Nation 3", + QuantityKg: "57563467", + QuantityUnits: "9598345432", + SubmissionPeriod: "Submission Period 2", + TransitionalPackagingUnits: "Transitional Packaging Units 2"), + }; + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(3, result.SubsidiaryOrganisationDetails.Count); + + Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(org => org.OrganisationReference == "1")); + Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(org => org.OrganisationReference == "2")); + Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(org => org.OrganisationReference == "3")); + } + } +} diff --git a/src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj b/src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj deleted file mode 100644 index 6783e83..0000000 --- a/src/EPR.ProducerContentValidation.UnitTests/EPR.ProducerContentValidation.UnitTests.csproj +++ /dev/null @@ -1,50 +0,0 @@ - - - - - Debug - AnyCPU - {E7C40F24-549B-494A-AEF1-325C5658C9A0} - Library - Properties - EPR.ProducerContentValidation.UnitTests - EPR.ProducerContentValidation.UnitTests - v4.7.2 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 15.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs b/src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs deleted file mode 100644 index 917489b..0000000 --- a/src/EPR.ProducerContentValidation.UnitTests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("EPR.ProducerContentValidation.UnitTests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("EPR.ProducerContentValidation.UnitTests")] -[assembly: AssemblyCopyright("Copyright © 2024")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -[assembly: ComVisible(false)] - -[assembly: Guid("e7c40f24-549b-494a-aef1-325c5658c9a0")] - -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs b/src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs deleted file mode 100644 index 0f13eca..0000000 --- a/src/EPR.ProducerContentValidation.UnitTests/UnitTest1.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; - -namespace EPR.ProducerContentValidation.UnitTests -{ - [TestClass] - public class UnitTest1 - { - [TestMethod] - public void TestMethod1() - { - } - } -} diff --git a/src/EPR.ProducerContentValidation.sln b/src/EPR.ProducerContentValidation.sln index d092b76..ad67399 100644 --- a/src/EPR.ProducerContentValidation.sln +++ b/src/EPR.ProducerContentValidation.sln @@ -24,6 +24,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.Data", "EPR.ProducerContentValidation.Data\EPR.ProducerContentValidation.Data.csproj", "{0944BDFE-6DD0-48E0-8A08-A36203138D43}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.UnitTest", "EPR.ProducerContentValidation.UnitTest\EPR.ProducerContentValidation.UnitTest.csproj", "{C22C5FE6-1839-4026-B7F3-ECD78154445E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -54,6 +56,10 @@ Global {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Debug|Any CPU.Build.0 = Debug|Any CPU {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Release|Any CPU.ActiveCfg = Release|Any CPU {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Release|Any CPU.Build.0 = Release|Any CPU + {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From d7cef534dea7dda8234d949159a3a8bec82de025 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Mon, 28 Oct 2024 12:16:33 +0000 Subject: [PATCH 05/44] Attending to SonarQube feedbACK --- .../SubsidiaryDetailsRequestBuilderTests.cs | 302 +++++++----------- 1 file changed, 113 insertions(+), 189 deletions(-) diff --git a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs index 00cf5fc..663796f 100644 --- a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs +++ b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs @@ -17,75 +17,52 @@ public void Setup() [TestMethod] public void CreateRequest_ShouldReturnEmptyRequest_WhenRowsIsEmpty() { - // Arrange var rows = new List(); - - // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); - // Assert Assert.IsNotNull(result); Assert.IsNotNull(result.SubsidiaryOrganisationDetails); Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); } [TestMethod] - public void CreateRequest_ShouldGroupByOrganisationReference_AndCreateSubsidiaryDetails() + public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() { // Arrange var rows = new List { new ProducerRow( SubsidiaryId: "Subsidiary Id 1", - DataSubmissionPeriod: "Submission Period 1", + DataSubmissionPeriod: "Period 1", ProducerId: "1", RowNumber: 1, - ProducerType: "Producer Type 1", - ProducerSize: "Producer Size 1", - WasteType: "Waste Type 1", - PackagingCategory: "Packaging Category 1", - MaterialType: "Material Type 1", - MaterialSubType: "Material SubType 1", - FromHomeNation: "From Nation 1", - ToHomeNation: "To Home Nation 1", - QuantityKg: "132", - QuantityUnits: "53243", - SubmissionPeriod: "Submission Period 1", - TransitionalPackagingUnits: "Transitional Packaging Units 1"), + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), new ProducerRow( - SubsidiaryId: "Subsidiary Id 2", - DataSubmissionPeriod: "Submission Period 2", - ProducerId: "2", + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Period 2", + ProducerId: "1", RowNumber: 2, - ProducerType: "Producer Type 2", - ProducerSize: "Producer Size 2", - WasteType: "Waste Type 2", - PackagingCategory: "Packaging Category 2", - MaterialType: "Material Type 2", - MaterialSubType: "Material SubType 2", - FromHomeNation: "From Nation 2", - ToHomeNation: "To Home Nation 2", - QuantityKg: "57567", - QuantityUnits: "95982", - SubmissionPeriod: "Submission Period 2", - TransitionalPackagingUnits: "Transitional Packaging Units 2"), - new ProducerRow( - SubsidiaryId: "Subsidiary Id 3", - DataSubmissionPeriod: "Submission Period 3", - ProducerId: "3", - RowNumber: 3, - ProducerType: "Producer Type 3", - ProducerSize: "Producer Size 3", - WasteType: "Waste Type 3", - PackagingCategory: "Packaging Category 3", - MaterialType: "Material Type 3", - MaterialSubType: "Material SubType 3", - FromHomeNation: "From Nation 3", - ToHomeNation: "To Home Nation 3", - QuantityKg: "57563467", - QuantityUnits: "9598345432", - SubmissionPeriod: "Submission Period 2", - TransitionalPackagingUnits: "Transitional Packaging Units 2"), + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") }; // Act @@ -93,77 +70,35 @@ public void CreateRequest_ShouldGroupByOrganisationReference_AndCreateSubsidiary // Assert Assert.IsNotNull(result); - Assert.AreEqual(3, result.SubsidiaryOrganisationDetails.Count); - - var org1 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "1"); - Assert.IsNotNull(org1); - Assert.AreEqual(1, org1.SubsidiaryDetails.Count); - Assert.IsTrue(org1.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); - Assert.IsTrue(org1.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); - - var org2 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "2"); - Assert.IsNotNull(org2); - Assert.AreEqual(1, org2.SubsidiaryDetails.Count); - Assert.IsTrue(org2.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 2")); + Assert.AreEqual(1, result.SubsidiaryOrganisationDetails.Count); + var org = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "1"); + Assert.IsNotNull(org); + Assert.AreEqual(1, org.SubsidiaryDetails.Count); + Assert.IsTrue(org.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); } [TestMethod] - public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() + public void CreateRequest_ShouldHandleNoValidSubsidiaryIds() { // Arrange var rows = new List { - new ProducerRow( - SubsidiaryId: "Subsidiary Id 1", - DataSubmissionPeriod: "Submission Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Producer Type 1", - ProducerSize: "Producer Size 1", - WasteType: "Waste Type 1", - PackagingCategory: "Packaging Category 1", - MaterialType: "Material Type 1", - MaterialSubType: "Material SubType 1", - FromHomeNation: "From Nation 1", - ToHomeNation: "To Home Nation 1", - QuantityKg: "132", - QuantityUnits: "53243", - SubmissionPeriod: "Submission Period 1", - TransitionalPackagingUnits: "Transitional Packaging Units 1"), new ProducerRow( SubsidiaryId: string.Empty, - DataSubmissionPeriod: "Submission Period 2", + DataSubmissionPeriod: "Period 1", ProducerId: "1", - RowNumber: 2, - ProducerType: "Producer Type 2", - ProducerSize: "Producer Size 2", - WasteType: "Waste Type 2", - PackagingCategory: "Packaging Category 2", - MaterialType: "Material Type 2", - MaterialSubType: "Material SubType 2", - FromHomeNation: "From Nation 2", - ToHomeNation: "To Home Nation 2", - QuantityKg: "57567", - QuantityUnits: "95982", - SubmissionPeriod: "Submission Period 2", - TransitionalPackagingUnits: "Transitional Packaging Units 2"), - new ProducerRow( - SubsidiaryId: "Subsidiary Id 2", - DataSubmissionPeriod: "Submission Period 3", - ProducerId: "2", - RowNumber: 3, - ProducerType: "Producer Type 3", - ProducerSize: "Producer Size 3", - WasteType: "Waste Type 3", - PackagingCategory: "Packaging Category 3", - MaterialType: "Material Type 3", - MaterialSubType: "Material SubType 3", - FromHomeNation: "From Nation 3", - ToHomeNation: "To Home Nation 3", - QuantityKg: "57563467", - QuantityUnits: "9598345432", - SubmissionPeriod: "Submission Period 2", - TransitionalPackagingUnits: "Transitional Packaging Units 2"), + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1") }; // Act @@ -171,42 +106,47 @@ public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() // Assert Assert.IsNotNull(result); - Assert.AreEqual(2, result.SubsidiaryOrganisationDetails.Count); - - var org1 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "1"); - Assert.IsNotNull(org1); - Assert.AreEqual(1, org1.SubsidiaryDetails.Count); - Assert.IsTrue(org1.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); - - var org2 = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "2"); - Assert.IsNotNull(org2); - Assert.AreEqual(1, org2.SubsidiaryDetails.Count); - Assert.IsTrue(org2.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 2")); + Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); } [TestMethod] - public void CreateRequest_WhenSingleSubIsEmptyRecord_ThenReturnCorrectRequest() + public void CreateRequest_ShouldGroupByProducerId_WithMultipleValidSubsidiaryIds() { // Arrange var rows = new List { new ProducerRow( - SubsidiaryId: string.Empty, - DataSubmissionPeriod: "Submission Period 1", + SubsidiaryId: "SubId1", + DataSubmissionPeriod: "Period 1", ProducerId: "1", RowNumber: 1, - ProducerType: "Producer Type 1", - ProducerSize: "Producer Size 1", - WasteType: "Waste Type 1", - PackagingCategory: "Packaging Category 1", - MaterialType: "Material Type 1", - MaterialSubType: "Material SubType 1", - FromHomeNation: "From Nation 1", - ToHomeNation: "To Home Nation 1", - QuantityKg: "132", - QuantityUnits: "53243", - SubmissionPeriod: "Submission Period 1", - TransitionalPackagingUnits: "Transitional Packaging Units 1") + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: "SubId2", + DataSubmissionPeriod: "Period 2", + ProducerId: "1", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") }; // Act @@ -214,66 +154,52 @@ public void CreateRequest_WhenSingleSubIsEmptyRecord_ThenReturnCorrectRequest() // Assert Assert.IsNotNull(result); - Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); + Assert.AreEqual(1, result.SubsidiaryOrganisationDetails.Count); + var org = result.SubsidiaryOrganisationDetails.First(); + Assert.AreEqual("1", org.OrganisationReference); + Assert.AreEqual(2, org.SubsidiaryDetails.Count); + Assert.IsTrue(org.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "SubId1")); + Assert.IsTrue(org.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "SubId2")); } [TestMethod] - public void CreateRequest_ShouldHandleMultipleOrganisations() + public void CreateRequest_ShouldReturnMultipleOrganisationsWithValidSubsidiaryIds() { // Arrange var rows = new List { new ProducerRow( - SubsidiaryId: "Subsidiary Id 1", - DataSubmissionPeriod: "Submission Period 1", + SubsidiaryId: "SubId1", + DataSubmissionPeriod: "Period 1", ProducerId: "1", RowNumber: 1, - ProducerType: "Producer Type 1", - ProducerSize: "Producer Size 1", - WasteType: "Waste Type 1", - PackagingCategory: "Packaging Category 1", - MaterialType: "Material Type 1", - MaterialSubType: "Material SubType 1", - FromHomeNation: "From Nation 1", - ToHomeNation: "To Home Nation 1", - QuantityKg: "132", - QuantityUnits: "53243", - SubmissionPeriod: "Submission Period 1", - TransitionalPackagingUnits: "Transitional Packaging Units 1"), + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), new ProducerRow( - SubsidiaryId: "Subsidiary Id 2", - DataSubmissionPeriod: "Submission Period 2", + SubsidiaryId: "SubId2", + DataSubmissionPeriod: "Period 2", ProducerId: "2", RowNumber: 2, - ProducerType: "Producer Type 2", - ProducerSize: "Producer Size 2", - WasteType: "Waste Type 2", - PackagingCategory: "Packaging Category 2", - MaterialType: "Material Type 2", - MaterialSubType: "Material SubType 2", - FromHomeNation: "From Nation 2", - ToHomeNation: "To Home Nation 2", - QuantityKg: "57567", - QuantityUnits: "95982", - SubmissionPeriod: "Submission Period 2", - TransitionalPackagingUnits: "Transitional Packaging Units 2"), - new ProducerRow( - SubsidiaryId: "SubsidiaryId", - DataSubmissionPeriod: "Submission Period 3", - ProducerId: "3", - RowNumber: 3, - ProducerType: "Producer Type 3", - ProducerSize: "Producer Size 3", - WasteType: "Waste Type 3", - PackagingCategory: "Packaging Category 3", - MaterialType: "Material Type 3", - MaterialSubType: "Material SubType 3", - FromHomeNation: "From Nation 3", - ToHomeNation: "To Home Nation 3", - QuantityKg: "57563467", - QuantityUnits: "9598345432", - SubmissionPeriod: "Submission Period 2", - TransitionalPackagingUnits: "Transitional Packaging Units 2"), + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") }; // Act @@ -281,11 +207,9 @@ public void CreateRequest_ShouldHandleMultipleOrganisations() // Assert Assert.IsNotNull(result); - Assert.AreEqual(3, result.SubsidiaryOrganisationDetails.Count); - - Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(org => org.OrganisationReference == "1")); - Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(org => org.OrganisationReference == "2")); - Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(org => org.OrganisationReference == "3")); + Assert.AreEqual(2, result.SubsidiaryOrganisationDetails.Count); + Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(o => o.OrganisationReference == "1")); + Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(o => o.OrganisationReference == "2")); } } } From be6fe8e070b0724a6dce6a88d3f87b59fb2290bb Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Tue, 29 Oct 2024 00:35:05 +0000 Subject: [PATCH 06/44] refactoring and more tests --- .../Performance/ValidatorsPerformanceTests.cs | 7 +- .../Helpers/FindMatchingProducerTests.cs | 126 ++++++++++ .../Helpers/OrganisationMatcherTests.cs | 128 ++++++++++ .../ProducerValidationEventFormatterTests.cs | 138 +++++++++++ .../Services/Helpers/RequestValidatorTests.cs | 79 +++++++ .../Helpers/SubsidiaryMatcherTests.cs | 177 ++++++++++++++ .../SubsidiaryValidationEvaluatorTests.cs | 172 ++++++++++++++ ...idationServiceProducerRowValidatorTests.cs | 218 ++++++++++++++++++ .../Services/ValidationServiceTests.cs | 199 ++++++++++------ .../ConfigureServices.cs | 10 +- .../Services/Helpers/FindMatchingProducer.cs | 38 +++ .../Services/Helpers/IFindMatchingProducer.cs | 11 + .../Services/Helpers/IOrganisationMatcher.cs | 10 + ...cerValidationEventIssueRequestFormatter.cs | 10 + .../Services/Helpers/IRequestValidator.cs | 9 + .../Services/Helpers/ISubsidiaryMatcher.cs | 10 + .../Helpers/ISubsidiaryValidationEvaluator.cs | 11 + .../IValidationServiceProducerRowValidator.cs | 12 + .../Services/Helpers/OrganisationMatcher.cs | 14 ++ ...cerValidationEventIssueRequestFormatter.cs | 30 +++ .../Services/Helpers/RequestValidator.cs | 10 + .../Services/Helpers/SubsidiaryMatcher.cs | 14 ++ .../Helpers/SubsidiaryValidationEvaluator.cs | 42 ++++ .../ValidationServiceProducerRowValidator.cs | 33 +++ .../Services/ValidationService.cs | 87 +++---- 25 files changed, 1469 insertions(+), 126 deletions(-) create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/IFindMatchingProducer.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/IOrganisationMatcher.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/IProducerValidationEventIssueRequestFormatter.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/IRequestValidator.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryMatcher.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryValidationEvaluator.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/IValidationServiceProducerRowValidator.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs index 465d3fb..b44832e 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs @@ -7,6 +7,7 @@ using EPR.ProducerContentValidation.Application.Profiles; using EPR.ProducerContentValidation.Application.ReferenceData; using EPR.ProducerContentValidation.Application.Services; +using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators; @@ -34,6 +35,8 @@ public ValidatorsPerformanceTests() Mock featureManagerMock = new(); Mock subsidiaryDetailsRequestBuilderMock = new(); Mock companyDetailsApiClientMock = new(); + Mock requestValidatorMock = new(); + Mock validationServiceProducerRowValidatorMock = new(); var submissionConfigOptions = new Mock>>(); @@ -63,7 +66,9 @@ public ValidatorsPerformanceTests() Microsoft.Extensions.Options.Options.Create(new StorageAccountOptions { PomContainer = "ContainerName" }), featureManagerMock.Object, subsidiaryDetailsRequestBuilderMock.Object, - companyDetailsApiClientMock.Object); + companyDetailsApiClientMock.Object, + requestValidatorMock.Object, + validationServiceProducerRowValidatorMock.Object); } [TestMethod] diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs new file mode 100644 index 0000000..51ef897 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs @@ -0,0 +1,126 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.TestSupport; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class FindMatchingProducerTests + { + private readonly Mock _organisationMatcherMock; + private readonly Mock _subsidiaryMatcherMock; + private readonly Mock _subsidiaryValidationEvaluatorMock; + private readonly FindMatchingProducer _findMatchingProducer; + + public FindMatchingProducerTests() + { + _organisationMatcherMock = new Mock(); + _subsidiaryMatcherMock = new Mock(); + _subsidiaryValidationEvaluatorMock = new Mock(); + + _findMatchingProducer = new FindMatchingProducer( + _organisationMatcherMock.Object, + _subsidiaryMatcherMock.Object, + _subsidiaryValidationEvaluatorMock.Object); + } + + [TestMethod] + public void Match_NoMatchingOrganisation_ReturnsNull() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1); + var response = new SubsidiaryDetailsResponse(); + + _organisationMatcherMock + .Setup(m => m.FindMatchingOrganisation(row, response)) + .Returns((SubsidiaryOrganisationDetail?)null); + + // Act + var result = _findMatchingProducer.Match(row, response, 1); + + // Assert + Assert.IsNull(result); + _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); + _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(It.IsAny(), It.IsAny()), Times.Never); + _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + } + + [TestMethod] + public void Match_NoMatchingSubsidiary_ReturnsNull() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1); + var response = new SubsidiaryDetailsResponse(); + var matchingOrg = new SubsidiaryOrganisationDetail(); + + _organisationMatcherMock + .Setup(m => m.FindMatchingOrganisation(row, response)) + .Returns(matchingOrg); + + _subsidiaryMatcherMock + .Setup(m => m.FindMatchingSubsidiary(row, matchingOrg)) + .Returns((SubsidiaryDetail?)null); + + // Act + var result = _findMatchingProducer.Match(row, response, 1); + + // Assert + Assert.IsNull(result); + _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); + _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(row, matchingOrg), Times.Once); + _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + } + + [TestMethod] + public void Match_MatchingOrganisationAndSubsidiary_ReturnsValidationResult() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1); + var response = new SubsidiaryDetailsResponse(); + var matchingOrg = new SubsidiaryOrganisationDetail(); + var matchingSub = new SubsidiaryDetail(); + var expectedValidationResult = new ProducerValidationEventIssueRequest( + SubsidiaryId: "S123", + DataSubmissionPeriod: "2024-Q1", + RowNumber: 1, + ProducerId: "P456", + ProducerType: "Large", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "Containers", + MaterialType: "Polyethylene", + MaterialSubType: "High-Density", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + BlobName: "ExampleBlobName", + ErrorCodes: new List { "E001", "E002" }); + + _organisationMatcherMock + .Setup(m => m.FindMatchingOrganisation(row, response)) + .Returns(matchingOrg); + + _subsidiaryMatcherMock + .Setup(m => m.FindMatchingSubsidiary(row, matchingOrg)) + .Returns(matchingSub); + + _subsidiaryValidationEvaluatorMock + .Setup(m => m.EvaluateSubsidiaryValidation(row, matchingSub, 1)) + .Returns(expectedValidationResult); + + // Act + var result = _findMatchingProducer.Match(row, response, 1); + + // Assert + Assert.AreEqual(expectedValidationResult, result); + _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); + _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(row, matchingOrg), Times.Once); + _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(row, matchingSub, 1), Times.Once); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs new file mode 100644 index 0000000..b69492d --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs @@ -0,0 +1,128 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class OrganisationMatcherTests + { + private readonly OrganisationMatcher _organisationMatcher; + + public OrganisationMatcherTests() + { + _organisationMatcher = new OrganisationMatcher(); + } + + [TestMethod] + public void FindMatchingOrganisation_ShouldReturnOrganisation_WhenMatchExists() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: "Sub123", + DataSubmissionPeriod: "2023-Q1", + ProducerId: "Org456", + RowNumber: 1, + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubMaterialX", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + SubmissionPeriod: "2023"); + + var matchingOrg = new SubsidiaryOrganisationDetail + { + OrganisationReference = "Org456" + }; + + var response = new SubsidiaryDetailsResponse + { + SubsidiaryOrganisationDetails = new List { matchingOrg } + }; + + // Act + var result = _organisationMatcher.FindMatchingOrganisation(row, response); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual("Org456", result.OrganisationReference); + } + + [TestMethod] + public void FindMatchingOrganisation_ShouldReturnNull_WhenNoMatchExists() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: "Sub123", + DataSubmissionPeriod: "2023-Q1", + ProducerId: "Org789", // This ID does not match any in the response + RowNumber: 1, + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubMaterialX", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + SubmissionPeriod: "2023"); + + var nonMatchingOrg = new SubsidiaryOrganisationDetail + { + OrganisationReference = "Org456" // Different ID than the row's ProducerId + }; + + var response = new SubsidiaryDetailsResponse + { + SubsidiaryOrganisationDetails = new List { nonMatchingOrg } + }; + + // Act + var result = _organisationMatcher.FindMatchingOrganisation(row, response); + + // Assert + Assert.IsNull(result); + } + + [TestMethod] + public void FindMatchingOrganisation_ShouldReturnNull_WhenResponseIsEmpty() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: "Sub123", + DataSubmissionPeriod: "2023-Q1", + ProducerId: "Org456", + RowNumber: 1, + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubMaterialX", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + SubmissionPeriod: "2023"); + + var response = new SubsidiaryDetailsResponse + { + SubsidiaryOrganisationDetails = new List() // Empty list + }; + + // Act + var result = _organisationMatcher.FindMatchingOrganisation(row, response); + + // Assert + Assert.IsNull(result); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs new file mode 100644 index 0000000..45ddfa1 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs @@ -0,0 +1,138 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class ProducerValidationEventFormatterTests + { + private readonly IProducerValidationEventIssueRequestFormatter _formatter; + + public ProducerValidationEventFormatterTests() + { + _formatter = new ProducerValidationEventIssueRequestFormatter(); + } + + [TestMethod] + public void Format_ShouldReturnFormattedRequest_WithAllFieldsProvided() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: "Sub123", + DataSubmissionPeriod: "2023-Q1", + ProducerId: "Org456", + RowNumber: 1, + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubMaterialX", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + SubmissionPeriod: "2023"); + + string errorCode = "ErrorCode123"; + + // Act + var result = _formatter.Format(row, errorCode); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual("Sub123", result.SubsidiaryId); + Assert.AreEqual("2023-Q1", result.DataSubmissionPeriod); + Assert.AreEqual(1, result.RowNumber); + Assert.AreEqual("Org456", result.ProducerId); + Assert.AreEqual("TypeA", result.ProducerType); + Assert.AreEqual("Large", result.ProducerSize); + Assert.AreEqual("Plastic", result.WasteType); + Assert.AreEqual("CategoryA", result.PackagingCategory); + Assert.AreEqual("MaterialX", result.MaterialType); + Assert.AreEqual("SubMaterialX", result.MaterialSubType); + Assert.AreEqual("UK", result.FromHomeNation); + Assert.AreEqual("Germany", result.ToHomeNation); + Assert.AreEqual("100", result.QuantityKg); + Assert.AreEqual("200", result.QuantityUnits); + CollectionAssert.Contains(result.ErrorCodes, errorCode); + } + + [TestMethod] + public void Format_ShouldHandleNullFields_InProducerRow() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: null, + DataSubmissionPeriod: null, + ProducerId: null, + RowNumber: 1, + ProducerType: null, + ProducerSize: null, + WasteType: null, + PackagingCategory: null, + MaterialType: null, + MaterialSubType: null, + FromHomeNation: null, + ToHomeNation: null, + QuantityKg: null, + QuantityUnits: null, + SubmissionPeriod: "2023"); + + string errorCode = "ErrorCode123"; + + // Act + var result = _formatter.Format(row, errorCode); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(string.Empty, result.SubsidiaryId); + Assert.AreEqual(string.Empty, result.DataSubmissionPeriod); + Assert.AreEqual(1, result.RowNumber); + Assert.AreEqual(string.Empty, result.ProducerId); + Assert.AreEqual(string.Empty, result.ProducerType); + Assert.AreEqual(string.Empty, result.ProducerSize); + Assert.AreEqual(string.Empty, result.WasteType); + Assert.AreEqual(string.Empty, result.PackagingCategory); + Assert.AreEqual(string.Empty, result.MaterialType); + Assert.AreEqual(string.Empty, result.MaterialSubType); + Assert.AreEqual(string.Empty, result.FromHomeNation); + Assert.AreEqual(string.Empty, result.ToHomeNation); + Assert.AreEqual(string.Empty, result.QuantityKg); + Assert.AreEqual(string.Empty, result.QuantityUnits); + CollectionAssert.Contains(result.ErrorCodes, errorCode); + } + + [TestMethod] + public void Format_ShouldReturnSingleErrorCode() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: "Sub123", + DataSubmissionPeriod: "2023-Q1", + ProducerId: "Org456", + RowNumber: 1, + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubMaterialX", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + SubmissionPeriod: "2023"); + + string errorCode = "SingleError"; + + // Act + var result = _formatter.Format(row, errorCode); + + // Assert + Assert.AreEqual(1, result.ErrorCodes.Count, "Expected exactly one error code in the list."); + Assert.AreEqual("SingleError", result.ErrorCodes[0]); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs new file mode 100644 index 0000000..41e9a88 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs @@ -0,0 +1,79 @@ +using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class RequestValidatorTests + { + private RequestValidator _validator; + + [TestInitialize] + public void Setup() + { + _validator = new RequestValidator(); + } + + [TestMethod] + public void IsInvalidRequest_ShouldReturnTrue_WhenRequestIsNull() + { + // Act + var result = _validator.IsInvalidRequest(null); + + // Assert + Assert.IsTrue(result, "Expected IsInvalidRequest to return true for null request."); + } + + [TestMethod] + public void IsInvalidRequest_ShouldReturnTrue_WhenSubsidiaryOrganisationDetailsIsNull() + { + // Arrange + var request = new SubsidiaryDetailsRequest + { + SubsidiaryOrganisationDetails = null + }; + + // Act + var result = _validator.IsInvalidRequest(request); + + // Assert + Assert.IsTrue(result, "Expected IsInvalidRequest to return true when SubsidiaryOrganisationDetails is null."); + } + + [TestMethod] + public void IsInvalidRequest_ShouldReturnTrue_WhenSubsidiaryOrganisationDetailsIsEmpty() + { + // Arrange + var request = new SubsidiaryDetailsRequest + { + SubsidiaryOrganisationDetails = new List() + }; + + // Act + var result = _validator.IsInvalidRequest(request); + + // Assert + Assert.IsTrue(result, "Expected IsInvalidRequest to return true when SubsidiaryOrganisationDetails is empty."); + } + + [TestMethod] + public void IsInvalidRequest_ShouldReturnFalse_WhenSubsidiaryOrganisationDetailsIsNotEmpty() + { + // Arrange + var request = new SubsidiaryDetailsRequest + { + SubsidiaryOrganisationDetails = new List + { + new SubsidiaryOrganisationDetail { OrganisationReference = "Org1" } + } + }; + + // Act + var result = _validator.IsInvalidRequest(request); + + // Assert + Assert.IsFalse(result, "Expected IsInvalidRequest to return false when SubsidiaryOrganisationDetails is not empty."); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs new file mode 100644 index 0000000..49685c9 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs @@ -0,0 +1,177 @@ +using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.TestSupport; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class SubsidiaryMatcherTests + { + private SubsidiaryMatcher _matcher; + + [TestInitialize] + public void SetUp() + { + _matcher = new SubsidiaryMatcher(); + } + + [TestMethod] + public void FindMatchingSubsidiary_ShouldReturnMatchingSubsidiary_WhenReferenceNumberMatches() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "123", + DataSubmissionPeriod = "2024Q1", + ProducerId = "456", + RowNumber = 1, + ProducerType = "Large", + ProducerSize = "1000", + WasteType = "Plastic", + PackagingCategory = "CategoryA", + MaterialType = "TypeA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "500", + QuantityUnits = "10" + }; + + var subsidiaryDetails = new List + { + new SubsidiaryDetail { ReferenceNumber = "123", SubsidiaryExists = true }, + new SubsidiaryDetail { ReferenceNumber = "456", SubsidiaryExists = true } + }; + + var org = new SubsidiaryOrganisationDetail + { + OrganisationReference = "456", + SubsidiaryDetails = subsidiaryDetails + }; + + // Act + var result = _matcher.FindMatchingSubsidiary(row, org); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual("123", result?.ReferenceNumber); + } + + [TestMethod] + public void FindMatchingSubsidiary_ShouldReturnNull_WhenNoMatchingReferenceNumber() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "789", + DataSubmissionPeriod = "2024Q1", + ProducerId = "456", + RowNumber = 1, + ProducerType = "Large", + ProducerSize = "1000", + WasteType = "Plastic", + PackagingCategory = "CategoryA", + MaterialType = "TypeA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "500", + QuantityUnits = "10" + }; + + var subsidiaryDetails = new List + { + new SubsidiaryDetail { ReferenceNumber = "123", SubsidiaryExists = true }, + new SubsidiaryDetail { ReferenceNumber = "456", SubsidiaryExists = true } + }; + + var org = new SubsidiaryOrganisationDetail + { + OrganisationReference = "456", + SubsidiaryDetails = subsidiaryDetails + }; + + // Act + var result = _matcher.FindMatchingSubsidiary(row, org); + + // Assert + Assert.IsNull(result); + } + + [TestMethod] + public void FindMatchingSubsidiary_ShouldReturnNull_WhenSubsidiaryDetailsIsEmpty() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "123", + DataSubmissionPeriod = "2024Q1", + ProducerId = "456", + RowNumber = 1, + ProducerType = "Large", + ProducerSize = "1000", + WasteType = "Plastic", + PackagingCategory = "CategoryA", + MaterialType = "TypeA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "500", + QuantityUnits = "10" + }; + + var org = new SubsidiaryOrganisationDetail + { + OrganisationReference = "456", + SubsidiaryDetails = new List() + }; + + // Act + var result = _matcher.FindMatchingSubsidiary(row, org); + + // Assert + Assert.IsNull(result); + } + + [TestMethod] + public void FindMatchingSubsidiary_ShouldReturnNull_WhenSubsidiaryIdIsNull() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with { + SubsidiaryId = null, + DataSubmissionPeriod = "2024Q1", + ProducerId = "456", + RowNumber = 1, + ProducerType = "Large", + ProducerSize = "1000", + WasteType = "Plastic", + PackagingCategory = "CategoryA", + MaterialType = "TypeA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "500", + QuantityUnits = "10" + }; + + var subsidiaryDetails = new List + { + new SubsidiaryDetail { ReferenceNumber = "123", SubsidiaryExists = true }, + new SubsidiaryDetail { ReferenceNumber = "456", SubsidiaryExists = true } + }; + + var org = new SubsidiaryOrganisationDetail + { + OrganisationReference = "456", + SubsidiaryDetails = subsidiaryDetails + }; + + // Act + var result = _matcher.FindMatchingSubsidiary(row, org); + + // Assert + Assert.IsNull(result); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs new file mode 100644 index 0000000..ca7abc2 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs @@ -0,0 +1,172 @@ +using EPR.ProducerContentValidation.Application.Constants; +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.TestSupport; +using Microsoft.Extensions.Logging; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class SubsidiaryValidationEvaluatorTests + { + private Mock _mockLogger; + private Mock _mockFormatter; + private SubsidiaryValidationEvaluator _evaluator; + + [TestInitialize] + public void Setup() + { + _mockLogger = new Mock(); + _mockFormatter = new Mock(); + _evaluator = new SubsidiaryValidationEvaluator(_mockLogger.Object, _mockFormatter.Object); + } + + [TestMethod] + public void EvaluateSubsidiaryValidation_SubsidiaryDoesNotExist_ShouldLogWarningAndReturnFormattedRequest() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "123", + DataSubmissionPeriod = "2024-01", + ProducerId = "Producer1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteType", + PackagingCategory = "CategoryA", + MaterialType = "MaterialX", + MaterialSubType = "SubTypeX", + FromHomeNation = "Nation1", + ToHomeNation = "Nation2", + QuantityKg = "100", + QuantityUnits = "Units" + }; + var subsidiary = new SubsidiaryDetail { SubsidiaryExists = false, SubsidiaryBelongsToOrganisation = true }; + var expectedRequest = new ProducerValidationEventIssueRequest( + row.SubsidiaryId, + row.DataSubmissionPeriod, + row.RowNumber, + row.ProducerId, + row.ProducerType, + row.ProducerSize, + row.WasteType, + row.PackagingCategory, + row.MaterialType, + row.MaterialSubType, + row.FromHomeNation, + row.ToHomeNation, + row.QuantityKg, + row.QuantityUnits, + ErrorCodes: new List { ErrorCode.SubsidiaryIdDoesNotExist }); + + _mockFormatter.Setup(f => f.Format(row, ErrorCode.SubsidiaryIdDoesNotExist)).Returns(expectedRequest); + + // Act + var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(expectedRequest, result); + + // _mockLogger.Verify( + // l => l.LogWarning( + // It.Is(s => s == "Validation Warning at row {RowNumber}: {Message} (ErrorCode: {ErrorCode})"), + // It.Is(o => + // (int)o[0] == row.RowNumber + 1 && + // (string)o[1] == "Subsidiary ID does not exist" && + // (string)o[2] == ErrorCode.SubsidiaryIdDoesNotExist)), + // Times.Once); + _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdDoesNotExist), Times.Once); + } + + [TestMethod] + public void EvaluateSubsidiaryValidation_SubsidiaryBelongsToDifferentOrganisation_ShouldLogWarningAndReturnFormattedRequest() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "123", + DataSubmissionPeriod = "2024-01", + ProducerId = "Producer1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteType", + PackagingCategory = "CategoryA", + MaterialType = "MaterialX", + MaterialSubType = "SubTypeX", + FromHomeNation = "Nation1", + ToHomeNation = "Nation2", + QuantityKg = "100", + QuantityUnits = "Units" + }; + var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToOrganisation = false }; + var expectedRequest = new ProducerValidationEventIssueRequest( + row.SubsidiaryId, + row.DataSubmissionPeriod, + row.RowNumber, + row.ProducerId, + row.ProducerType, + row.ProducerSize, + row.WasteType, + row.PackagingCategory, + row.MaterialType, + row.MaterialSubType, + row.FromHomeNation, + row.ToHomeNation, + row.QuantityKg, + row.QuantityUnits, + ErrorCodes: new List { ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation }); + + _mockFormatter.Setup(f => f.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation)).Returns(expectedRequest); + + // Act + var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(expectedRequest, result); + + // _mockLogger.Verify(l => l.LogWarning(It.IsAny(), row.RowNumber + 1, "Subsidiary ID is assigned to a different organisation", ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation), Times.Once); + _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation), Times.Once); + } + + [TestMethod] + public void EvaluateSubsidiaryValidation_SubsidiaryIsValid_ShouldReturnNull() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "123", + DataSubmissionPeriod = "2024-01", + ProducerId = "Producer1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteType", + PackagingCategory = "CategoryA", + MaterialType = "MaterialX", + MaterialSubType = "SubTypeX", + FromHomeNation = "Nation1", + ToHomeNation = "Nation2", + QuantityKg = "100", + QuantityUnits = "Units" + }; + var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToOrganisation = true }; + + // Act + var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); + + // Assert + Assert.IsNull(result); + + // _mockLogger.Verify(l => l.LogWarning(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + _mockFormatter.Verify(f => f.Format(It.IsAny(), It.IsAny()), Times.Never); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs new file mode 100644 index 0000000..ecf39a0 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs @@ -0,0 +1,218 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.TestSupport; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class ValidationServiceProducerRowValidatorTests + { + private Mock _mockFindMatchingProducer; + private ValidationServiceProducerRowValidator _validator; + + [TestInitialize] + public void Setup() + { + _mockFindMatchingProducer = new Mock(); + _validator = new ValidationServiceProducerRowValidator(_mockFindMatchingProducer.Object); + } + + [TestMethod] + public void ProcessRowsForValidationErrors_NoValidationErrors_ReturnsEmptyList() + { + // Arrange + var producerRow = ModelGenerator.CreateProducerRow(1); + var producerRowTwo = ModelGenerator.CreateProducerRow(2); + var producerRows = new List { producerRow, producerRowTwo }; + + var row1 = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub1", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteTypeA", + PackagingCategory = "CategoryA", + MaterialType = "MaterialA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "100", + QuantityUnits = "10" + }; + + var row2 = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub2", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod2", + RowNumber = 2, + ProducerType = "TypeB", + ProducerSize = "Small", + WasteType = "WasteTypeB", + PackagingCategory = "CategoryB", + MaterialType = "MaterialB", + MaterialSubType = "SubTypeB", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "200", + QuantityUnits = "20" + }; + var rows = new List + { + row1, + row2 + }; + + var response = new SubsidiaryDetailsResponse + { + // Initialize your response data + }; + + _mockFindMatchingProducer.Setup(x => x.Match(It.IsAny(), response, It.IsAny())).Returns((ProducerValidationEventIssueRequest)null); + + // Act + var result = _validator.ProcessRowsForValidationErrors(rows, response); + + // Assert + Assert.IsNotNull(result); + Assert.IsFalse(result.Any()); + } + + [TestMethod] + public void ProcessRowsForValidationErrors_SingleValidationError_ReturnsListWithOneError() + { + // Arrange + var row1 = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub1", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteTypeA", + PackagingCategory = "CategoryA", + MaterialType = "MaterialA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "100", + QuantityUnits = "10" + }; + + var row2 = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub2", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod2", + RowNumber = 2, + ProducerType = "TypeB", + ProducerSize = "Small", + WasteType = "WasteTypeB", + PackagingCategory = "CategoryB", + MaterialType = "MaterialB", + MaterialSubType = "SubTypeB", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "200", + QuantityUnits = "20" + }; + var rows = new List + { + row1, + row2 + }; + + var response = new SubsidiaryDetailsResponse + { + // Initialize your response data + }; + + var errorRequest = new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", ErrorCodes: new List { "Error1" }); + + _mockFindMatchingProducer.Setup(x => x.Match(rows[0], response, 0)).Returns(errorRequest); + _mockFindMatchingProducer.Setup(x => x.Match(rows[1], response, 1)).Returns((ProducerValidationEventIssueRequest)null); + + // Act + var result = _validator.ProcessRowsForValidationErrors(rows, response); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(1, result.Count()); + Assert.AreEqual(errorRequest, result.First()); + } + + [TestMethod] + public void ProcessRowsForValidationErrors_MultipleValidationErrors_ReturnsListWithAllErrors() + { + // Arrange + var row1 = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub1", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteTypeA", + PackagingCategory = "CategoryA", + MaterialType = "MaterialA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "100", + QuantityUnits = "10" + }; + + var row2 = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub2", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod2", + RowNumber = 2, + ProducerType = "TypeB", + ProducerSize = "Small", + WasteType = "WasteTypeB", + PackagingCategory = "CategoryB", + MaterialType = "MaterialB", + MaterialSubType = "SubTypeB", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "200", + QuantityUnits = "20" + }; + var rows = new List + { + row1, + row2 + }; + + var response = new SubsidiaryDetailsResponse + { + // Initialize your response data + }; + + var errorRequest1 = new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", ErrorCodes: new List { "Error1" }); + var errorRequest2 = new ProducerValidationEventIssueRequest("Sub2", "2024Q1", 2, "Prod2", "TypeB", "Small", "WasteTypeB", "CategoryB", "MaterialB", "SubTypeB", "NationA", "NationB", "200", "20", ErrorCodes: new List { "Error2" }); + + _mockFindMatchingProducer.Setup(x => x.Match(rows[0], response, 0)).Returns(errorRequest1); + _mockFindMatchingProducer.Setup(x => x.Match(rows[1], response, 1)).Returns(errorRequest2); + + // Act + var result = _validator.ProcessRowsForValidationErrors(rows, response); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(2, result.Count()); + Assert.IsTrue(result.Contains(errorRequest1)); + Assert.IsTrue(result.Contains(errorRequest2)); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index a1fbafc..e2e46a1 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -1,11 +1,11 @@ using AutoMapper; using EPR.ProducerContentValidation.Application.Clients; -using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Profiles; using EPR.ProducerContentValidation.Application.Services; +using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; @@ -37,6 +37,9 @@ public class ValidationServiceTests private Mock _featureManagerMock; private Mock _subsidiaryDetailsRequestBuilderMock; private Mock _companyDetailsApiClientMock; + private Mock _requestValidatorMock; + private Mock _validationServiceProducerRowValidatorMock; + private Mock _mockLogger; [TestInitialize] public void TestInitialize() @@ -46,8 +49,11 @@ public void TestInitialize() _issueCountServiceMock = new Mock(); _mapper = AutoMapperHelpers.GetMapper(); _featureManagerMock = new Mock(); + _requestValidatorMock = new Mock(); _subsidiaryDetailsRequestBuilderMock = new Mock(); _companyDetailsApiClientMock = new Mock(); + _validationServiceProducerRowValidatorMock = new Mock(); + _mockLogger = new Mock(); _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(ErrorStoreKey)) .ReturnsAsync(100); @@ -130,7 +136,7 @@ public async Task ValidateSubsidiary_SuccessfulValidation_ReturnsEmptyList() var service = CreateSystemUnderTest(); // Act - var result = await service.ValidateSubsidiary(rows); + var result = await service.ValidateSubsidiaryAsync(rows); // Assert Assert.IsNotNull(result); @@ -138,18 +144,36 @@ public async Task ValidateSubsidiary_SuccessfulValidation_ReturnsEmptyList() } [TestMethod] - public async Task ValidateSubsidiary_NullSubsidiaryDetailsResponse_ReturnsEmptyList() + public async Task ValidateSubsidiaryAsync_InvalidRequest_ReturnsEmptyList() { // Arrange - var rows = new List { /* example ProducerRow data */ }; - _subsidiaryDetailsRequestBuilderMock - .Setup(x => x.CreateRequest(rows)) - .Returns((SubsidiaryDetailsRequest)null); + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub1", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteTypeA", + PackagingCategory = "CategoryA", + MaterialType = "MaterialA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "100", + QuantityUnits = "10" + }; + var rows = new List { row }; + var subsidiaryDetailsRequest = new SubsidiaryDetailsRequest(); + + _subsidiaryDetailsRequestBuilderMock.Setup(x => x.CreateRequest(rows)).Returns(subsidiaryDetailsRequest); + _requestValidatorMock.Setup(x => x.IsInvalidRequest(subsidiaryDetailsRequest)).Returns(true); var service = CreateSystemUnderTest(); // Act - var result = await service.ValidateSubsidiary(rows); + var result = await service.ValidateSubsidiaryAsync(rows); // Assert Assert.IsNotNull(result); @@ -157,106 +181,135 @@ public async Task ValidateSubsidiary_NullSubsidiaryDetailsResponse_ReturnsEmptyL } [TestMethod] - public async Task ValidateSubsidiary_HttpRequestException_LogsErrorAndReturnsEmptyList() + public async Task ValidateSubsidiaryAsync_ValidRequest_ReturnsValidationErrors() { // Arrange - var rows = new List { /* example ProducerRow data */ }; - var exception = new HttpRequestException("An error occurred while creating the request."); - - _subsidiaryDetailsRequestBuilderMock - .Setup(x => x.CreateRequest(It.IsAny>())) - .Throws(exception); + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub1", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteTypeA", + PackagingCategory = "CategoryA", + MaterialType = "MaterialA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "100", + QuantityUnits = "10" + }; + var rows = new List { row }; + var subsidiaryDetailsRequest = new SubsidiaryDetailsRequest(); + var subsidiaryDetailsResponse = new SubsidiaryDetailsResponse(); + var validationErrors = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", ErrorCodes: new List { "Error1" }) + }; + _subsidiaryDetailsRequestBuilderMock.Setup(x => x.CreateRequest(rows)).Returns(subsidiaryDetailsRequest); + _requestValidatorMock.Setup(x => x.IsInvalidRequest(subsidiaryDetailsRequest)).Returns(false); + _companyDetailsApiClientMock.Setup(x => x.GetSubsidiaryDetails(subsidiaryDetailsRequest)).ReturnsAsync(subsidiaryDetailsResponse); + _validationServiceProducerRowValidatorMock.Setup(x => x.ProcessRowsForValidationErrors(rows, subsidiaryDetailsResponse)).Returns(validationErrors); var service = CreateSystemUnderTest(); // Act - var result = await service.ValidateSubsidiary(rows); + var result = await service.ValidateSubsidiaryAsync(rows); // Assert Assert.IsNotNull(result); - Assert.AreEqual(0, result.Count); - _loggerMock.Verify( - x => x.Log( - LogLevel.Error, - It.IsAny(), - It.Is((v, t) => v.ToString().Contains("Error Subsidiary validation")), - It.Is(ex => ex == exception), - It.IsAny>()), - Times.Once); + Assert.AreEqual(1, result.Count); + Assert.AreEqual(validationErrors.First(), result.First()); } [TestMethod] - public async Task ValidateAsync_WithSubsidiaryValidationEnabled_PerformsSubsidiaryValidation() + public async Task ValidateSubsidiaryAsync_HttpRequestException_LogsErrorAndReturnsEmptyList() { // Arrange - var producerRows = new List { ModelGenerator.CreateProducerRow(1) }; - var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); - - var validationErrors = new List(); + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub1", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteTypeA", + PackagingCategory = "CategoryA", + MaterialType = "MaterialA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "100", + QuantityUnits = "10" + }; + var rows = new List { row }; + var subsidiaryDetailsRequest = new SubsidiaryDetailsRequest(); - _featureManagerMock - .Setup(fm => fm.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)) - .ReturnsAsync(true); + _subsidiaryDetailsRequestBuilderMock.Setup(x => x.CreateRequest(rows)).Returns(subsidiaryDetailsRequest); + _requestValidatorMock.Setup(x => x.IsInvalidRequest(subsidiaryDetailsRequest)).Returns(false); + _companyDetailsApiClientMock.Setup(x => x.GetSubsidiaryDetails(subsidiaryDetailsRequest)).ThrowsAsync(new HttpRequestException()); + var service = CreateSystemUnderTest(); - _subsidiaryDetailsRequestBuilderMock - .Setup(x => x.CreateRequest(producer.Rows)) - .Returns(new SubsidiaryDetailsRequest() - { - SubsidiaryOrganisationDetails = new List() - { - new SubsidiaryOrganisationDetail() - { } - } - }); + // Act + var result = await service.ValidateSubsidiaryAsync(rows); - var subsidiaryOrganisationDetails = new List(); - subsidiaryOrganisationDetails.Add(new SubsidiaryOrganisationDetail - { - OrganisationReference = "sds", - SubsidiaryDetails = new List() - }); - var subsidiaryDetailsResponse = new SubsidiaryDetailsResponse(); - subsidiaryDetailsResponse.SubsidiaryOrganisationDetails = subsidiaryOrganisationDetails; + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); - _companyDetailsApiClientMock - .Setup(x => x.GetSubsidiaryDetails(It.IsAny())) - .ReturnsAsync(subsidiaryDetailsResponse); + // _mockLogger.Verify(x => x.LogError(It.IsAny(), "Error during subsidiary validation."), Times.Once); + } - _issueCountServiceMock - .Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())) - .ReturnsAsync(1); + // End + [TestMethod] + public async Task ValidateSubsidiary_NullSubsidiaryDetailsResponse_ReturnsEmptyList() + { + // Arrange + var rows = new List { /* example ProducerRow data */ }; + _subsidiaryDetailsRequestBuilderMock + .Setup(x => x.CreateRequest(rows)) + .Returns((SubsidiaryDetailsRequest)null); var service = CreateSystemUnderTest(); // Act - var result = await service.ValidateAsync(producer); + var result = await service.ValidateSubsidiaryAsync(rows); // Assert - _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(producer.Rows), Times.Once); - _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Once); + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); } [TestMethod] - public async Task ValidateAsync_WithSubsidiaryValidationDisabled_SkipsSubsidiaryValidation() + public async Task ValidateSubsidiary_HttpRequestException_LogsErrorAndReturnsEmptyList() { // Arrange - var producerRows = new List { ModelGenerator.CreateProducerRow(1) }; - var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); + var rows = new List { /* example ProducerRow data */ }; + var exception = new HttpRequestException("An error occurred while creating the request."); - // Mock feature flag to disable subsidiary validation - _featureManagerMock - .Setup(fm => fm.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)) - .ReturnsAsync(false); + _subsidiaryDetailsRequestBuilderMock + .Setup(x => x.CreateRequest(It.IsAny>())) + .Throws(exception); var service = CreateSystemUnderTest(); // Act - var result = await service.ValidateAsync(producer); + var result = await service.ValidateSubsidiaryAsync(rows); // Assert - _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(It.IsAny>()), Times.Never); - _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Never); - result.ValidationErrors.Should().BeEmpty(); + Assert.IsNotNull(result); + Assert.AreEqual(0, result.Count); + _loggerMock.Verify( + x => x.Log( + LogLevel.Error, + It.IsAny(), + It.Is((v, t) => v.ToString().Contains("Error during subsidiary validation.")), + It.Is(ex => ex == exception), + It.IsAny>()), + Times.Once); } private ValidationService CreateSystemUnderTest() => @@ -268,5 +321,7 @@ private ValidationService CreateSystemUnderTest() => Microsoft.Extensions.Options.Options.Create(new StorageAccountOptions { PomContainer = ContainerName }), _featureManagerMock.Object, _subsidiaryDetailsRequestBuilderMock.Object, - _companyDetailsApiClientMock.Object); + _companyDetailsApiClientMock.Object, + _requestValidatorMock.Object, + _validationServiceProducerRowValidatorMock.Object); } \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs index a8583b9..30683d6 100644 --- a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs +++ b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs @@ -4,6 +4,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Services; +using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators; @@ -33,7 +34,14 @@ private static void RegisterServices(this IServiceCollection services) .AddScoped() .AddScoped() .AddSingleton(ConnectionMultiplexer.Connect(redisOptions.ConnectionString)) - .AddSingleton(); + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton(); } private static IServiceCollection ConfigureOptions(this IServiceCollection services) diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs new file mode 100644 index 0000000..e8814b0 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs @@ -0,0 +1,38 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public class FindMatchingProducer : IFindMatchingProducer + { + private readonly IOrganisationMatcher _organisationMatcher; + private readonly ISubsidiaryMatcher _subsidiaryMatcher; + private readonly ISubsidiaryValidationEvaluator _subsidiaryValidationEvaluator; + + public FindMatchingProducer(IOrganisationMatcher organisationMatcher, ISubsidiaryMatcher subsidiaryMatcher, ISubsidiaryValidationEvaluator subsidiaryValidationEvaluator) + { + _organisationMatcher = organisationMatcher; + _subsidiaryMatcher = subsidiaryMatcher; + _subsidiaryValidationEvaluator = subsidiaryValidationEvaluator; + } + + public ProducerValidationEventIssueRequest? Match( + ProducerRow row, SubsidiaryDetailsResponse response, int rowIndex) + { + var matchingOrg = _organisationMatcher.FindMatchingOrganisation(row, response); + if (matchingOrg == null) + { + return null; + } + + var matchingSub = _subsidiaryMatcher.FindMatchingSubsidiary(row, matchingOrg); + if (matchingSub == null) + { + return null; + } + + return _subsidiaryValidationEvaluator.EvaluateSubsidiaryValidation(row, matchingSub, rowIndex); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IFindMatchingProducer.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IFindMatchingProducer.cs new file mode 100644 index 0000000..6b8040a --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IFindMatchingProducer.cs @@ -0,0 +1,11 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public interface IFindMatchingProducer + { + ProducerValidationEventIssueRequest? Match(ProducerRow row, SubsidiaryDetailsResponse response, int rowIndex); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IOrganisationMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IOrganisationMatcher.cs new file mode 100644 index 0000000..e990a26 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IOrganisationMatcher.cs @@ -0,0 +1,10 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public interface IOrganisationMatcher + { + SubsidiaryOrganisationDetail? FindMatchingOrganisation(ProducerRow row, SubsidiaryDetailsResponse response); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IProducerValidationEventIssueRequestFormatter.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IProducerValidationEventIssueRequestFormatter.cs new file mode 100644 index 0000000..b196450 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IProducerValidationEventIssueRequestFormatter.cs @@ -0,0 +1,10 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public interface IProducerValidationEventIssueRequestFormatter + { + ProducerValidationEventIssueRequest Format(ProducerRow row, string errorCode); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IRequestValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IRequestValidator.cs new file mode 100644 index 0000000..4e54b82 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IRequestValidator.cs @@ -0,0 +1,9 @@ +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public interface IRequestValidator + { + bool IsInvalidRequest(SubsidiaryDetailsRequest request); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryMatcher.cs new file mode 100644 index 0000000..5f3b696 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryMatcher.cs @@ -0,0 +1,10 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public interface ISubsidiaryMatcher + { + SubsidiaryDetail? FindMatchingSubsidiary(ProducerRow row, SubsidiaryOrganisationDetail org); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryValidationEvaluator.cs new file mode 100644 index 0000000..0d19fe0 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryValidationEvaluator.cs @@ -0,0 +1,11 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public interface ISubsidiaryValidationEvaluator + { + ProducerValidationEventIssueRequest? EvaluateSubsidiaryValidation(ProducerRow row, SubsidiaryDetail subsidiary, int rowIndex); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IValidationServiceProducerRowValidator.cs new file mode 100644 index 0000000..2ed81ec --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/IValidationServiceProducerRowValidator.cs @@ -0,0 +1,12 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public interface IValidationServiceProducerRowValidator + { + IEnumerable ProcessRowsForValidationErrors( + List rows, SubsidiaryDetailsResponse response); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs new file mode 100644 index 0000000..036b944 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs @@ -0,0 +1,14 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public class OrganisationMatcher : IOrganisationMatcher + { + public SubsidiaryOrganisationDetail? FindMatchingOrganisation(ProducerRow row, SubsidiaryDetailsResponse response) + { + return response.SubsidiaryOrganisationDetails + .FirstOrDefault(org => org.OrganisationReference == row.ProducerId); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs new file mode 100644 index 0000000..52c6b53 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs @@ -0,0 +1,30 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public class ProducerValidationEventIssueRequestFormatter : IProducerValidationEventIssueRequestFormatter + { + public ProducerValidationEventIssueRequest Format(ProducerRow row, string errorCode) + { + var errorCodes = new List { errorCode }; + + return new ProducerValidationEventIssueRequest( + SubsidiaryId: row.SubsidiaryId ?? string.Empty, + DataSubmissionPeriod: row.DataSubmissionPeriod ?? string.Empty, + RowNumber: row.RowNumber, + ProducerId: row.ProducerId ?? string.Empty, + ProducerType: row.ProducerType ?? string.Empty, + ProducerSize: row.ProducerSize ?? string.Empty, + WasteType: row.WasteType ?? string.Empty, + PackagingCategory: row.PackagingCategory ?? string.Empty, + MaterialType: row.MaterialType ?? string.Empty, + MaterialSubType: row.MaterialSubType ?? string.Empty, + FromHomeNation: row.FromHomeNation ?? string.Empty, + ToHomeNation: row.ToHomeNation ?? string.Empty, + QuantityKg: row.QuantityKg ?? string.Empty, + QuantityUnits: row.QuantityUnits ?? string.Empty, + ErrorCodes: errorCodes); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs new file mode 100644 index 0000000..8fe3cb8 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs @@ -0,0 +1,10 @@ +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public class RequestValidator : IRequestValidator + { + public bool IsInvalidRequest(SubsidiaryDetailsRequest request) => + request?.SubsidiaryOrganisationDetails == null || !request.SubsidiaryOrganisationDetails.Any(); + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs new file mode 100644 index 0000000..88935f4 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs @@ -0,0 +1,14 @@ +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public class SubsidiaryMatcher : ISubsidiaryMatcher + { + public SubsidiaryDetail? FindMatchingSubsidiary(ProducerRow row, SubsidiaryOrganisationDetail org) + { + return org.SubsidiaryDetails + .FirstOrDefault(sub => sub.ReferenceNumber == row.SubsidiaryId); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs new file mode 100644 index 0000000..af22a83 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs @@ -0,0 +1,42 @@ +using EPR.ProducerContentValidation.Application.Constants; +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using Microsoft.Extensions.Logging; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public class SubsidiaryValidationEvaluator : ISubsidiaryValidationEvaluator + { + private readonly ILogger _logger; + private readonly IProducerValidationEventIssueRequestFormatter _producerValidationEventIssueRequestFormatter; + + public SubsidiaryValidationEvaluator(ILogger logger, IProducerValidationEventIssueRequestFormatter producerValidationEventIssueRequestFormatter) + { + _logger = logger; + _producerValidationEventIssueRequestFormatter = producerValidationEventIssueRequestFormatter; + } + + public ProducerValidationEventIssueRequest? EvaluateSubsidiaryValidation(ProducerRow row, SubsidiaryDetail subsidiary, int rowIndex) + { + if (!subsidiary.SubsidiaryExists) + { + LogValidationWarning(rowIndex + 1, "Subsidiary ID does not exist", ErrorCode.SubsidiaryIdDoesNotExist); + return _producerValidationEventIssueRequestFormatter.Format(row, ErrorCode.SubsidiaryIdDoesNotExist); + } + + if (!subsidiary.SubsidiaryBelongsToOrganisation) + { + LogValidationWarning(rowIndex + 1, "Subsidiary ID is assigned to a different organisation", ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); + return _producerValidationEventIssueRequestFormatter.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); + } + + return null; + } + + private void LogValidationWarning(int rowNumber, string message, string errorCode) + { + _logger.LogWarning("Validation Warning at row {RowNumber}: {Message} (ErrorCode: {ErrorCode})", rowNumber, message, errorCode); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs new file mode 100644 index 0000000..b150b2a --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs @@ -0,0 +1,33 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public class ValidationServiceProducerRowValidator : IValidationServiceProducerRowValidator + { + private readonly IFindMatchingProducer _findMatchingProducer; + + public ValidationServiceProducerRowValidator(IFindMatchingProducer findMatchingProducer) + { + _findMatchingProducer = findMatchingProducer; + } + + public IEnumerable ProcessRowsForValidationErrors( + List rows, SubsidiaryDetailsResponse response) + { + var validationErrors = new List(); + + for (int i = 0; i < rows.Count; i++) + { + var error = _findMatchingProducer.Match(rows[i], response, i); + if (error != null) + { + validationErrors.Add(error); + } + } + + return validationErrors; + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index 4056839..51c88b0 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -5,9 +5,11 @@ using EPR.ProducerContentValidation.Application.Extensions; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; +using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.FeatureManagement; @@ -23,7 +25,9 @@ public class ValidationService : IValidationService private readonly StorageAccountOptions _storageAccountOptions; private readonly ISubsidiaryDetailsRequestBuilder _subsidiaryDetailsRequestBuilder; private readonly ICompanyDetailsApiClient _companyDetailsApiClient; - private IFeatureManager _featureManager; + private readonly IFeatureManager _featureManager; + private readonly IRequestValidator _requestValidator; + private readonly IValidationServiceProducerRowValidator _validationServiceProducerRowValidator; public ValidationService( ILogger logger, @@ -33,7 +37,9 @@ public ValidationService( IOptions storageAccountOptions, IFeatureManager featureManager, ISubsidiaryDetailsRequestBuilder subsidiaryDetailsRequestBuilder, - ICompanyDetailsApiClient companyDetailsApiClient) + ICompanyDetailsApiClient companyDetailsApiClient, + IRequestValidator requestValidator, + IValidationServiceProducerRowValidator validationServiceProducerRowValidator) { _logger = logger; _compositeValidator = compositeValidator; @@ -43,6 +49,8 @@ public ValidationService( _featureManager = featureManager; _subsidiaryDetailsRequestBuilder = subsidiaryDetailsRequestBuilder; _companyDetailsApiClient = companyDetailsApiClient; + _requestValidator = requestValidator; + _validationServiceProducerRowValidator = validationServiceProducerRowValidator; } public async Task ValidateAsync(Producer producer) @@ -77,7 +85,7 @@ public async Task ValidateAsync(Producer producer) if (await _featureManager.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)) { - List subValidationResult = await ValidateSubsidiary(producer.Rows); + List subValidationResult = await ValidateSubsidiaryAsync(producer.Rows); producerValidationOutRequest.ValidationErrors.AddRange(subValidationResult.Take(remainingErrorCapacity - errors.Count)); } @@ -86,66 +94,46 @@ public async Task ValidateAsync(Producer producer) return producerValidationOutRequest; } - public async Task> ValidateSubsidiary(List rows) + public async Task> ValidateSubsidiaryAsync(List rows) { - List validationErrors = new(); + var validationErrors = new List(); + try { - var subsidiaryDetailsRequest = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); - if (subsidiaryDetailsRequest == null || subsidiaryDetailsRequest.SubsidiaryOrganisationDetails == null || !subsidiaryDetailsRequest.SubsidiaryOrganisationDetails.Any()) + var subsidiaryDetailsRequest = BuildSubsidiaryRequest(rows); + if (_requestValidator.IsInvalidRequest(subsidiaryDetailsRequest)) { return validationErrors; } - var result = await _companyDetailsApiClient.GetSubsidiaryDetails(subsidiaryDetailsRequest); - - for (int i = 0; i < rows.Count; i++) - { - var matchingOrg = result.SubsidiaryOrganisationDetails - .FirstOrDefault(org => org.OrganisationReference == rows[i].ProducerId); - - if (matchingOrg == null) - { - continue; - } - - var matchingSub = matchingOrg.SubsidiaryDetails - .FirstOrDefault(sub => sub.ReferenceNumber == rows[i].SubsidiaryId); - - if (matchingSub == null) - { - continue; - } - - if (!matchingSub.SubsidiaryExists) - { - var error = CreateSubValidationError(rows[i], ErrorCode.SubsidiaryIdDoesNotExist); - var errorMessage = $"Subsidiary ID does not exist"; - - LogValidationWarning(i + 1, errorMessage, ErrorCode.SubsidiaryIdDoesNotExist); - validationErrors.Add(error); - continue; - } - - if (!matchingSub.SubsidiaryBelongsToOrganisation) - { - var error = CreateSubValidationError(rows[i], ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); - var errorMessage = $"Subsidiary ID is assigned to a different organisation"; - - LogValidationWarning(i + 1, errorMessage, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); - validationErrors.Add(error); - } - } + var subsidiaryDetailsResponse = await FetchSubsidiaryDetailsAsync(subsidiaryDetailsRequest); + validationErrors.AddRange(_validationServiceProducerRowValidator.ProcessRowsForValidationErrors(rows, subsidiaryDetailsResponse)); return validationErrors; } catch (HttpRequestException exception) { - _logger.LogError(exception, "Error Subsidiary validation"); + LogRequestError(exception); return validationErrors; } } + // Helper Methods + private SubsidiaryDetailsRequest BuildSubsidiaryRequest(List rows) => + _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + private async Task FetchSubsidiaryDetailsAsync(SubsidiaryDetailsRequest request) => + await _companyDetailsApiClient.GetSubsidiaryDetails(request); + + private SubsidiaryOrganisationDetail? FindMatchingOrganisation(ProducerRow row, SubsidiaryDetailsResponse response) => + response.SubsidiaryOrganisationDetails.FirstOrDefault(org => org.OrganisationReference == row.ProducerId); + + private SubsidiaryDetail? FindMatchingSubsidiary(ProducerRow row, SubsidiaryOrganisationDetail org) => + org.SubsidiaryDetails.FirstOrDefault(sub => sub.ReferenceNumber == row.SubsidiaryId); + + private void LogRequestError(HttpRequestException exception) => + _logger.LogError(exception, "Error during subsidiary validation."); + private void LogValidationWarning(int rowNumber, string errorMessage, string errorCode) { _logger.LogWarning( @@ -154,9 +142,4 @@ private void LogValidationWarning(int rowNumber, string errorMessage, string err errorMessage, errorCode); } - - private ProducerValidationEventIssueRequest CreateSubValidationError(ProducerRow row, object subsidiaryIdDoesNotExist) - { - throw new NotImplementedException(); - } } \ No newline at end of file From 694fffb031ca5f3fcfd006ac251f39da769bb661 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Tue, 29 Oct 2024 11:14:53 +0000 Subject: [PATCH 07/44] added tests --- .../Clients/CompanyDetailsApiClientTests.cs | 110 ++++++++ .../CompanyDetailsDataItem.cs | 12 + .../CompanyDetailsDataResult.cs | 9 + .../SubsidiaryDetailsRequestBuilderTests.cs | 244 +++++++++--------- 4 files changed, 255 insertions(+), 120 deletions(-) create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs create mode 100644 src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs new file mode 100644 index 0000000..5a4431e --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs @@ -0,0 +1,110 @@ +using System.Net; +using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Data.Config; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using FluentAssertions; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Moq.Protected; +using Newtonsoft.Json; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Clients +{ + [TestClass] + public class CompanyDetailsApiClientTests + { + private CompanyDetailsApiConfig? _config; + + [TestInitialize] + public void Setup() + { + _config = new CompanyDetailsApiConfig + { + BaseUrl = "https://www.testurl.com", + ClientId = "test-client-id", + Timeout = 5, + }; + } + + [TestMethod] + public async Task GetSubsidiaryDetails_ShouldReturnSubsidiaryDetailsRequest_OnSuccess() + { + // Arrange + var request = new SubsidiaryDetailsRequest(); + var content = JsonConvert.SerializeObject(request); + var responseMessage = new HttpResponseMessage + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(content), + }; + var handlerMock = new Mock(MockBehavior.Strict); + handlerMock + .Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(content), + }) + .Verifiable(); + var httpClient = new HttpClient(handlerMock.Object) + { + BaseAddress = new Uri(_config.BaseUrl), + Timeout = TimeSpan.FromSeconds(_config.Timeout), + }; + var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); + + // Act + var result = await sut.GetSubsidiaryDetails(request); + + // Assert + result.Should().BeEquivalentTo(request); + handlerMock.Protected().Verify( + "SendAsync", + Times.Once(), + ItExpr.Is(req => + req.Method == HttpMethod.Post && + req.RequestUri.ToString().EndsWith("api/subsidiary-details")), + ItExpr.IsAny()); + } + + [DataRow(HttpStatusCode.Conflict)] + [DataRow(HttpStatusCode.BadRequest)] + [DataRow(HttpStatusCode.BadGateway)] + [DataRow(HttpStatusCode.Unauthorized)] + [TestMethod] + public async Task GetSubsidiaryDetails_WhenSendAsyncNotSuccessful_ThrowsError(HttpStatusCode statusCode) + { + // Arrange + var handlerMock = new Mock(MockBehavior.Strict); + handlerMock + .Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = statusCode, + }) + .Verifiable(); + + var httpClient = new HttpClient(handlerMock.Object) + { + BaseAddress = new Uri(_config.BaseUrl), + Timeout = TimeSpan.FromSeconds(_config.Timeout), + }; + var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); + + // Act + Func act = () => sut.GetSubsidiaryDetails(new SubsidiaryDetailsRequest()); + + // Assert + await act.Should().ThrowAsync(); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs new file mode 100644 index 0000000..81a58ee --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs @@ -0,0 +1,12 @@ +namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; + +using Newtonsoft.Json; + +public class CompanyDetailsDataItem +{ + [JsonProperty("RN")] + public string ReferenceNumber { get; set; } + + [JsonProperty("CHN")] + public string CompaniesHouseNumber { get; set; } +} \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs new file mode 100644 index 0000000..25a585e --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs @@ -0,0 +1,9 @@ +namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; + +using Newtonsoft.Json; + +public class CompanyDetailsDataResult +{ + [JsonProperty(nameof(Organisations))] + public IEnumerable Organisations { get; set; } +} diff --git a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs index 663796f..cc0b806 100644 --- a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs +++ b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs @@ -17,9 +17,13 @@ public void Setup() [TestMethod] public void CreateRequest_ShouldReturnEmptyRequest_WhenRowsIsEmpty() { + // Arrange var rows = new List(); + + // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + // Assert Assert.IsNotNull(result); Assert.IsNotNull(result.SubsidiaryOrganisationDetails); Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); @@ -30,40 +34,40 @@ public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: "Subsidiary Id 1", - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1"), - new ProducerRow( - SubsidiaryId: string.Empty, - DataSubmissionPeriod: "Period 2", - ProducerId: "1", - RowNumber: 2, - ProducerType: "Type 2", - ProducerSize: "Size 2", - WasteType: "Waste 2", - PackagingCategory: "Category 2", - MaterialType: "Type 2", - MaterialSubType: "SubType 2", - FromHomeNation: "Nation 2", - ToHomeNation: "Nation 2", - QuantityKg: "200", - QuantityUnits: "1000", - SubmissionPeriod: "Period 2") - }; + { + new ProducerRow( + SubsidiaryId: "Subsidiary Id 1", + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Period 2", + ProducerId: "1", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); @@ -82,24 +86,24 @@ public void CreateRequest_ShouldHandleNoValidSubsidiaryIds() { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: string.Empty, - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1") - }; + { + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); @@ -114,40 +118,40 @@ public void CreateRequest_ShouldGroupByProducerId_WithMultipleValidSubsidiaryIds { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: "SubId1", - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1"), - new ProducerRow( - SubsidiaryId: "SubId2", - DataSubmissionPeriod: "Period 2", - ProducerId: "1", - RowNumber: 2, - ProducerType: "Type 2", - ProducerSize: "Size 2", - WasteType: "Waste 2", - PackagingCategory: "Category 2", - MaterialType: "Type 2", - MaterialSubType: "SubType 2", - FromHomeNation: "Nation 2", - ToHomeNation: "Nation 2", - QuantityKg: "200", - QuantityUnits: "1000", - SubmissionPeriod: "Period 2") - }; + { + new ProducerRow( + SubsidiaryId: "SubId1", + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: "SubId2", + DataSubmissionPeriod: "Period 2", + ProducerId: "1", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); @@ -167,40 +171,40 @@ public void CreateRequest_ShouldReturnMultipleOrganisationsWithValidSubsidiaryId { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: "SubId1", - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1"), - new ProducerRow( - SubsidiaryId: "SubId2", - DataSubmissionPeriod: "Period 2", - ProducerId: "2", - RowNumber: 2, - ProducerType: "Type 2", - ProducerSize: "Size 2", - WasteType: "Waste 2", - PackagingCategory: "Category 2", - MaterialType: "Type 2", - MaterialSubType: "SubType 2", - FromHomeNation: "Nation 2", - ToHomeNation: "Nation 2", - QuantityKg: "200", - QuantityUnits: "1000", - SubmissionPeriod: "Period 2") - }; + { + new ProducerRow( + SubsidiaryId: "SubId1", + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: "SubId2", + DataSubmissionPeriod: "Period 2", + ProducerId: "2", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); From aa3999e50f00255f23b584dd375358a0a9cfb5ef Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Tue, 29 Oct 2024 13:01:35 +0000 Subject: [PATCH 08/44] Correction of error thrown up in the Build Docker Image satge of the build pipeline --- src/EPR.ProducerContentValidation.FunctionApp/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile index 30f9ead..bfabcea 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile +++ b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile @@ -8,6 +8,7 @@ FROM mcr.microsoft.com/dotnet/sdk:8.0 AS installer-env COPY stylecop.ruleset ./ COPY Directory.Build.props ./ COPY EPR.ProducerContentValidation.Application/. ./EPR.ProducerContentValidation.Application/. +COPY EPR.RegistrationValidation.Data/. ./EPR.RegistrationValidation.Data/. COPY EPR.ProducerContentValidation.FunctionApp/. ./EPR.ProducerContentValidation.FunctionApp/. RUN dotnet publish EPR.ProducerContentValidation.FunctionApp/*.csproj --output /home/site/wwwroot From 9db9f185f79e7006b890141c69662c6e1c582edc Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Tue, 29 Oct 2024 15:09:25 +0000 Subject: [PATCH 09/44] Corrected filename in Dockerfile --- src/EPR.ProducerContentValidation.FunctionApp/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile index bfabcea..dfe992d 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile +++ b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile @@ -8,7 +8,7 @@ FROM mcr.microsoft.com/dotnet/sdk:8.0 AS installer-env COPY stylecop.ruleset ./ COPY Directory.Build.props ./ COPY EPR.ProducerContentValidation.Application/. ./EPR.ProducerContentValidation.Application/. -COPY EPR.RegistrationValidation.Data/. ./EPR.RegistrationValidation.Data/. +COPY EPR.ProducerContentValidation.Data/. ./EPR.ProducerContentValidation.Data/. COPY EPR.ProducerContentValidation.FunctionApp/. ./EPR.ProducerContentValidation.FunctionApp/. RUN dotnet publish EPR.ProducerContentValidation.FunctionApp/*.csproj --output /home/site/wwwroot From d41fb58b2b138f5fddfd3dc944d019127bce80b9 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Tue, 29 Oct 2024 15:32:03 +0000 Subject: [PATCH 10/44] Added more tests --- .../Services/ValidationServiceTests.cs | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index e2e46a1..467b7db 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -1,5 +1,6 @@ using AutoMapper; using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; @@ -144,7 +145,7 @@ public async Task ValidateSubsidiary_SuccessfulValidation_ReturnsEmptyList() } [TestMethod] - public async Task ValidateSubsidiaryAsync_InvalidRequest_ReturnsEmptyList() + public async Task ValidateSubsidiaryAsyncInvalidRequestReturnsEmptyList() { // Arrange var row = ModelGenerator.CreateProducerRow(1) with @@ -312,6 +313,60 @@ public async Task ValidateSubsidiary_HttpRequestException_LogsErrorAndReturnsEmp Times.Once); } + [TestMethod] + public async Task ValidateAsync_WhenFeatureFlagIsOff_DoesNotPerformSubsidiaryValidation() + { + // Arrange + var producer = new Producer(Guid.NewGuid(), "000123", "test-blob", new List { ModelGenerator.CreateProducerRow(1) }); + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)).ReturnsAsync(false); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(It.IsAny>()), Times.Never); + _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Never); + Assert.IsNotNull(result); + } + + [TestMethod] + public async Task ValidateAsync_WhenRemainingWarningCapacityIsZero_OnlyErrorsAreValidated() + { + // Arrange + var producer = new Producer(Guid.NewGuid(), "000123", "test-blob", new List { ModelGenerator.CreateProducerRow(1) }); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync("test-blob:error")).ReturnsAsync(100); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync("test-blob:warning")).ReturnsAsync(0); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + Assert.IsNotNull(result); + Assert.IsTrue(result.ValidationWarnings.Count == 0); + } + + [TestMethod] + public async Task ValidateSubsidiaryAsync_InvalidRequest_ReturnsEmptyList() + { + // Arrange + var rows = new List { ModelGenerator.CreateProducerRow(1) }; + var subsidiaryDetailsRequest = new SubsidiaryDetailsRequest(); + _subsidiaryDetailsRequestBuilderMock.Setup(x => x.CreateRequest(rows)).Returns(subsidiaryDetailsRequest); + _requestValidatorMock.Setup(x => x.IsInvalidRequest(subsidiaryDetailsRequest)).Returns(true); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateSubsidiaryAsync(rows); + + // Assert + Assert.AreEqual(0, result.Count); + } + private ValidationService CreateSystemUnderTest() => new( _loggerMock.Object, From f788bdcffcdcbbd4f7e961608e95baa099df189e Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Tue, 29 Oct 2024 16:53:11 +0000 Subject: [PATCH 11/44] Added more tests --- .../Services/ValidationServiceTests.cs | 47 +++ .../Services/ValidationService.cs | 9 - .../SubsidiaryDetailsRequestBuilderTests.cs | 277 ++++++++++-------- 3 files changed, 202 insertions(+), 131 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 467b7db..9d4ccb1 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -331,6 +331,25 @@ public async Task ValidateAsync_WhenFeatureFlagIsOff_DoesNotPerformSubsidiaryVal Assert.IsNotNull(result); } + [TestMethod] + public async Task ValidateAsync_WhenFeatureFlagIsOn_DoesPerformSubsidiaryValidation() + { + // Arrange + var producer = new Producer(Guid.NewGuid(), "000123", "test-blob", new List { ModelGenerator.CreateProducerRow(1) }); + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)).ReturnsAsync(true); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(1); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(It.IsAny>()), Times.Once); + _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Once); + Assert.IsNotNull(result); + } + [TestMethod] public async Task ValidateAsync_WhenRemainingWarningCapacityIsZero_OnlyErrorsAreValidated() { @@ -367,6 +386,34 @@ public async Task ValidateSubsidiaryAsync_InvalidRequest_ReturnsEmptyList() Assert.AreEqual(0, result.Count); } + [TestMethod] + public async Task ValidateAsync_WhenWarningCapacityReached_LogsWarning() + { + // Arrange + var rows = new List { ModelGenerator.CreateProducerRow(1) }; + var producer = new Producer(_submissionId, ProducerId, BlobName, rows); + + // Simulate reaching warning capacity + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(WarningStoreKey)).ReturnsAsync(0); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + _loggerMock.Verify( + x => x.Log( + LogLevel.Warning, + It.IsAny(), + It.Is((v, t) => v.ToString().Contains("No capacity left to process issues.")), + It.IsAny(), + It.IsAny>()), + Times.Never); + Assert.IsNotNull(result); + Assert.AreEqual(0, result.ValidationWarnings.Count); + } + private ValidationService CreateSystemUnderTest() => new( _loggerMock.Object, diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index 51c88b0..654118d 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -133,13 +133,4 @@ private async Task FetchSubsidiaryDetailsAsync(Subsid private void LogRequestError(HttpRequestException exception) => _logger.LogError(exception, "Error during subsidiary validation."); - - private void LogValidationWarning(int rowNumber, string errorMessage, string errorCode) - { - _logger.LogWarning( - "Validation error on row {Row} {ErrorMessage} Error code {ErrorCode}", - rowNumber, - errorMessage, - errorCode); - } } \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs index cc0b806..3041710 100644 --- a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs +++ b/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs @@ -34,40 +34,40 @@ public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: "Subsidiary Id 1", - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1"), - new ProducerRow( - SubsidiaryId: string.Empty, - DataSubmissionPeriod: "Period 2", - ProducerId: "1", - RowNumber: 2, - ProducerType: "Type 2", - ProducerSize: "Size 2", - WasteType: "Waste 2", - PackagingCategory: "Category 2", - MaterialType: "Type 2", - MaterialSubType: "SubType 2", - FromHomeNation: "Nation 2", - ToHomeNation: "Nation 2", - QuantityKg: "200", - QuantityUnits: "1000", - SubmissionPeriod: "Period 2") - }; + { + new ProducerRow( + SubsidiaryId: "Subsidiary Id 1", + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Period 2", + ProducerId: "1", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); @@ -75,10 +75,11 @@ public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() // Assert Assert.IsNotNull(result); Assert.AreEqual(1, result.SubsidiaryOrganisationDetails.Count); - var org = result.SubsidiaryOrganisationDetails.FirstOrDefault(o => o.OrganisationReference == "1"); + var org = result.SubsidiaryOrganisationDetails.First(); Assert.IsNotNull(org); + Assert.AreEqual("1", org.OrganisationReference); Assert.AreEqual(1, org.SubsidiaryDetails.Count); - Assert.IsTrue(org.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "Subsidiary Id 1")); + Assert.AreEqual("Subsidiary Id 1", org.SubsidiaryDetails[0].ReferenceNumber); } [TestMethod] @@ -86,24 +87,24 @@ public void CreateRequest_ShouldHandleNoValidSubsidiaryIds() { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: string.Empty, - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1") - }; + { + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); @@ -118,40 +119,40 @@ public void CreateRequest_ShouldGroupByProducerId_WithMultipleValidSubsidiaryIds { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: "SubId1", - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1"), - new ProducerRow( - SubsidiaryId: "SubId2", - DataSubmissionPeriod: "Period 2", - ProducerId: "1", - RowNumber: 2, - ProducerType: "Type 2", - ProducerSize: "Size 2", - WasteType: "Waste 2", - PackagingCategory: "Category 2", - MaterialType: "Type 2", - MaterialSubType: "SubType 2", - FromHomeNation: "Nation 2", - ToHomeNation: "Nation 2", - QuantityKg: "200", - QuantityUnits: "1000", - SubmissionPeriod: "Period 2") - }; + { + new ProducerRow( + SubsidiaryId: "SubId1", + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: "SubId2", + DataSubmissionPeriod: "Period 2", + ProducerId: "1", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); @@ -171,40 +172,40 @@ public void CreateRequest_ShouldReturnMultipleOrganisationsWithValidSubsidiaryId { // Arrange var rows = new List - { - new ProducerRow( - SubsidiaryId: "SubId1", - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1"), - new ProducerRow( - SubsidiaryId: "SubId2", - DataSubmissionPeriod: "Period 2", - ProducerId: "2", - RowNumber: 2, - ProducerType: "Type 2", - ProducerSize: "Size 2", - WasteType: "Waste 2", - PackagingCategory: "Category 2", - MaterialType: "Type 2", - MaterialSubType: "SubType 2", - FromHomeNation: "Nation 2", - ToHomeNation: "Nation 2", - QuantityKg: "200", - QuantityUnits: "1000", - SubmissionPeriod: "Period 2") - }; + { + new ProducerRow( + SubsidiaryId: "SubId1", + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: "SubId2", + DataSubmissionPeriod: "Period 2", + ProducerId: "2", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") + }; // Act var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); @@ -215,5 +216,37 @@ public void CreateRequest_ShouldReturnMultipleOrganisationsWithValidSubsidiaryId Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(o => o.OrganisationReference == "1")); Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(o => o.OrganisationReference == "2")); } + + [TestMethod] + public void CreateRequest_ShouldIgnoreRowsWithWhitespaceSubsidiaryId() + { + // Arrange + var rows = new List + { + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1") + }; + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); + } } } From c45a0513fbd3fb0d828028d3f12708ed673eeea5 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 10:31:49 +0000 Subject: [PATCH 12/44] Added more tests --- .../Services/ValidationServiceTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 9d4ccb1..e059a82 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -260,8 +260,6 @@ public async Task ValidateSubsidiaryAsync_HttpRequestException_LogsErrorAndRetur // Assert Assert.IsNotNull(result); Assert.AreEqual(0, result.Count); - - // _mockLogger.Verify(x => x.LogError(It.IsAny(), "Error during subsidiary validation."), Times.Once); } // End From b4de89eb392a4be73c0cc800cd5a455009f230c0 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 11:40:46 +0000 Subject: [PATCH 13/44] Added more tests --- .../Services/ValidationServiceTests.cs | 4 ++-- .../ConfigureServices.cs | 4 ++-- .../Constants/FeatureFlags.cs | 2 +- .../EPR.ProducerContentValidation.Application.csproj | 4 ++++ .../Services/ValidationService.cs | 8 +------- .../settings.json | 2 +- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index e059a82..56138f1 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -316,7 +316,7 @@ public async Task ValidateAsync_WhenFeatureFlagIsOff_DoesNotPerformSubsidiaryVal { // Arrange var producer = new Producer(Guid.NewGuid(), "000123", "test-blob", new List { ModelGenerator.CreateProducerRow(1) }); - _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)).ReturnsAsync(false); + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)).ReturnsAsync(false); var service = CreateSystemUnderTest(); @@ -334,7 +334,7 @@ public async Task ValidateAsync_WhenFeatureFlagIsOn_DoesPerformSubsidiaryValidat { // Arrange var producer = new Producer(Guid.NewGuid(), "000123", "test-blob", new List { ModelGenerator.CreateProducerRow(1) }); - _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)).ReturnsAsync(true); + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)).ReturnsAsync(true); _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(1); var service = CreateSystemUnderTest(); diff --git a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs index 30683d6..a6b7767 100644 --- a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs +++ b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs @@ -31,7 +31,6 @@ private static void RegisterServices(this IServiceCollection services) { var redisOptions = services.BuildServiceProvider().GetRequiredService>().Value; services - .AddScoped() .AddScoped() .AddSingleton(ConnectionMultiplexer.Connect(redisOptions.ConnectionString)) .AddSingleton() @@ -41,7 +40,8 @@ private static void RegisterServices(this IServiceCollection services) .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton(); + .AddSingleton() + .AddScoped(); } private static IServiceCollection ConfigureOptions(this IServiceCollection services) diff --git a/src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs b/src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs index 72ef6a1..c9cb1a9 100644 --- a/src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs +++ b/src/EPR.ProducerContentValidation.Application/Constants/FeatureFlags.cs @@ -2,6 +2,6 @@ { public static class FeatureFlags { - public const string EnableSubsidiaryValidation = "EnableSubsidiaryValidation"; + public const string EnableSubsidiaryValidationPom = "EnableSubsidiaryValidationPom"; } } diff --git a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj index eda8453..a951d38 100644 --- a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj +++ b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj @@ -29,4 +29,8 @@ + + + + \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index 654118d..79b10d6 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -83,7 +83,7 @@ public async Task ValidateAsync(Producer producer) producerValidationOutRequest.ValidationErrors.AddRange(errors); producerValidationOutRequest.ValidationWarnings.AddRange(warnings); - if (await _featureManager.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidation)) + if (await _featureManager.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)) { List subValidationResult = await ValidateSubsidiaryAsync(producer.Rows); producerValidationOutRequest.ValidationErrors.AddRange(subValidationResult.Take(remainingErrorCapacity - errors.Count)); @@ -125,12 +125,6 @@ private SubsidiaryDetailsRequest BuildSubsidiaryRequest(List rows) private async Task FetchSubsidiaryDetailsAsync(SubsidiaryDetailsRequest request) => await _companyDetailsApiClient.GetSubsidiaryDetails(request); - private SubsidiaryOrganisationDetail? FindMatchingOrganisation(ProducerRow row, SubsidiaryDetailsResponse response) => - response.SubsidiaryOrganisationDetails.FirstOrDefault(org => org.OrganisationReference == row.ProducerId); - - private SubsidiaryDetail? FindMatchingSubsidiary(ProducerRow row, SubsidiaryOrganisationDetail org) => - org.SubsidiaryDetails.FirstOrDefault(sub => sub.ReferenceNumber == row.SubsidiaryId); - private void LogRequestError(HttpRequestException exception) => _logger.LogError(exception, "Error during subsidiary validation."); } \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.FunctionApp/settings.json b/src/EPR.ProducerContentValidation.FunctionApp/settings.json index 9d0d533..d89bf2a 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/settings.json +++ b/src/EPR.ProducerContentValidation.FunctionApp/settings.json @@ -13,6 +13,6 @@ "Validation:MaxIssuesToProcess": 1000, "Redis:ConnectionString": "https://localhost:1234", "Validation:IsLatest": false, - "FeatureManagement:EnableSubsidiaryValidation": false + "FeatureManagement:EnableSubsidiaryValidationPom": false } } From eafe6d1afee015037f8030c9c72e155891ac85ca Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 11:48:51 +0000 Subject: [PATCH 14/44] Added more tests --- .../Performance/ValidatorsPerformanceTests.cs | 2 +- .../Services/Helpers/FindMatchingProducerTests.cs | 1 + .../Services/Helpers/ProducerValidationEventFormatterTests.cs | 1 + .../Services/Helpers/SubsidiaryValidationEvaluatorTests.cs | 1 + .../Helpers/ValidationServiceProducerRowValidatorTests.cs | 1 + .../Services/ValidationServiceTests.cs | 2 +- .../ConfigureServices.cs | 1 + .../EPR.ProducerContentValidation.Application.csproj | 4 ---- .../Services/Helpers/FindMatchingProducer.cs | 1 + .../Helpers/{ => Interfaces}/IFindMatchingProducer.cs | 2 +- .../Services/Helpers/{ => Interfaces}/IOrganisationMatcher.cs | 2 +- .../IProducerValidationEventIssueRequestFormatter.cs | 2 +- .../Services/Helpers/{ => Interfaces}/IRequestValidator.cs | 2 +- .../Services/Helpers/{ => Interfaces}/ISubsidiaryMatcher.cs | 2 +- .../{ => Interfaces}/ISubsidiaryValidationEvaluator.cs | 2 +- .../IValidationServiceProducerRowValidator.cs | 2 +- .../Services/Helpers/OrganisationMatcher.cs | 1 + .../Helpers/ProducerValidationEventIssueRequestFormatter.cs | 1 + .../Services/Helpers/RequestValidator.cs | 3 ++- .../Services/Helpers/SubsidiaryMatcher.cs | 1 + .../Services/Helpers/SubsidiaryValidationEvaluator.cs | 1 + .../Services/Helpers/ValidationServiceProducerRowValidator.cs | 1 + .../Services/ValidationService.cs | 2 +- 23 files changed, 23 insertions(+), 15 deletions(-) rename src/EPR.ProducerContentValidation.Application/Services/Helpers/{ => Interfaces}/IFindMatchingProducer.cs (96%) rename src/EPR.ProducerContentValidation.Application/Services/Helpers/{ => Interfaces}/IOrganisationMatcher.cs (95%) rename src/EPR.ProducerContentValidation.Application/Services/Helpers/{ => Interfaces}/IProducerValidationEventIssueRequestFormatter.cs (95%) rename src/EPR.ProducerContentValidation.Application/Services/Helpers/{ => Interfaces}/IRequestValidator.cs (93%) rename src/EPR.ProducerContentValidation.Application/Services/Helpers/{ => Interfaces}/ISubsidiaryMatcher.cs (95%) rename src/EPR.ProducerContentValidation.Application/Services/Helpers/{ => Interfaces}/ISubsidiaryValidationEvaluator.cs (96%) rename src/EPR.ProducerContentValidation.Application/Services/Helpers/{ => Interfaces}/IValidationServiceProducerRowValidator.cs (96%) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs index b44832e..eaad95b 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Performance/ValidatorsPerformanceTests.cs @@ -7,7 +7,7 @@ using EPR.ProducerContentValidation.Application.Profiles; using EPR.ProducerContentValidation.Application.ReferenceData; using EPR.ProducerContentValidation.Application.Services; -using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs index 51ef897..c392c06 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs @@ -1,6 +1,7 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs index 45ddfa1..45a6b4a 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs @@ -1,5 +1,6 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs index ca7abc2..75ea1cc 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs @@ -2,6 +2,7 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using Microsoft.Extensions.Logging; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs index ecf39a0..88d7f9a 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs @@ -1,6 +1,7 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 56138f1..1d96497 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -6,7 +6,7 @@ using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Profiles; using EPR.ProducerContentValidation.Application.Services; -using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; diff --git a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs index a6b7767..352e80d 100644 --- a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs +++ b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs @@ -5,6 +5,7 @@ using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Services; using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators; diff --git a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj index a951d38..eda8453 100644 --- a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj +++ b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj @@ -29,8 +29,4 @@ - - - - \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs index e8814b0..dcb12fb 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs @@ -1,5 +1,6 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IFindMatchingProducer.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs similarity index 96% rename from src/EPR.ProducerContentValidation.Application/Services/Helpers/IFindMatchingProducer.cs rename to src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs index 6b8040a..e27f943 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IFindMatchingProducer.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs @@ -2,7 +2,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Data.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { public interface IFindMatchingProducer { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IOrganisationMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs similarity index 95% rename from src/EPR.ProducerContentValidation.Application/Services/Helpers/IOrganisationMatcher.cs rename to src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs index e990a26..ba25656 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IOrganisationMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs @@ -1,7 +1,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Data.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { public interface IOrganisationMatcher { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IProducerValidationEventIssueRequestFormatter.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IProducerValidationEventIssueRequestFormatter.cs similarity index 95% rename from src/EPR.ProducerContentValidation.Application/Services/Helpers/IProducerValidationEventIssueRequestFormatter.cs rename to src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IProducerValidationEventIssueRequestFormatter.cs index b196450..cef13c5 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IProducerValidationEventIssueRequestFormatter.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IProducerValidationEventIssueRequestFormatter.cs @@ -1,7 +1,7 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { public interface IProducerValidationEventIssueRequestFormatter { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IRequestValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs similarity index 93% rename from src/EPR.ProducerContentValidation.Application/Services/Helpers/IRequestValidator.cs rename to src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs index 4e54b82..321a86f 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IRequestValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs @@ -1,6 +1,6 @@ using EPR.ProducerContentValidation.Data.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { public interface IRequestValidator { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs similarity index 95% rename from src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryMatcher.cs rename to src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs index 5f3b696..8e97c6d 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs @@ -1,7 +1,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Data.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { public interface ISubsidiaryMatcher { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs similarity index 96% rename from src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryValidationEvaluator.cs rename to src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs index 0d19fe0..2979b17 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ISubsidiaryValidationEvaluator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs @@ -2,7 +2,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Data.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { public interface ISubsidiaryValidationEvaluator { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs similarity index 96% rename from src/EPR.ProducerContentValidation.Application/Services/Helpers/IValidationServiceProducerRowValidator.cs rename to src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs index 2ed81ec..8793799 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/IValidationServiceProducerRowValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs @@ -2,7 +2,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Data.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { public interface IValidationServiceProducerRowValidator { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs index 036b944..02192da 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs @@ -1,4 +1,5 @@ using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs index 52c6b53..52e56da 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs @@ -1,5 +1,6 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; namespace EPR.ProducerContentValidation.Application.Services.Helpers { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs index 8fe3cb8..a0db7c9 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs @@ -1,4 +1,5 @@ -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; +using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs index 88935f4..7137043 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs @@ -1,4 +1,5 @@ using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs index af22a83..15e2000 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs @@ -1,6 +1,7 @@ using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using Microsoft.Extensions.Logging; diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs index b150b2a..7e7d95f 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs @@ -1,5 +1,6 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index 79b10d6..18525f6 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -5,7 +5,7 @@ using EPR.ProducerContentValidation.Application.Extensions; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; -using EPR.ProducerContentValidation.Application.Services.Helpers; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; From d3f232b322fa45715fbf62e3f215b2b86b379ac8 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 12:51:21 +0000 Subject: [PATCH 15/44] Edited gitignore to remove local.settings 18.json --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index b72df34..d342c2f 100644 --- a/.gitignore +++ b/.gitignore @@ -414,4 +414,3 @@ FodyWeavers.xsd # AppSettings Development file **/appSettings.Development.json /src/EPR.ProducerContentValidation.FunctionApp/localSettings.json -/src/EPR.ProducerContentValidation.FunctionApp/local.settings 18.json From 0ed65b4822e5667c9bb8cfc024abbea97d1c5c32 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 13:33:28 +0000 Subject: [PATCH 16/44] Added more tests --- .../CompanyDetailsDataItemTests.cs | 82 +++++++++++++++++++ ...cerContentValidation.Data.UnitTests.csproj | 22 +++++ src/EPR.ProducerContentValidation.sln | 8 +- 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs create mode 100644 src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj diff --git a/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs b/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs new file mode 100644 index 0000000..a81b851 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs @@ -0,0 +1,82 @@ +using EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json; + +namespace EPR.ProducerContentValidation.Data.UnitTests +{ + [TestClass] + public class CompanyDetailsDataItemTests + { + [TestMethod] + public void SerializeCompanyDetailsDataItem_ToJson_ContainsCorrectJsonPropertyNames() + { + // Arrange + var companyDetails = new CompanyDetailsDataItem + { + ReferenceNumber = "REF123", + CompaniesHouseNumber = "CHN456" + }; + + // Act + var json = JsonConvert.SerializeObject(companyDetails); + + // Assert + Assert.IsTrue(json.Contains("\"RN\":\"REF123\""), "Serialized JSON should contain 'RN' with correct value."); + Assert.IsTrue(json.Contains("\"CHN\":\"CHN456\""), "Serialized JSON should contain 'CHN' with correct value."); + } + + [TestMethod] + public void DeserializeCompanyDetailsDataItem_FromJson_HasCorrectPropertyValues() + { + // Arrange + var json = "{\"RN\":\"REF123\", \"CHN\":\"CHN456\"}"; + + // Act + var companyDetails = JsonConvert.DeserializeObject(json); + + // Assert + Assert.IsNotNull(companyDetails, "Deserialized object should not be null."); + Assert.AreEqual("REF123", companyDetails.ReferenceNumber, "ReferenceNumber should match the JSON value."); + Assert.AreEqual("CHN456", companyDetails.CompaniesHouseNumber, "CompaniesHouseNumber should match the JSON value."); + } + + [TestMethod] + public void SerializeCompanyDetailsDataItem_NullValues_HasNullJsonProperties() + { + // Arrange + var companyDetails = new CompanyDetailsDataItem + { + ReferenceNumber = null, + CompaniesHouseNumber = null + }; + + // Act + var json = JsonConvert.SerializeObject(companyDetails); + + // Assert + Assert.IsTrue(json.Contains("\"RN\":null"), "Serialized JSON should contain 'RN' with a null value."); + Assert.IsTrue(json.Contains("\"CHN\":null"), "Serialized JSON should contain 'CHN' with a null value."); + } + + [TestMethod] + public void DeserializeCompanyDetailsDataItem_NullOrMissingValues_PropertiesAreNull() + { + // Arrange + var jsonWithNulls = "{\"RN\":null, \"CHN\":null}"; + var jsonWithoutKeys = "{}"; + + // Act + var companyDetailsWithNulls = JsonConvert.DeserializeObject(jsonWithNulls); + var companyDetailsWithoutKeys = JsonConvert.DeserializeObject(jsonWithoutKeys); + + // Assert + Assert.IsNotNull(companyDetailsWithNulls, "Deserialized object with nulls should not be null."); + Assert.IsNull(companyDetailsWithNulls.ReferenceNumber, "ReferenceNumber should be null if JSON contains null."); + Assert.IsNull(companyDetailsWithNulls.CompaniesHouseNumber, "CompaniesHouseNumber should be null if JSON contains null."); + + Assert.IsNotNull(companyDetailsWithoutKeys, "Deserialized object without keys should not be null."); + Assert.IsNull(companyDetailsWithoutKeys.ReferenceNumber, "ReferenceNumber should be null if JSON key is missing."); + Assert.IsNull(companyDetailsWithoutKeys.CompaniesHouseNumber, "CompaniesHouseNumber should be null if JSON key is missing."); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj b/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj new file mode 100644 index 0000000..72dda96 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj @@ -0,0 +1,22 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + + + + diff --git a/src/EPR.ProducerContentValidation.sln b/src/EPR.ProducerContentValidation.sln index ad67399..6fb7ebb 100644 --- a/src/EPR.ProducerContentValidation.sln +++ b/src/EPR.ProducerContentValidation.sln @@ -24,7 +24,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.Data", "EPR.ProducerContentValidation.Data\EPR.ProducerContentValidation.Data.csproj", "{0944BDFE-6DD0-48E0-8A08-A36203138D43}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.UnitTest", "EPR.ProducerContentValidation.UnitTest\EPR.ProducerContentValidation.UnitTest.csproj", "{C22C5FE6-1839-4026-B7F3-ECD78154445E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.UnitTest", "EPR.ProducerContentValidation.UnitTest\EPR.ProducerContentValidation.UnitTest.csproj", "{C22C5FE6-1839-4026-B7F3-ECD78154445E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.Data.UnitTests", "EPR.ProducerContentValidation.Data.UnitTests\EPR.ProducerContentValidation.Data.UnitTests.csproj", "{F3E90F69-1835-460D-ACCA-890229303A0E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -60,6 +62,10 @@ Global {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Debug|Any CPU.Build.0 = Debug|Any CPU {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Release|Any CPU.ActiveCfg = Release|Any CPU {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Release|Any CPU.Build.0 = Release|Any CPU + {F3E90F69-1835-460D-ACCA-890229303A0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F3E90F69-1835-460D-ACCA-890229303A0E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F3E90F69-1835-460D-ACCA-890229303A0E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F3E90F69-1835-460D-ACCA-890229303A0E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 2fe906308e8620256188ae398b9b198a67c3465a Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 15:42:03 +0000 Subject: [PATCH 17/44] Added more tests --- .../EPR.ProducerContentValidation.Data.UnitTests.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj b/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj index 72dda96..ae6b92c 100644 --- a/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj +++ b/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj @@ -9,10 +9,10 @@ - + - + From dded9ac906a75e241be5457f95247d79f3821ef0 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 17:15:22 +0000 Subject: [PATCH 18/44] Added more tests --- .../Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename src/{EPR.ProducerContentValidation.UnitTest => EPR.ProducerContentValidation.Application.UnitTests}/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs (98%) diff --git a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs similarity index 98% rename from src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs rename to src/EPR.ProducerContentValidation.Application.UnitTests/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs index 3041710..f8f82d6 100644 --- a/src/EPR.ProducerContentValidation.UnitTest/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs @@ -1,7 +1,8 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Services.Subsidiary; +using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace EPR.ProducerContentValidation.UnitTest.Services.Subsidiary +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Subsidiary { [TestClass] public class SubsidiaryDetailsRequestBuilderTests From a5d0788e7bd207c25825cad6702eeb55384dddda Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Wed, 30 Oct 2024 17:41:49 +0000 Subject: [PATCH 19/44] Excluded CompanyDetailsDataItem and CompanyDetailsDataResult from coverage --- .../Models/CompanyDetailsApi/CompanyDetailsDataItem.cs | 2 ++ .../Models/CompanyDetailsApi/CompanyDetailsDataResult.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs index 81a58ee..9d0fe95 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs +++ b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs @@ -1,7 +1,9 @@ namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; +[ExcludeFromCodeCoverage] public class CompanyDetailsDataItem { [JsonProperty("RN")] diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs index 25a585e..9b57696 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs +++ b/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs @@ -1,7 +1,9 @@ namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; +[ExcludeFromCodeCoverage] public class CompanyDetailsDataResult { [JsonProperty(nameof(Organisations))] From ca9429de34265579a3b6db6feabccb614a4d53b2 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Thu, 31 Oct 2024 09:13:46 +0000 Subject: [PATCH 20/44] Added more tests --- .../Clients/CompanyDetailsApiClientTests.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs index 5a4431e..fb0f622 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs @@ -106,5 +106,45 @@ public async Task GetSubsidiaryDetails_WhenSendAsyncNotSuccessful_ThrowsError(Ht // Assert await act.Should().ThrowAsync(); } + + [TestMethod] + public async Task GetSubsidiaryDetails_ShouldReturnDefault_WhenResponseContentIsEmpty() + { + // Arrange + var request = new SubsidiaryDetailsRequest(); + var handlerMock = new Mock(MockBehavior.Strict); + handlerMock + .Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(string.Empty), // Simulate empty content + }) + .Verifiable(); + + var httpClient = new HttpClient(handlerMock.Object) + { + BaseAddress = new Uri(_config.BaseUrl), + Timeout = TimeSpan.FromSeconds(_config.Timeout), + }; + var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); + + // Act + var result = await sut.GetSubsidiaryDetails(request); + + // Assert + result.Should().BeNull(); // Since default for reference type is null + handlerMock.Protected().Verify( + "SendAsync", + Times.Once(), + ItExpr.Is(req => + req.Method == HttpMethod.Post && + req.RequestUri.ToString().EndsWith("api/subsidiary-details")), + ItExpr.IsAny()); + } } } From f609d7dec937f6ea089d5a5f502987d787290704 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Thu, 31 Oct 2024 10:53:37 +0000 Subject: [PATCH 21/44] Made changes to reflect changes that came out of QA of User Story 448425 --- .../SubsidiaryValidationEvaluatorTests.cs | 16 +++------------- .../Services/ValidationServiceTests.cs | 2 +- .../Helpers/SubsidiaryValidationEvaluator.cs | 2 +- .../Models/Subsidiary/SubsidiaryDetail.cs | 2 +- 4 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs index 75ea1cc..b443b0a 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs @@ -47,7 +47,7 @@ public void EvaluateSubsidiaryValidation_SubsidiaryDoesNotExist_ShouldLogWarning QuantityKg = "100", QuantityUnits = "Units" }; - var subsidiary = new SubsidiaryDetail { SubsidiaryExists = false, SubsidiaryBelongsToOrganisation = true }; + var subsidiary = new SubsidiaryDetail { SubsidiaryExists = false, SubsidiaryBelongsToAnyOtherOrganisation = true }; var expectedRequest = new ProducerValidationEventIssueRequest( row.SubsidiaryId, row.DataSubmissionPeriod, @@ -74,14 +74,6 @@ public void EvaluateSubsidiaryValidation_SubsidiaryDoesNotExist_ShouldLogWarning Assert.IsNotNull(result); Assert.AreEqual(expectedRequest, result); - // _mockLogger.Verify( - // l => l.LogWarning( - // It.Is(s => s == "Validation Warning at row {RowNumber}: {Message} (ErrorCode: {ErrorCode})"), - // It.Is(o => - // (int)o[0] == row.RowNumber + 1 && - // (string)o[1] == "Subsidiary ID does not exist" && - // (string)o[2] == ErrorCode.SubsidiaryIdDoesNotExist)), - // Times.Once); _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdDoesNotExist), Times.Once); } @@ -106,7 +98,7 @@ public void EvaluateSubsidiaryValidation_SubsidiaryBelongsToDifferentOrganisatio QuantityKg = "100", QuantityUnits = "Units" }; - var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToOrganisation = false }; + var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToAnyOtherOrganisation = true }; var expectedRequest = new ProducerValidationEventIssueRequest( row.SubsidiaryId, row.DataSubmissionPeriod, @@ -133,7 +125,6 @@ public void EvaluateSubsidiaryValidation_SubsidiaryBelongsToDifferentOrganisatio Assert.IsNotNull(result); Assert.AreEqual(expectedRequest, result); - // _mockLogger.Verify(l => l.LogWarning(It.IsAny(), row.RowNumber + 1, "Subsidiary ID is assigned to a different organisation", ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation), Times.Once); _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation), Times.Once); } @@ -158,7 +149,7 @@ public void EvaluateSubsidiaryValidation_SubsidiaryIsValid_ShouldReturnNull() QuantityKg = "100", QuantityUnits = "Units" }; - var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToOrganisation = true }; + var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToAnyOtherOrganisation = false }; // Act var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); @@ -166,7 +157,6 @@ public void EvaluateSubsidiaryValidation_SubsidiaryIsValid_ShouldReturnNull() // Assert Assert.IsNull(result); - // _mockLogger.Verify(l => l.LogWarning(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); _mockFormatter.Verify(f => f.Format(It.IsAny(), It.IsAny()), Times.Never); } } diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 1d96497..686ec25 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -119,7 +119,7 @@ public async Task ValidateSubsidiary_SuccessfulValidation_ReturnsEmptyList() { ReferenceNumber = "SubRef", SubsidiaryExists = true, - SubsidiaryBelongsToOrganisation = true + SubsidiaryBelongsToAnyOtherOrganisation = true } } } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs index 15e2000..026fae2 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs @@ -26,7 +26,7 @@ public SubsidiaryValidationEvaluator(ILogger logger, IProducerValidationEventIss return _producerValidationEventIssueRequestFormatter.Format(row, ErrorCode.SubsidiaryIdDoesNotExist); } - if (!subsidiary.SubsidiaryBelongsToOrganisation) + if (subsidiary.SubsidiaryBelongsToAnyOtherOrganisation) { LogValidationWarning(rowIndex + 1, "Subsidiary ID is assigned to a different organisation", ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); return _producerValidationEventIssueRequestFormatter.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs index cb92f85..3ab3452 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs +++ b/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs @@ -9,6 +9,6 @@ public class SubsidiaryDetail public bool SubsidiaryExists { get; set; } - public bool SubsidiaryBelongsToOrganisation { get; set; } + public bool SubsidiaryBelongsToAnyOtherOrganisation { get; set; } } } From c0ef4bcabc8d769bb2669fe15bf20ab562b69127 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Thu, 31 Oct 2024 14:41:27 +0000 Subject: [PATCH 22/44] Made changes to merge the errorcodes for same producer into one collection --- ...rValidationEventIssueRequestMergerTests.cs | 270 ++++++++++++++++++ .../Services/ValidationServiceTests.cs | 125 ++++++++ ...oducerValidationEventIssueRequestMerger.cs | 56 ++++ .../Services/ValidationService.cs | 16 +- 4 files changed, 464 insertions(+), 3 deletions(-) create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventIssueRequestMergerTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestMerger.cs diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventIssueRequestMergerTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventIssueRequestMergerTests.cs new file mode 100644 index 0000000..89324b4 --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventIssueRequestMergerTests.cs @@ -0,0 +1,270 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; +using EPR.ProducerContentValidation.Application.Services.Helpers; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +{ + [TestClass] + public class ProducerValidationEventIssueRequestMergerTests + { + [TestMethod] + public void MergeRequests_IdenticalEntries_ShouldMergeErrorCodes() + { + // Arrange + var request1 = new ProducerValidationEventIssueRequest( + "123", + "2024-01", + 1, + "Producer1", + "TypeA", + "Large", + "WasteType", + "CategoryA", + "MaterialX", + "SubTypeX", + "Nation1", + "Nation2", + "100", + "Units", + ErrorCodes: new List { "Error1" }); + var request2 = new ProducerValidationEventIssueRequest( + "123", + "2024-01", + 1, + "Producer1", + "TypeA", + "Large", + "WasteType", + "CategoryA", + "MaterialX", + "SubTypeX", + "Nation1", + "Nation2", + "100", + "Units", + ErrorCodes: new List { "Error2" }); + + var list1 = new List { request1 }; + var list2 = new List { request2 }; + + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + + // Assert + result.Should().HaveCount(1); + result[0].ErrorCodes.Should().BeEquivalentTo(new List { "Error1", "Error2" }); + } + + [TestMethod] + public void MergeRequests_UniqueEntries_ShouldRetainBothEntries() + { + // Arrange + var request1 = new ProducerValidationEventIssueRequest( + "123", + "2024-01", + 1, + "Producer1", + "TypeA", + "Large", + "WasteType", + "CategoryA", + "MaterialX", + "SubTypeX", + "Nation1", + "Nation2", + "100", + "Units", + ErrorCodes: new List { "Error1" }); + var request2 = new ProducerValidationEventIssueRequest( + "456", + "2024-02", + 2, + "Producer2", + "TypeB", + "Medium", + "WasteType", + "CategoryB", + "MaterialY", + "SubTypeY", + "Nation3", + "Nation4", + "200", + "Units", + ErrorCodes: new List { "Error3" }); + + var list1 = new List { request1 }; + var list2 = new List { request2 }; + + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + + // Assert + result.Should().HaveCount(2); + result.Should().ContainEquivalentOf(request1); + result.Should().ContainEquivalentOf(request2); + } + + [TestMethod] + public void MergeRequests_MixedEntries_ShouldMergeIdenticalAndRetainUnique() + { + // Arrange + var request1 = new ProducerValidationEventIssueRequest( + SubsidiaryId: "123", + DataSubmissionPeriod: "2024-01", + RowNumber: 1, + ProducerId: "Producer1", + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "WasteType", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubTypeX", + FromHomeNation: "Nation1", + ToHomeNation: "Nation2", + QuantityKg: "100", + QuantityUnits: "Units", + ErrorCodes: new List { "Error1" }); + + var request2 = new ProducerValidationEventIssueRequest( + SubsidiaryId: "123", + DataSubmissionPeriod: "2024-01", + RowNumber: 1, + ProducerId: "Producer1", + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "WasteType", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubTypeX", + FromHomeNation: "Nation1", + ToHomeNation: "Nation2", + QuantityKg: "100", + QuantityUnits: "Units", + ErrorCodes: new List { "Error2" }); + + var uniqueRequest = new ProducerValidationEventIssueRequest( + SubsidiaryId: "789", + DataSubmissionPeriod: "2024-03", + RowNumber: 3, + ProducerId: "Producer3", + ProducerType: "TypeC", + ProducerSize: "Small", + WasteType: "WasteType", + PackagingCategory: "CategoryC", + MaterialType: "MaterialZ", + MaterialSubType: "SubTypeZ", + FromHomeNation: "Nation5", + ToHomeNation: "Nation6", + QuantityKg: "300", + QuantityUnits: "Units", + ErrorCodes: new List { "Error4" }); + + var list1 = new List { request1, uniqueRequest }; + var list2 = new List { request2 }; + + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + + // Assert + result.Should().HaveCount(2); + result.Should().ContainSingle(r => r.SubsidiaryId == "123" && r.ErrorCodes.Contains("Error1") && r.ErrorCodes.Contains("Error2")); + result.Should().ContainEquivalentOf(uniqueRequest); + } + + [TestMethod] + public void MergeRequests_EmptyList_ShouldReturnOtherList() + { + // Arrange + var request = new ProducerValidationEventIssueRequest( + SubsidiaryId: "123", + DataSubmissionPeriod: "2024-01", + RowNumber: 1, + ProducerId: "Producer1", + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "WasteType", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubTypeX", + FromHomeNation: "Nation1", + ToHomeNation: "Nation2", + QuantityKg: "100", + QuantityUnits: "Units", + ErrorCodes: new List { "Error1" }); + + var list1 = new List { request }; + var list2 = new List(); + + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + + // Assert + result.Should().HaveCount(1); + result.Should().ContainEquivalentOf(request); + } + + [TestMethod] + public void MergeRequests_BothEmpty_ShouldReturnEmpty() + { + // Arrange + var list1 = new List(); + var list2 = new List(); + + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + + // Assert + result.Should().BeEmpty(); + } + + [TestMethod] + public void MergeRequests_NullErrorCodes_ShouldHandleGracefully() + { + // Arrange + var request1 = new ProducerValidationEventIssueRequest( + SubsidiaryId: "123", + DataSubmissionPeriod: "2024-01", + RowNumber: 1, + ProducerId: "Producer1", + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "WasteType", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubTypeX", + FromHomeNation: "Nation1", + ToHomeNation: "Nation2", + QuantityKg: "100", + QuantityUnits: "Units", + ErrorCodes: null); + + var request2 = new ProducerValidationEventIssueRequest( + SubsidiaryId: "123", + DataSubmissionPeriod: "2024-01", + RowNumber: 1, + ProducerId: "Producer1", + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "WasteType", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubTypeX", + FromHomeNation: "Nation1", + ToHomeNation: "Nation2", + QuantityKg: "100", + QuantityUnits: "Units", + ErrorCodes: new List { "Error2" }); + + var list1 = new List { request1 }; + var list2 = new List { request2 }; + + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + + // Assert + result.Should().HaveCount(1); + result[0].ErrorCodes.Should().BeEquivalentTo(new List { "Error2" }); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 686ec25..38dcab1 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -412,6 +412,131 @@ public async Task ValidateAsync_WhenWarningCapacityReached_LogsWarning() Assert.AreEqual(0, result.ValidationWarnings.Count); } + [TestMethod] + public async Task ValidateAsync_CollectsWarningsAndValidatesSubsidiaries_LimitedByErrorCapacity() + { + // Arrange + var producerRows = new List + { + ModelGenerator.CreateProducerRow(1), + ModelGenerator.CreateProducerRow(2) + }; + + var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); + + var expectedErrors = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Error1" }) + }; + + var expectedWarnings = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Warning1" }) + }; + + // Mocking + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + + _compositeValidatorMock.Setup(x => x.ValidateAndFetchForIssuesAsync(It.IsAny>(), It.IsAny>(), It.IsAny>(), BlobName)) + .Callback, List, List, string>((rows, errors, warnings, blob) => + { + warnings.AddRange(expectedWarnings); + errors.AddRange(expectedErrors); + }); + + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)).ReturnsAsync(true); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(ErrorStoreKey)).ReturnsAsync(10); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(WarningStoreKey)).ReturnsAsync(5); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + result.ValidationWarnings.Should().BeEquivalentTo(expectedWarnings); + result.ValidationErrors.Should().BeEquivalentTo(expectedErrors.Take(5)); // Limited by error capacity + } + + [TestMethod] + public async Task ValidateAsync_EnabledSubsidiaryValidation_NoErrorsFromSubsidiaryValidation_AggregatesErrors() + { + // Arrange + var producerRows = new List + { + ModelGenerator.CreateProducerRow(1) + }; + + var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); + + var expectedErrors = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Error1" }) + }; + + // Mocking + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + + _compositeValidatorMock.Setup(x => x.ValidateAndFetchForIssuesAsync(It.IsAny>(), It.IsAny>(), It.IsAny>(), BlobName)) + .Callback, List, List, string>((rows, errors, warnings, blob) => + { + // No warnings + errors.Add(new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Error1" })); + }); + + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)).ReturnsAsync(true); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + result.ValidationWarnings.Should().BeEmpty(); + result.ValidationErrors.Should().BeEquivalentTo(expectedErrors); + } + + [TestMethod] + public async Task ValidateAsync_DisabledSubsidiaryValidation_DoesNotValidateSubsidiaries() + { + // Arrange + var producerRows = new List + { + ModelGenerator.CreateProducerRow(1) + }; + + var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); + + var expectedErrors = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Error1" }) + }; + + // Mocking + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)).ReturnsAsync(false); + + _compositeValidatorMock.Setup(x => x.ValidateAndFetchForIssuesAsync(It.IsAny>(), It.IsAny>(), It.IsAny>(), BlobName)) + .Callback, List, List, string>((rows, errors, warnings, blob) => + { + errors.AddRange(expectedErrors); + }); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + result.ValidationWarnings.Should().BeEmpty(); + result.ValidationErrors.Should().BeEquivalentTo(expectedErrors); + _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(It.IsAny>()), Times.Never); + _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Never); + } + private ValidationService CreateSystemUnderTest() => new( _loggerMock.Object, diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestMerger.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestMerger.cs new file mode 100644 index 0000000..54e928b --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestMerger.cs @@ -0,0 +1,56 @@ +using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; + +namespace EPR.ProducerContentValidation.Application.Services.Helpers +{ + public static class ProducerValidationEventIssueRequestMerger + { + public static List MergeRequests( + List list1, + List list2) + { + // Combine both lists + var combinedList = list1.Concat(list2); + + // Use a dictionary to group and merge ErrorCodes for identical records + var mergedDict = new Dictionary<(string, string, int, string, string, string, string, string, string, string, string, string, string, string, string), ProducerValidationEventIssueRequest>(); + + foreach (var request in combinedList) + { + var key = ( + request.SubsidiaryId, + request.DataSubmissionPeriod, + request.RowNumber, + request.ProducerId, + request.ProducerType, + request.ProducerSize, + request.WasteType, + request.PackagingCategory, + request.MaterialType, + request.MaterialSubType, + request.FromHomeNation, + request.ToHomeNation, + request.QuantityKg, + request.QuantityUnits, + request.BlobName); + + if (mergedDict.TryGetValue(key, out var existingRequest)) + { + // Merge ErrorCodes if they exist + var mergedErrorCodes = existingRequest.ErrorCodes?.Union(request.ErrorCodes ?? new List()).ToList() + ?? request.ErrorCodes ?? new List(); + + // Update the dictionary with the merged ErrorCodes + mergedDict[key] = existingRequest with { ErrorCodes = mergedErrorCodes }; + } + else + { + // Add the request to the dictionary if it doesn't exist + mergedDict[key] = request; + } + } + + // Return the merged list + return mergedDict.Values.ToList(); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index 18525f6..a231601 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -5,6 +5,7 @@ using EPR.ProducerContentValidation.Application.Extensions; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; +using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; @@ -76,17 +77,26 @@ public async Task ValidateAsync(Producer producer) var errors = new List(); var warnings = new List(); + var subValidationResult = new List(); await _compositeValidator.ValidateAndFetchForIssuesAsync(producer.Rows, errors, warnings, producer.BlobName); await _compositeValidator.ValidateDuplicatesAndGroupedData(producer.Rows, errors, warnings, producer.BlobName); - producerValidationOutRequest.ValidationErrors.AddRange(errors); producerValidationOutRequest.ValidationWarnings.AddRange(warnings); if (await _featureManager.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)) { - List subValidationResult = await ValidateSubsidiaryAsync(producer.Rows); - producerValidationOutRequest.ValidationErrors.AddRange(subValidationResult.Take(remainingErrorCapacity - errors.Count)); + subValidationResult = await ValidateSubsidiaryAsync(producer.Rows); + } + + if (subValidationResult.Count > 0) + { + var subValidationResultLimitedToRemainingErrorCapacity = subValidationResult.Take(remainingErrorCapacity - errors.Count); + ProducerValidationEventIssueRequestMerger.MergeRequests(errors, (List)subValidationResultLimitedToRemainingErrorCapacity); + } + else + { + producerValidationOutRequest.ValidationErrors.AddRange(errors); } _logger.LogExit(); From c88e99148819fa56642b8835ad2c5bbfd8e254df Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Thu, 31 Oct 2024 15:42:06 +0000 Subject: [PATCH 23/44] Made changes to merge the errorcodes for same producer into one collection --- .../Services/ValidationServiceTests.cs | 45 +++++++++++++++++++ .../Services/ValidationService.cs | 4 +- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 38dcab1..ebb2e75 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -498,6 +498,51 @@ public async Task ValidateAsync_EnabledSubsidiaryValidation_NoErrorsFromSubsidia result.ValidationErrors.Should().BeEquivalentTo(expectedErrors); } + [TestMethod] + public async Task ValidateAsync_EnabledSubsidiaryValidation_ErrorsFromSubsidiaryValidation_AggregatesErrors() + { + // Arrange + var producerRows = new List + { + ModelGenerator.CreateProducerRow(1) + }; + + var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); + + var expectedErrors = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Error1" }) + }; + var validationErrors = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", ErrorCodes: new List { "Error1" }) + }; + + _validationServiceProducerRowValidatorMock.Setup(x => x.ProcessRowsForValidationErrors(It.IsAny>(), It.IsAny())).Returns(validationErrors); + + // Mocking + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + + _compositeValidatorMock.Setup(x => x.ValidateAndFetchForIssuesAsync(It.IsAny>(), It.IsAny>(), It.IsAny>(), BlobName)) + .Callback, List, List, string>((rows, errors, warnings, blob) => + { + // No warnings + errors.Add(new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Error1" })); + }); + + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)).ReturnsAsync(true); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + result.ValidationWarnings.Should().BeEmpty(); + result.ValidationErrors.Count.Should().Be(2); + } + [TestMethod] public async Task ValidateAsync_DisabledSubsidiaryValidation_DoesNotValidateSubsidiaries() { diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index a231601..1f37e23 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -91,8 +91,8 @@ public async Task ValidateAsync(Producer producer) if (subValidationResult.Count > 0) { - var subValidationResultLimitedToRemainingErrorCapacity = subValidationResult.Take(remainingErrorCapacity - errors.Count); - ProducerValidationEventIssueRequestMerger.MergeRequests(errors, (List)subValidationResultLimitedToRemainingErrorCapacity); + var mergedErrors = ProducerValidationEventIssueRequestMerger.MergeRequests(errors, subValidationResult); + producerValidationOutRequest.ValidationErrors.AddRange(mergedErrors.Take(remainingErrorCapacity - errors.Count)); } else { From c1c9af31252d309c3a15bd5946bf135df9f91bcb Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 09:28:00 +0000 Subject: [PATCH 24/44] Changed FindMatchingProducerTests to use fluent validation --- .../Services/Helpers/FindMatchingProducerTests.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs index c392c06..dcf323c 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs @@ -4,6 +4,7 @@ using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -44,7 +45,7 @@ public void Match_NoMatchingOrganisation_ReturnsNull() var result = _findMatchingProducer.Match(row, response, 1); // Assert - Assert.IsNull(result); + result.Should().BeNull(); _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(It.IsAny(), It.IsAny()), Times.Never); _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); @@ -70,7 +71,7 @@ public void Match_NoMatchingSubsidiary_ReturnsNull() var result = _findMatchingProducer.Match(row, response, 1); // Assert - Assert.IsNull(result); + result.Should().BeNull(); _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(row, matchingOrg), Times.Once); _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); @@ -118,7 +119,7 @@ public void Match_MatchingOrganisationAndSubsidiary_ReturnsValidationResult() var result = _findMatchingProducer.Match(row, response, 1); // Assert - Assert.AreEqual(expectedValidationResult, result); + result.Should().Be(expectedValidationResult); _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(row, matchingOrg), Times.Once); _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(row, matchingSub, 1), Times.Once); From 2c4001f74fdf4c37a06ddf7a252d0f3f79c8790b Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 09:34:33 +0000 Subject: [PATCH 25/44] Changed FindMatchingProducerTests to use fluent validation --- .../Clients/CompanyDetailsApiClientTests.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs b/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs index 59c6c17..717a780 100644 --- a/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs +++ b/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs @@ -39,17 +39,17 @@ public async Task GetSubsidiaryDetails_ShouldReturnSubsidiaryDetailsRequest_OnSu }; var handlerMock = new Mock(MockBehavior.Strict); handlerMock - .Protected() - .Setup>( - "SendAsync", - ItExpr.IsAny(), - ItExpr.IsAny()) - .ReturnsAsync(new HttpResponseMessage() - { - StatusCode = HttpStatusCode.OK, - Content = new StringContent(content), - }) - .Verifiable(); + .Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(content), + }) + .Verifiable(); var httpClient = new HttpClient(handlerMock.Object) { BaseAddress = new Uri(_config.BaseUrl), From 01d7e1abfd0ebdc9135d147e4bca020dbae605d3 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 09:52:28 +0000 Subject: [PATCH 26/44] Changed CompanyDetailsDataItemTests.cs to use fluent validation --- .../CompanyDetailsDataItemTests.cs | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs b/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs index a81b851..6fb725f 100644 --- a/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs +++ b/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs @@ -1,4 +1,5 @@ using EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; @@ -21,8 +22,8 @@ public void SerializeCompanyDetailsDataItem_ToJson_ContainsCorrectJsonPropertyNa var json = JsonConvert.SerializeObject(companyDetails); // Assert - Assert.IsTrue(json.Contains("\"RN\":\"REF123\""), "Serialized JSON should contain 'RN' with correct value."); - Assert.IsTrue(json.Contains("\"CHN\":\"CHN456\""), "Serialized JSON should contain 'CHN' with correct value."); + json.Should().Contain("\"RN\":\"REF123\"") + .And.Contain("\"CHN\":\"CHN456\""); } [TestMethod] @@ -35,9 +36,9 @@ public void DeserializeCompanyDetailsDataItem_FromJson_HasCorrectPropertyValues( var companyDetails = JsonConvert.DeserializeObject(json); // Assert - Assert.IsNotNull(companyDetails, "Deserialized object should not be null."); - Assert.AreEqual("REF123", companyDetails.ReferenceNumber, "ReferenceNumber should match the JSON value."); - Assert.AreEqual("CHN456", companyDetails.CompaniesHouseNumber, "CompaniesHouseNumber should match the JSON value."); + companyDetails.Should().NotBeNull(); + companyDetails!.ReferenceNumber.Should().Be("REF123"); + companyDetails.CompaniesHouseNumber.Should().Be("CHN456"); } [TestMethod] @@ -54,8 +55,8 @@ public void SerializeCompanyDetailsDataItem_NullValues_HasNullJsonProperties() var json = JsonConvert.SerializeObject(companyDetails); // Assert - Assert.IsTrue(json.Contains("\"RN\":null"), "Serialized JSON should contain 'RN' with a null value."); - Assert.IsTrue(json.Contains("\"CHN\":null"), "Serialized JSON should contain 'CHN' with a null value."); + json.Should().Contain("\"RN\":null") + .And.Contain("\"CHN\":null"); } [TestMethod] @@ -70,13 +71,13 @@ public void DeserializeCompanyDetailsDataItem_NullOrMissingValues_PropertiesAreN var companyDetailsWithoutKeys = JsonConvert.DeserializeObject(jsonWithoutKeys); // Assert - Assert.IsNotNull(companyDetailsWithNulls, "Deserialized object with nulls should not be null."); - Assert.IsNull(companyDetailsWithNulls.ReferenceNumber, "ReferenceNumber should be null if JSON contains null."); - Assert.IsNull(companyDetailsWithNulls.CompaniesHouseNumber, "CompaniesHouseNumber should be null if JSON contains null."); + companyDetailsWithNulls.Should().NotBeNull(); + companyDetailsWithNulls!.ReferenceNumber.Should().BeNull(); + companyDetailsWithNulls.CompaniesHouseNumber.Should().BeNull(); - Assert.IsNotNull(companyDetailsWithoutKeys, "Deserialized object without keys should not be null."); - Assert.IsNull(companyDetailsWithoutKeys.ReferenceNumber, "ReferenceNumber should be null if JSON key is missing."); - Assert.IsNull(companyDetailsWithoutKeys.CompaniesHouseNumber, "CompaniesHouseNumber should be null if JSON key is missing."); + companyDetailsWithoutKeys.Should().NotBeNull(); + companyDetailsWithoutKeys!.ReferenceNumber.Should().BeNull(); + companyDetailsWithoutKeys.CompaniesHouseNumber.Should().BeNull(); } } } From f0c3dbf2d7cef59edabf01b48a5af208c92eb81c Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 09:58:42 +0000 Subject: [PATCH 27/44] Changed OrganisationMatcherTests to use fluent validation --- .../Services/Helpers/OrganisationMatcherTests.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs index b69492d..ad17f13 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs @@ -1,6 +1,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers @@ -50,8 +51,8 @@ public void FindMatchingOrganisation_ShouldReturnOrganisation_WhenMatchExists() var result = _organisationMatcher.FindMatchingOrganisation(row, response); // Assert - Assert.IsNotNull(result); - Assert.AreEqual("Org456", result.OrganisationReference); + result.Should().NotBeNull(); + result!.OrganisationReference.Should().Be("Org456"); } [TestMethod] @@ -89,7 +90,7 @@ public void FindMatchingOrganisation_ShouldReturnNull_WhenNoMatchExists() var result = _organisationMatcher.FindMatchingOrganisation(row, response); // Assert - Assert.IsNull(result); + result.Should().BeNull(); } [TestMethod] @@ -122,7 +123,7 @@ public void FindMatchingOrganisation_ShouldReturnNull_WhenResponseIsEmpty() var result = _organisationMatcher.FindMatchingOrganisation(row, response); // Assert - Assert.IsNull(result); + result.Should().BeNull(); } } } From 977adad25d66ac2436a8bbc11d6561c7d8dc6335 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 10:03:44 +0000 Subject: [PATCH 28/44] Changed ProducerValidationEventFormatterTests to use fluent validation --- .../ProducerValidationEventFormatterTests.cs | 69 ++++++++++--------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs index 45a6b4a..953cb31 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs @@ -1,6 +1,7 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers @@ -42,22 +43,22 @@ public void Format_ShouldReturnFormattedRequest_WithAllFieldsProvided() var result = _formatter.Format(row, errorCode); // Assert - Assert.IsNotNull(result); - Assert.AreEqual("Sub123", result.SubsidiaryId); - Assert.AreEqual("2023-Q1", result.DataSubmissionPeriod); - Assert.AreEqual(1, result.RowNumber); - Assert.AreEqual("Org456", result.ProducerId); - Assert.AreEqual("TypeA", result.ProducerType); - Assert.AreEqual("Large", result.ProducerSize); - Assert.AreEqual("Plastic", result.WasteType); - Assert.AreEqual("CategoryA", result.PackagingCategory); - Assert.AreEqual("MaterialX", result.MaterialType); - Assert.AreEqual("SubMaterialX", result.MaterialSubType); - Assert.AreEqual("UK", result.FromHomeNation); - Assert.AreEqual("Germany", result.ToHomeNation); - Assert.AreEqual("100", result.QuantityKg); - Assert.AreEqual("200", result.QuantityUnits); - CollectionAssert.Contains(result.ErrorCodes, errorCode); + result.Should().NotBeNull(); + result.SubsidiaryId.Should().Be("Sub123"); + result.DataSubmissionPeriod.Should().Be("2023-Q1"); + result.RowNumber.Should().Be(1); + result.ProducerId.Should().Be("Org456"); + result.ProducerType.Should().Be("TypeA"); + result.ProducerSize.Should().Be("Large"); + result.WasteType.Should().Be("Plastic"); + result.PackagingCategory.Should().Be("CategoryA"); + result.MaterialType.Should().Be("MaterialX"); + result.MaterialSubType.Should().Be("SubMaterialX"); + result.FromHomeNation.Should().Be("UK"); + result.ToHomeNation.Should().Be("Germany"); + result.QuantityKg.Should().Be("100"); + result.QuantityUnits.Should().Be("200"); + result.ErrorCodes.Should().Contain(errorCode); } [TestMethod] @@ -87,22 +88,22 @@ public void Format_ShouldHandleNullFields_InProducerRow() var result = _formatter.Format(row, errorCode); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(string.Empty, result.SubsidiaryId); - Assert.AreEqual(string.Empty, result.DataSubmissionPeriod); - Assert.AreEqual(1, result.RowNumber); - Assert.AreEqual(string.Empty, result.ProducerId); - Assert.AreEqual(string.Empty, result.ProducerType); - Assert.AreEqual(string.Empty, result.ProducerSize); - Assert.AreEqual(string.Empty, result.WasteType); - Assert.AreEqual(string.Empty, result.PackagingCategory); - Assert.AreEqual(string.Empty, result.MaterialType); - Assert.AreEqual(string.Empty, result.MaterialSubType); - Assert.AreEqual(string.Empty, result.FromHomeNation); - Assert.AreEqual(string.Empty, result.ToHomeNation); - Assert.AreEqual(string.Empty, result.QuantityKg); - Assert.AreEqual(string.Empty, result.QuantityUnits); - CollectionAssert.Contains(result.ErrorCodes, errorCode); + result.Should().NotBeNull(); + result.SubsidiaryId.Should().BeEmpty(); + result.DataSubmissionPeriod.Should().BeEmpty(); + result.RowNumber.Should().Be(1); + result.ProducerId.Should().BeEmpty(); + result.ProducerType.Should().BeEmpty(); + result.ProducerSize.Should().BeEmpty(); + result.WasteType.Should().BeEmpty(); + result.PackagingCategory.Should().BeEmpty(); + result.MaterialType.Should().BeEmpty(); + result.MaterialSubType.Should().BeEmpty(); + result.FromHomeNation.Should().BeEmpty(); + result.ToHomeNation.Should().BeEmpty(); + result.QuantityKg.Should().BeEmpty(); + result.QuantityUnits.Should().BeEmpty(); + result.ErrorCodes.Should().Contain(errorCode); } [TestMethod] @@ -132,8 +133,8 @@ public void Format_ShouldReturnSingleErrorCode() var result = _formatter.Format(row, errorCode); // Assert - Assert.AreEqual(1, result.ErrorCodes.Count, "Expected exactly one error code in the list."); - Assert.AreEqual("SingleError", result.ErrorCodes[0]); + result.ErrorCodes.Should().HaveCount(1, "Expected exactly one error code in the list.") + .And.ContainSingle(e => e == "SingleError"); } } } From 09aa5280812cf05a4b9092e6dd3111598fabaee6 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 10:14:13 +0000 Subject: [PATCH 29/44] Changed RequestValidatorTests to use fluent validation --- .../Services/Helpers/RequestValidatorTests.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs index 41e9a88..b47650c 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs @@ -1,5 +1,6 @@ using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers @@ -22,7 +23,7 @@ public void IsInvalidRequest_ShouldReturnTrue_WhenRequestIsNull() var result = _validator.IsInvalidRequest(null); // Assert - Assert.IsTrue(result, "Expected IsInvalidRequest to return true for null request."); + result.Should().BeTrue("because the request is null and should be considered invalid."); } [TestMethod] @@ -38,7 +39,7 @@ public void IsInvalidRequest_ShouldReturnTrue_WhenSubsidiaryOrganisationDetailsI var result = _validator.IsInvalidRequest(request); // Assert - Assert.IsTrue(result, "Expected IsInvalidRequest to return true when SubsidiaryOrganisationDetails is null."); + result.Should().BeTrue("because SubsidiaryOrganisationDetails is null and the request should be invalid."); } [TestMethod] @@ -54,7 +55,7 @@ public void IsInvalidRequest_ShouldReturnTrue_WhenSubsidiaryOrganisationDetailsI var result = _validator.IsInvalidRequest(request); // Assert - Assert.IsTrue(result, "Expected IsInvalidRequest to return true when SubsidiaryOrganisationDetails is empty."); + result.Should().BeTrue("because SubsidiaryOrganisationDetails is empty and should be considered invalid."); } [TestMethod] @@ -64,16 +65,16 @@ public void IsInvalidRequest_ShouldReturnFalse_WhenSubsidiaryOrganisationDetails var request = new SubsidiaryDetailsRequest { SubsidiaryOrganisationDetails = new List - { - new SubsidiaryOrganisationDetail { OrganisationReference = "Org1" } - } + { + new SubsidiaryOrganisationDetail { OrganisationReference = "Org1" } + } }; // Act var result = _validator.IsInvalidRequest(request); // Assert - Assert.IsFalse(result, "Expected IsInvalidRequest to return false when SubsidiaryOrganisationDetails is not empty."); + result.Should().BeFalse("because SubsidiaryOrganisationDetails contains entries and should be considered valid."); } } } From 84b52b9124289dd077be61d5ca13f5b6c3b8da71 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 10:20:37 +0000 Subject: [PATCH 30/44] Changed SubsidiaryMatcherTests to use fluent validation --- .../Services/Helpers/SubsidiaryMatcherTests.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs index 49685c9..910f4e4 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs @@ -1,6 +1,7 @@ using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers @@ -54,8 +55,8 @@ public void FindMatchingSubsidiary_ShouldReturnMatchingSubsidiary_WhenReferenceN var result = _matcher.FindMatchingSubsidiary(row, org); // Assert - Assert.IsNotNull(result); - Assert.AreEqual("123", result?.ReferenceNumber); + result.Should().NotBeNull("because there is a matching subsidiary with the reference number '123'"); + result?.ReferenceNumber.Should().Be("123", "because the reference number should match the subsidiary ID in the row."); } [TestMethod] @@ -96,7 +97,7 @@ public void FindMatchingSubsidiary_ShouldReturnNull_WhenNoMatchingReferenceNumbe var result = _matcher.FindMatchingSubsidiary(row, org); // Assert - Assert.IsNull(result); + result.Should().BeNull("because there is no matching subsidiary with the reference number '789'."); } [TestMethod] @@ -131,14 +132,15 @@ public void FindMatchingSubsidiary_ShouldReturnNull_WhenSubsidiaryDetailsIsEmpty var result = _matcher.FindMatchingSubsidiary(row, org); // Assert - Assert.IsNull(result); + result.Should().BeNull("because SubsidiaryDetails is empty and should not contain a matching subsidiary."); } [TestMethod] public void FindMatchingSubsidiary_ShouldReturnNull_WhenSubsidiaryIdIsNull() { // Arrange - var row = ModelGenerator.CreateProducerRow(1) with { + var row = ModelGenerator.CreateProducerRow(1) with + { SubsidiaryId = null, DataSubmissionPeriod = "2024Q1", ProducerId = "456", @@ -171,7 +173,7 @@ public void FindMatchingSubsidiary_ShouldReturnNull_WhenSubsidiaryIdIsNull() var result = _matcher.FindMatchingSubsidiary(row, org); // Assert - Assert.IsNull(result); + result.Should().BeNull("because the row's SubsidiaryId is null and cannot match any reference number."); } } } From c0d869763f60fe14289559f93e23f068b84c074c Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 10:26:05 +0000 Subject: [PATCH 31/44] Changed SubsidiaryValidationEvaluatorTests to use fluent validation --- .../Helpers/SubsidiaryValidationEvaluatorTests.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs index b443b0a..9be42eb 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs @@ -5,6 +5,7 @@ using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; +using FluentAssertions; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -71,8 +72,8 @@ public void EvaluateSubsidiaryValidation_SubsidiaryDoesNotExist_ShouldLogWarning var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(expectedRequest, result); + result.Should().NotBeNull("because a request should be returned if the subsidiary does not exist.") + .And.BeEquivalentTo(expectedRequest, "because the returned request should match the expected formatted request."); _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdDoesNotExist), Times.Once); } @@ -122,8 +123,8 @@ public void EvaluateSubsidiaryValidation_SubsidiaryBelongsToDifferentOrganisatio var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(expectedRequest, result); + result.Should().NotBeNull("because a request should be returned if the subsidiary belongs to a different organisation.") + .And.BeEquivalentTo(expectedRequest, "because the returned request should match the expected formatted request."); _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation), Times.Once); } @@ -155,7 +156,7 @@ public void EvaluateSubsidiaryValidation_SubsidiaryIsValid_ShouldReturnNull() var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); // Assert - Assert.IsNull(result); + result.Should().BeNull("because the subsidiary is valid and should not generate any validation issue."); _mockFormatter.Verify(f => f.Format(It.IsAny(), It.IsAny()), Times.Never); } From 878e919fb0b1674c191f9b4e92ddac590114778b Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 10:37:32 +0000 Subject: [PATCH 32/44] Changed ValidationServiceProducerRowValidatorTests to use fluent validation --- ...idationServiceProducerRowValidatorTests.cs | 143 +++++++++--------- 1 file changed, 70 insertions(+), 73 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs index 88d7f9a..6e32a08 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs @@ -4,6 +4,7 @@ using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -28,52 +29,11 @@ public void ProcessRowsForValidationErrors_NoValidationErrors_ReturnsEmptyList() // Arrange var producerRow = ModelGenerator.CreateProducerRow(1); var producerRowTwo = ModelGenerator.CreateProducerRow(2); - var producerRows = new List { producerRow, producerRowTwo }; - - var row1 = ModelGenerator.CreateProducerRow(1) with - { - SubsidiaryId = "Sub1", - DataSubmissionPeriod = "2024Q1", - ProducerId = "Prod1", - RowNumber = 1, - ProducerType = "TypeA", - ProducerSize = "Large", - WasteType = "WasteTypeA", - PackagingCategory = "CategoryA", - MaterialType = "MaterialA", - MaterialSubType = "SubTypeA", - FromHomeNation = "NationA", - ToHomeNation = "NationB", - QuantityKg = "100", - QuantityUnits = "10" - }; - - var row2 = ModelGenerator.CreateProducerRow(1) with - { - SubsidiaryId = "Sub2", - DataSubmissionPeriod = "2024Q1", - ProducerId = "Prod2", - RowNumber = 2, - ProducerType = "TypeB", - ProducerSize = "Small", - WasteType = "WasteTypeB", - PackagingCategory = "CategoryB", - MaterialType = "MaterialB", - MaterialSubType = "SubTypeB", - FromHomeNation = "NationA", - ToHomeNation = "NationB", - QuantityKg = "200", - QuantityUnits = "20" - }; - var rows = new List - { - row1, - row2 - }; + var rows = new List { producerRow, producerRowTwo }; var response = new SubsidiaryDetailsResponse { - // Initialize your response data + // Initialize response data if needed }; _mockFindMatchingProducer.Setup(x => x.Match(It.IsAny(), response, It.IsAny())).Returns((ProducerValidationEventIssueRequest)null); @@ -82,8 +42,8 @@ public void ProcessRowsForValidationErrors_NoValidationErrors_ReturnsEmptyList() var result = _validator.ProcessRowsForValidationErrors(rows, response); // Assert - Assert.IsNotNull(result); - Assert.IsFalse(result.Any()); + result.Should().NotBeNull("the result should not be null, even if it contains no errors.") + .And.BeEmpty("because there are no validation errors expected in this case."); } [TestMethod] @@ -125,29 +85,40 @@ public void ProcessRowsForValidationErrors_SingleValidationError_ReturnsListWith QuantityKg = "200", QuantityUnits = "20" }; - var rows = new List - { - row1, - row2 - }; + var rows = new List { row1, row2 }; var response = new SubsidiaryDetailsResponse { - // Initialize your response data + // Initialize response data if needed }; - var errorRequest = new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", ErrorCodes: new List { "Error1" }); - - _mockFindMatchingProducer.Setup(x => x.Match(rows[0], response, 0)).Returns(errorRequest); - _mockFindMatchingProducer.Setup(x => x.Match(rows[1], response, 1)).Returns((ProducerValidationEventIssueRequest)null); + var errorRequest = new ProducerValidationEventIssueRequest( + "Sub1", + "2024Q1", + 1, + "Prod1", + "TypeA", + "Large", + "WasteTypeA", + "CategoryA", + "MaterialA", + "SubTypeA", + "NationA", + "NationB", + "100", + "10", + ErrorCodes: new List { "Error1" }); + + _mockFindMatchingProducer.Setup(x => x.Match(row1, response, 0)).Returns(errorRequest); + _mockFindMatchingProducer.Setup(x => x.Match(row2, response, 1)).Returns((ProducerValidationEventIssueRequest)null); // Act var result = _validator.ProcessRowsForValidationErrors(rows, response); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(1, result.Count()); - Assert.AreEqual(errorRequest, result.First()); + result.Should().NotBeNull("the result should contain errors if one row has a validation issue.") + .And.HaveCount(1, "because there is only one expected validation error.") + .And.ContainSingle(error => error.Equals(errorRequest), "the single error returned should match the expected error request."); } [TestMethod] @@ -189,31 +160,57 @@ public void ProcessRowsForValidationErrors_MultipleValidationErrors_ReturnsListW QuantityKg = "200", QuantityUnits = "20" }; - var rows = new List - { - row1, - row2 - }; + var rows = new List { row1, row2 }; var response = new SubsidiaryDetailsResponse { - // Initialize your response data + // Initialize response data if needed }; - var errorRequest1 = new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", ErrorCodes: new List { "Error1" }); - var errorRequest2 = new ProducerValidationEventIssueRequest("Sub2", "2024Q1", 2, "Prod2", "TypeB", "Small", "WasteTypeB", "CategoryB", "MaterialB", "SubTypeB", "NationA", "NationB", "200", "20", ErrorCodes: new List { "Error2" }); - - _mockFindMatchingProducer.Setup(x => x.Match(rows[0], response, 0)).Returns(errorRequest1); - _mockFindMatchingProducer.Setup(x => x.Match(rows[1], response, 1)).Returns(errorRequest2); + var errorRequest1 = new ProducerValidationEventIssueRequest( + "Sub1", + "2024Q1", + 1, + "Prod1", + "TypeA", + "Large", + "WasteTypeA", + "CategoryA", + "MaterialA", + "SubTypeA", + "NationA", + "NationB", + "100", + "10", + ErrorCodes: new List { "Error1" }); + + var errorRequest2 = new ProducerValidationEventIssueRequest( + "Sub2", + "2024Q1", + 2, + "Prod2", + "TypeB", + "Small", + "WasteTypeB", + "CategoryB", + "MaterialB", + "SubTypeB", + "NationA", + "NationB", + "200", + "20", + ErrorCodes: new List { "Error2" }); + + _mockFindMatchingProducer.Setup(x => x.Match(row1, response, 0)).Returns(errorRequest1); + _mockFindMatchingProducer.Setup(x => x.Match(row2, response, 1)).Returns(errorRequest2); // Act var result = _validator.ProcessRowsForValidationErrors(rows, response); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(2, result.Count()); - Assert.IsTrue(result.Contains(errorRequest1)); - Assert.IsTrue(result.Contains(errorRequest2)); + result.Should().NotBeNull("the result should contain all validation errors if multiple rows have issues.") + .And.HaveCount(2, "because two validation errors are expected.") + .And.Contain(new[] { errorRequest1, errorRequest2 }, "the list of errors returned should match the expected errors."); } } } From a4153702fc66e69820820f7059d0ee84b12a3a7a Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 10:58:07 +0000 Subject: [PATCH 33/44] Changed ValidationServiceTests to use fluent validation --- .../Services/ValidationServiceTests.cs | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index ebb2e75..9fbc6e4 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -140,8 +140,8 @@ public async Task ValidateSubsidiary_SuccessfulValidation_ReturnsEmptyList() var result = await service.ValidateSubsidiaryAsync(rows); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(0, result.Count); + result.Should().NotBeNull("the result should not be null.") + .And.HaveCount(0, "because there are no validation errors expected in this case."); } [TestMethod] @@ -177,8 +177,8 @@ public async Task ValidateSubsidiaryAsyncInvalidRequestReturnsEmptyList() var result = await service.ValidateSubsidiaryAsync(rows); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(0, result.Count); + result.Should().NotBeNull("the result should not be null.") + .And.HaveCount(0, "because there are no validation errors expected in this case."); } [TestMethod] @@ -220,9 +220,9 @@ public async Task ValidateSubsidiaryAsync_ValidRequest_ReturnsValidationErrors() var result = await service.ValidateSubsidiaryAsync(rows); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(1, result.Count); - Assert.AreEqual(validationErrors.First(), result.First()); + result.Should().NotBeNull("the result should not be null.") + .And.HaveCount(1, "because there is only one expected validation error.") + .And.ContainSingle(error => error.Equals(validationErrors.First()), "the single error returned should match the expected validation error."); } [TestMethod] @@ -258,8 +258,8 @@ public async Task ValidateSubsidiaryAsync_HttpRequestException_LogsErrorAndRetur var result = await service.ValidateSubsidiaryAsync(rows); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(0, result.Count); + result.Should().NotBeNull("the result should not be null") + .And.HaveCount(0, "because we expect no validation errors."); } // End @@ -278,8 +278,8 @@ public async Task ValidateSubsidiary_NullSubsidiaryDetailsResponse_ReturnsEmptyL var result = await service.ValidateSubsidiaryAsync(rows); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(0, result.Count); + result.Should().NotBeNull(); + result.Should().BeEmpty(); } [TestMethod] @@ -299,8 +299,9 @@ public async Task ValidateSubsidiary_HttpRequestException_LogsErrorAndReturnsEmp var result = await service.ValidateSubsidiaryAsync(rows); // Assert - Assert.IsNotNull(result); - Assert.AreEqual(0, result.Count); + result.Should().NotBeNull("the result should not be null.") + .And.HaveCount(0, "because we expect zero validation errors."); + _loggerMock.Verify( x => x.Log( LogLevel.Error, @@ -308,7 +309,8 @@ public async Task ValidateSubsidiary_HttpRequestException_LogsErrorAndReturnsEmp It.Is((v, t) => v.ToString().Contains("Error during subsidiary validation.")), It.Is(ex => ex == exception), It.IsAny>()), - Times.Once); + Times.Once, + "the logger should log an error when validation fails."); } [TestMethod] @@ -326,7 +328,7 @@ public async Task ValidateAsync_WhenFeatureFlagIsOff_DoesNotPerformSubsidiaryVal // Assert _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(It.IsAny>()), Times.Never); _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Never); - Assert.IsNotNull(result); + result.Should().NotBeNull("the result should not be null"); } [TestMethod] @@ -345,7 +347,7 @@ public async Task ValidateAsync_WhenFeatureFlagIsOn_DoesPerformSubsidiaryValidat // Assert _subsidiaryDetailsRequestBuilderMock.Verify(x => x.CreateRequest(It.IsAny>()), Times.Once); _companyDetailsApiClientMock.Verify(x => x.GetSubsidiaryDetails(It.IsAny()), Times.Once); - Assert.IsNotNull(result); + result.Should().NotBeNull("the result should not be null."); } [TestMethod] @@ -362,8 +364,8 @@ public async Task ValidateAsync_WhenRemainingWarningCapacityIsZero_OnlyErrorsAre var result = await service.ValidateAsync(producer); // Assert - Assert.IsNotNull(result); - Assert.IsTrue(result.ValidationWarnings.Count == 0); + result.Should().NotBeNull("the result should not be null."); + result.ValidationWarnings.Should().BeEmpty("because there should be no validation warnings."); } [TestMethod] @@ -381,7 +383,7 @@ public async Task ValidateSubsidiaryAsync_InvalidRequest_ReturnsEmptyList() var result = await service.ValidateSubsidiaryAsync(rows); // Assert - Assert.AreEqual(0, result.Count); + result.Should().HaveCount(0, "because there are no validation errors expected in this case."); } [TestMethod] @@ -408,8 +410,10 @@ public async Task ValidateAsync_WhenWarningCapacityReached_LogsWarning() It.IsAny(), It.IsAny>()), Times.Never); - Assert.IsNotNull(result); - Assert.AreEqual(0, result.ValidationWarnings.Count); + + // Use FluentAssertions for result validation + result.Should().NotBeNull("the result should not be null."); + result.ValidationWarnings.Should().BeEmpty("because there should be no validation warnings."); } [TestMethod] From 605c6757bdd62d1774de8bbdccf348148aaf5376 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 11:19:17 +0000 Subject: [PATCH 34/44] Resolved a review comment --- .../Services/Helpers/ValidationServiceProducerRowValidator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs index 7e7d95f..de6fec1 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs @@ -19,7 +19,7 @@ public IEnumerable ProcessRowsForValidation { var validationErrors = new List(); - for (int i = 0; i < rows.Count; i++) + for (var i = 0; i < rows.Count; i++) { var error = _findMatchingProducer.Match(rows[i], response, i); if (error != null) From c37c36f9ebca0bc2330fe6cc2bd9cd8a28106108 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 12:27:14 +0000 Subject: [PATCH 35/44] Removed Data project, moving functional contents to Application --- .../Clients/CompanyDetailsApiClientTests.cs | 2 +- .../Config/CompanyDetailsApiConfig.cs | 0 .../Data/CompanyDetailsDataItemTests.cs | 83 +++++++++++++++++++ .../Helpers/FindMatchingProducerTests.cs | 2 +- .../Helpers/OrganisationMatcherTests.cs | 2 +- .../Services/Helpers/RequestValidatorTests.cs | 4 +- .../Helpers/SubsidiaryMatcherTests.cs | 4 +- .../SubsidiaryValidationEvaluatorTests.cs | 2 +- ...idationServiceProducerRowValidatorTests.cs | 2 +- .../Services/ValidationServiceTests.cs | 2 +- .../Clients/CompanyDetailsApiClient.cs | 2 +- .../Clients/ICompanyDetailsApiClient.cs | 2 +- .../Config/CompanyDetailsApiConfig.cs | 16 ++++ ...oducerContentValidation.Application.csproj | 4 - .../CompanyDetailsApiAuthorisationHandler.cs | 2 +- .../CompanyDetailsDataItem.cs | 2 +- .../CompanyDetailsDataResult.cs | 2 +- .../Models/Subsidiary/SubsidiaryDetail.cs | 2 +- .../Subsidiary/SubsidiaryDetailsRequest.cs | 2 +- .../Subsidiary/SubsidiaryDetailsResponse.cs | 2 +- .../SubsidiaryOrganisationDetail.cs | 2 +- .../Services/Helpers/FindMatchingProducer.cs | 2 +- .../Interfaces/IFindMatchingProducer.cs | 2 +- .../Interfaces/IOrganisationMatcher.cs | 2 +- .../Helpers/Interfaces/IRequestValidator.cs | 2 +- .../Helpers/Interfaces/ISubsidiaryMatcher.cs | 2 +- .../ISubsidiaryValidationEvaluator.cs | 2 +- .../IValidationServiceProducerRowValidator.cs | 2 +- .../Services/Helpers/OrganisationMatcher.cs | 2 +- .../Services/Helpers/RequestValidator.cs | 4 +- .../Services/Helpers/SubsidiaryMatcher.cs | 2 +- .../Helpers/SubsidiaryValidationEvaluator.cs | 2 +- .../ValidationServiceProducerRowValidator.cs | 2 +- .../ISubsidiaryDetailsRequestBuilder.cs | 2 +- .../SubsidiaryDetailsRequestBuilder.cs | 2 +- .../Services/ValidationService.cs | 2 +- ...cerContentValidation.Data.UnitTests.csproj | 4 - .../StartUp.cs | 2 +- .../Clients/CompanyDetailsApiClientTests.cs | 4 +- ....ProducerContentValidation.UnitTest.csproj | 1 - src/EPR.ProducerContentValidation.sln | 12 --- 41 files changed, 137 insertions(+), 59 deletions(-) rename src/{EPR.ProducerContentValidation.Data => EPR.ProducerContentValidation.Application.UnitTests}/Config/CompanyDetailsApiConfig.cs (100%) create mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs create mode 100644 src/EPR.ProducerContentValidation.Application/Config/CompanyDetailsApiConfig.cs rename src/{EPR.ProducerContentValidation.Data => EPR.ProducerContentValidation.Application}/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs (77%) rename src/{EPR.ProducerContentValidation.Data => EPR.ProducerContentValidation.Application}/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs (75%) rename src/{EPR.ProducerContentValidation.Data => EPR.ProducerContentValidation.Application}/Models/Subsidiary/SubsidiaryDetail.cs (81%) rename src/{EPR.ProducerContentValidation.Data => EPR.ProducerContentValidation.Application}/Models/Subsidiary/SubsidiaryDetailsRequest.cs (76%) rename src/{EPR.ProducerContentValidation.Data => EPR.ProducerContentValidation.Application}/Models/Subsidiary/SubsidiaryDetailsResponse.cs (76%) rename src/{EPR.ProducerContentValidation.Data => EPR.ProducerContentValidation.Application}/Models/Subsidiary/SubsidiaryOrganisationDetail.cs (79%) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs index fb0f622..67fa909 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs @@ -1,7 +1,7 @@ using System.Net; using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Data.Config; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using FluentAssertions; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Data/Config/CompanyDetailsApiConfig.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Config/CompanyDetailsApiConfig.cs similarity index 100% rename from src/EPR.ProducerContentValidation.Data/Config/CompanyDetailsApiConfig.cs rename to src/EPR.ProducerContentValidation.Application.UnitTests/Config/CompanyDetailsApiConfig.cs diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs new file mode 100644 index 0000000..ec3639d --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs @@ -0,0 +1,83 @@ +using EPR.ProducerContentValidation.Application.Models.CompanyDetailsApi; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json; + +namespace EPR.ProducerContentValidation.Data.UnitTests +{ + [TestClass] + public class CompanyDetailsDataItemTests + { + [TestMethod] + public void SerializeCompanyDetailsDataItem_ToJson_ContainsCorrectJsonPropertyNames() + { + // Arrange + var companyDetails = new CompanyDetailsDataItem + { + ReferenceNumber = "REF123", + CompaniesHouseNumber = "CHN456" + }; + + // Act + var json = JsonConvert.SerializeObject(companyDetails); + + // Assert + json.Should().Contain("\"RN\":\"REF123\"") + .And.Contain("\"CHN\":\"CHN456\""); + } + + [TestMethod] + public void DeserializeCompanyDetailsDataItem_FromJson_HasCorrectPropertyValues() + { + // Arrange + var json = "{\"RN\":\"REF123\", \"CHN\":\"CHN456\"}"; + + // Act + var companyDetails = JsonConvert.DeserializeObject(json); + + // Assert + companyDetails.Should().NotBeNull(); + companyDetails!.ReferenceNumber.Should().Be("REF123"); + companyDetails.CompaniesHouseNumber.Should().Be("CHN456"); + } + + [TestMethod] + public void SerializeCompanyDetailsDataItem_NullValues_HasNullJsonProperties() + { + // Arrange + var companyDetails = new CompanyDetailsDataItem + { + ReferenceNumber = null, + CompaniesHouseNumber = null + }; + + // Act + var json = JsonConvert.SerializeObject(companyDetails); + + // Assert + json.Should().Contain("\"RN\":null") + .And.Contain("\"CHN\":null"); + } + + [TestMethod] + public void DeserializeCompanyDetailsDataItem_NullOrMissingValues_PropertiesAreNull() + { + // Arrange + var jsonWithNulls = "{\"RN\":null, \"CHN\":null}"; + var jsonWithoutKeys = "{}"; + + // Act + var companyDetailsWithNulls = JsonConvert.DeserializeObject(jsonWithNulls); + var companyDetailsWithoutKeys = JsonConvert.DeserializeObject(jsonWithoutKeys); + + // Assert + companyDetailsWithNulls.Should().NotBeNull(); + companyDetailsWithNulls!.ReferenceNumber.Should().BeNull(); + companyDetailsWithNulls.CompaniesHouseNumber.Should().BeNull(); + + companyDetailsWithoutKeys.Should().NotBeNull(); + companyDetailsWithoutKeys!.ReferenceNumber.Should().BeNull(); + companyDetailsWithoutKeys.CompaniesHouseNumber.Should().BeNull(); + } + } +} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs index dcf323c..f482ae5 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs @@ -1,8 +1,8 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs index ad17f13..5759154 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs @@ -1,6 +1,6 @@ using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs index b47650c..9920490 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs @@ -1,5 +1,5 @@ -using EPR.ProducerContentValidation.Application.Services.Helpers; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Services.Helpers; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs index 910f4e4..09c9103 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs @@ -1,5 +1,5 @@ -using EPR.ProducerContentValidation.Application.Services.Helpers; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs index 9be42eb..0b5bfea 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs @@ -1,9 +1,9 @@ using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.Extensions.Logging; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs index 6e32a08..48b27a3 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs @@ -1,8 +1,8 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 9fbc6e4..635d368 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -3,6 +3,7 @@ using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Profiles; using EPR.ProducerContentValidation.Application.Services; @@ -10,7 +11,6 @@ using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using EPR.ProducerContentValidation.TestSupport; using FluentAssertions; using Microsoft.Extensions.Logging; diff --git a/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs b/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs index 05c886b..c08c2db 100644 --- a/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs +++ b/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs @@ -1,4 +1,4 @@ -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using Microsoft.Extensions.Logging; using Newtonsoft.Json; diff --git a/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs b/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs index 79086d9..a197b06 100644 --- a/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs +++ b/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs @@ -1,4 +1,4 @@ -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Clients { diff --git a/src/EPR.ProducerContentValidation.Application/Config/CompanyDetailsApiConfig.cs b/src/EPR.ProducerContentValidation.Application/Config/CompanyDetailsApiConfig.cs new file mode 100644 index 0000000..35cdd8d --- /dev/null +++ b/src/EPR.ProducerContentValidation.Application/Config/CompanyDetailsApiConfig.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; + +namespace EPR.ProducerContentValidation.Application.Config +{ + public class CompanyDetailsApiConfig + { + public const string Section = "CompanyDetailsApi"; + + [Required] + public string BaseUrl { get; init; } + + public string? ClientId { get; set; } + + public int Timeout { get; set; } + } +} diff --git a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj index eda8453..a63ccb9 100644 --- a/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj +++ b/src/EPR.ProducerContentValidation.Application/EPR.ProducerContentValidation.Application.csproj @@ -25,8 +25,4 @@ - - - - \ No newline at end of file diff --git a/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs b/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs index 8513db8..1b3e179 100644 --- a/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs +++ b/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs @@ -2,7 +2,7 @@ using System.Net.Http.Headers; using Azure.Core; using Azure.Identity; -using EPR.ProducerContentValidation.Data.Config; +using EPR.ProducerContentValidation.Application.Config; using Microsoft.Extensions.Options; namespace EPR.ProducerContentValidation.Application.Handlers diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs b/src/EPR.ProducerContentValidation.Application/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs similarity index 77% rename from src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs rename to src/EPR.ProducerContentValidation.Application/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs index 9d0fe95..ec4b324 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/CompanyDetailsApi/CompanyDetailsDataItem.cs @@ -1,4 +1,4 @@ -namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +namespace EPR.ProducerContentValidation.Application.Models.CompanyDetailsApi; using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; diff --git a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs b/src/EPR.ProducerContentValidation.Application/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs similarity index 75% rename from src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs rename to src/EPR.ProducerContentValidation.Application/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs index 9b57696..cd5b99e 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/CompanyDetailsApi/CompanyDetailsDataResult.cs @@ -1,4 +1,4 @@ -namespace EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; +namespace EPR.ProducerContentValidation.Application.Models.CompanyDetailsApi; using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetail.cs similarity index 81% rename from src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs rename to src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetail.cs index 3ab3452..415cd8c 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetail.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetail.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; -namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +namespace EPR.ProducerContentValidation.Application.Models.Subsidiary { [ExcludeFromCodeCoverage] public class SubsidiaryDetail diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsRequest.cs b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsRequest.cs similarity index 76% rename from src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsRequest.cs rename to src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsRequest.cs index c3a3f47..edecc9d 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsRequest.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsRequest.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; -namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +namespace EPR.ProducerContentValidation.Application.Models.Subsidiary { [ExcludeFromCodeCoverage] public class SubsidiaryDetailsRequest diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsResponse.cs b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsResponse.cs similarity index 76% rename from src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsResponse.cs rename to src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsResponse.cs index 7a82d14..669fff7 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryDetailsResponse.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsResponse.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; -namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +namespace EPR.ProducerContentValidation.Application.Models.Subsidiary { [ExcludeFromCodeCoverage] public class SubsidiaryDetailsResponse diff --git a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryOrganisationDetail.cs b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryOrganisationDetail.cs similarity index 79% rename from src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryOrganisationDetail.cs rename to src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryOrganisationDetail.cs index c467b0c..9ca2695 100644 --- a/src/EPR.ProducerContentValidation.Data/Models/Subsidiary/SubsidiaryOrganisationDetail.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryOrganisationDetail.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; -namespace EPR.ProducerContentValidation.Data.Models.Subsidiary +namespace EPR.ProducerContentValidation.Application.Models.Subsidiary { [ExcludeFromCodeCoverage] public class SubsidiaryOrganisationDetail diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs index dcb12fb..5d4474e 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs @@ -1,7 +1,7 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs index e27f943..97bc2b2 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs @@ -1,6 +1,6 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs index ba25656..2aca078 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs @@ -1,5 +1,5 @@ using EPR.ProducerContentValidation.Application.Models; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs index 321a86f..f332719 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs @@ -1,4 +1,4 @@ -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs index 8e97c6d..bed05ee 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs @@ -1,5 +1,5 @@ using EPR.ProducerContentValidation.Application.Models; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs index 2979b17..41781d4 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs @@ -1,6 +1,6 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs index 8793799..09e628a 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs @@ -1,6 +1,6 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs index 02192da..514ef72 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs @@ -1,6 +1,6 @@ using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs index a0db7c9..0818036 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs @@ -1,5 +1,5 @@ -using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; namespace EPR.ProducerContentValidation.Application.Services.Helpers { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs index 7137043..cf29478 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs @@ -1,6 +1,6 @@ using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs index 026fae2..1a28614 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs @@ -1,8 +1,8 @@ using EPR.ProducerContentValidation.Application.Constants; using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using Microsoft.Extensions.Logging; namespace EPR.ProducerContentValidation.Application.Services.Helpers diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs index de6fec1..d681b9c 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs @@ -1,7 +1,7 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Helpers { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs index c4eda28..cdc1b25 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs @@ -1,5 +1,5 @@ using EPR.ProducerContentValidation.Application.Models; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Subsidiary { diff --git a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs index 8084dcb..6342e2b 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs @@ -1,5 +1,5 @@ using EPR.ProducerContentValidation.Application.Models; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; namespace EPR.ProducerContentValidation.Application.Services.Subsidiary { diff --git a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs index 1f37e23..b921611 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/ValidationService.cs @@ -4,13 +4,13 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Extensions; using EPR.ProducerContentValidation.Application.Models; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Services.Helpers; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using EPR.ProducerContentValidation.Application.Services.Interfaces; using EPR.ProducerContentValidation.Application.Services.Subsidiary; using EPR.ProducerContentValidation.Application.Validators.Interfaces; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.FeatureManagement; diff --git a/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj b/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj index ae6b92c..cd4452f 100644 --- a/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj +++ b/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj @@ -15,8 +15,4 @@ - - - - diff --git a/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs b/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs index 60826d1..ca27672 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs +++ b/src/EPR.ProducerContentValidation.FunctionApp/StartUp.cs @@ -9,8 +9,8 @@ namespace EPR.ProducerContentValidation.FunctionApp; using System.Net.Http.Headers; using Application; using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Application.Config; using EPR.ProducerContentValidation.Application.Handlers; -using EPR.ProducerContentValidation.Data.Config; using Microsoft.Azure.Functions.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; diff --git a/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs b/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs index 717a780..db9437b 100644 --- a/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs +++ b/src/EPR.ProducerContentValidation.UnitTest/Clients/CompanyDetailsApiClientTests.cs @@ -1,7 +1,7 @@ using System.Net; using EPR.ProducerContentValidation.Application.Clients; -using EPR.ProducerContentValidation.Data.Config; -using EPR.ProducerContentValidation.Data.Models.Subsidiary; +using EPR.ProducerContentValidation.Application.Config; +using EPR.ProducerContentValidation.Application.Models.Subsidiary; using FluentAssertions; using Microsoft.Extensions.Logging.Abstractions; using Moq; diff --git a/src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj b/src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj index 36e4698..345a1b6 100644 --- a/src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj +++ b/src/EPR.ProducerContentValidation.UnitTest/EPR.ProducerContentValidation.UnitTest.csproj @@ -20,7 +20,6 @@ - diff --git a/src/EPR.ProducerContentValidation.sln b/src/EPR.ProducerContentValidation.sln index 6fb7ebb..db18649 100644 --- a/src/EPR.ProducerContentValidation.sln +++ b/src/EPR.ProducerContentValidation.sln @@ -22,12 +22,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution stylecop.ruleset = stylecop.ruleset EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.Data", "EPR.ProducerContentValidation.Data\EPR.ProducerContentValidation.Data.csproj", "{0944BDFE-6DD0-48E0-8A08-A36203138D43}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EPR.ProducerContentValidation.UnitTest", "EPR.ProducerContentValidation.UnitTest\EPR.ProducerContentValidation.UnitTest.csproj", "{C22C5FE6-1839-4026-B7F3-ECD78154445E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EPR.ProducerContentValidation.Data.UnitTests", "EPR.ProducerContentValidation.Data.UnitTests\EPR.ProducerContentValidation.Data.UnitTests.csproj", "{F3E90F69-1835-460D-ACCA-890229303A0E}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -54,18 +50,10 @@ Global {3CFB967D-D84E-44E0-91A4-55B44EEC5215}.Debug|Any CPU.Build.0 = Debug|Any CPU {3CFB967D-D84E-44E0-91A4-55B44EEC5215}.Release|Any CPU.ActiveCfg = Release|Any CPU {3CFB967D-D84E-44E0-91A4-55B44EEC5215}.Release|Any CPU.Build.0 = Release|Any CPU - {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0944BDFE-6DD0-48E0-8A08-A36203138D43}.Release|Any CPU.Build.0 = Release|Any CPU {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Debug|Any CPU.Build.0 = Debug|Any CPU {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Release|Any CPU.ActiveCfg = Release|Any CPU {C22C5FE6-1839-4026-B7F3-ECD78154445E}.Release|Any CPU.Build.0 = Release|Any CPU - {F3E90F69-1835-460D-ACCA-890229303A0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F3E90F69-1835-460D-ACCA-890229303A0E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F3E90F69-1835-460D-ACCA-890229303A0E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F3E90F69-1835-460D-ACCA-890229303A0E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From ca3556ad0d3552ae053aaab4f7ebb56a0eb62a61 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 12:52:34 +0000 Subject: [PATCH 36/44] Some refactoring --- .../Clients/CompanyDetailsApiClientTests.cs | 2 +- .../Config/CompanyDetailsApiConfig.cs | 16 ---------------- .../Data/CompanyDetailsDataItemTests.cs | 2 +- 3 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 src/EPR.ProducerContentValidation.Application.UnitTests/Config/CompanyDetailsApiConfig.cs diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs index 67fa909..65c41b5 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs @@ -1,7 +1,7 @@ using System.Net; using EPR.ProducerContentValidation.Application.Clients; +using EPR.ProducerContentValidation.Application.Config; using EPR.ProducerContentValidation.Application.Models.Subsidiary; -using EPR.ProducerContentValidation.Data.Config; using FluentAssertions; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Config/CompanyDetailsApiConfig.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Config/CompanyDetailsApiConfig.cs deleted file mode 100644 index d890038..0000000 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Config/CompanyDetailsApiConfig.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace EPR.ProducerContentValidation.Data.Config -{ - public class CompanyDetailsApiConfig - { - public const string Section = "CompanyDetailsApi"; - - [Required] - public string BaseUrl { get; init; } - - public string? ClientId { get; set; } - - public int Timeout { get; set; } - } -} diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs index ec3639d..8e5b027 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs @@ -3,7 +3,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; -namespace EPR.ProducerContentValidation.Data.UnitTests +namespace EPR.ProducerContentValidation.Application.UnitTests { [TestClass] public class CompanyDetailsDataItemTests From e73f2f2387d3935ba73aa76aac4ad454a59610c4 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 13:05:36 +0000 Subject: [PATCH 37/44] Some refactoring --- src/EPR.ProducerContentValidation.FunctionApp/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile index dfe992d..30f9ead 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile +++ b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile @@ -8,7 +8,6 @@ FROM mcr.microsoft.com/dotnet/sdk:8.0 AS installer-env COPY stylecop.ruleset ./ COPY Directory.Build.props ./ COPY EPR.ProducerContentValidation.Application/. ./EPR.ProducerContentValidation.Application/. -COPY EPR.ProducerContentValidation.Data/. ./EPR.ProducerContentValidation.Data/. COPY EPR.ProducerContentValidation.FunctionApp/. ./EPR.ProducerContentValidation.FunctionApp/. RUN dotnet publish EPR.ProducerContentValidation.FunctionApp/*.csproj --output /home/site/wwwroot From dcda9dab2f973e548c42cb166fa2aa9a75c981b9 Mon Sep 17 00:00:00 2001 From: Fahad Ali Date: Fri, 1 Nov 2024 13:19:16 +0000 Subject: [PATCH 38/44] project removed from docker file --- src/EPR.ProducerContentValidation.FunctionApp/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile index dfe992d..30f9ead 100644 --- a/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile +++ b/src/EPR.ProducerContentValidation.FunctionApp/Dockerfile @@ -8,7 +8,6 @@ FROM mcr.microsoft.com/dotnet/sdk:8.0 AS installer-env COPY stylecop.ruleset ./ COPY Directory.Build.props ./ COPY EPR.ProducerContentValidation.Application/. ./EPR.ProducerContentValidation.Application/. -COPY EPR.ProducerContentValidation.Data/. ./EPR.ProducerContentValidation.Data/. COPY EPR.ProducerContentValidation.FunctionApp/. ./EPR.ProducerContentValidation.FunctionApp/. RUN dotnet publish EPR.ProducerContentValidation.FunctionApp/*.csproj --output /home/site/wwwroot From 753f96d87277f5469d34b5c9d90605d290473d43 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Fri, 1 Nov 2024 13:33:46 +0000 Subject: [PATCH 39/44] Some refactoring --- .../CompanyDetailsDataItemTests.cs | 83 ------------------- ...cerContentValidation.Data.UnitTests.csproj | 18 ---- .../EPR.ProducerContentValidation.Data.csproj | 13 --- 3 files changed, 114 deletions(-) delete mode 100644 src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs delete mode 100644 src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj delete mode 100644 src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj diff --git a/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs b/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs deleted file mode 100644 index 6fb725f..0000000 --- a/src/EPR.ProducerContentValidation.Data.UnitTests/CompanyDetailsDataItemTests.cs +++ /dev/null @@ -1,83 +0,0 @@ -using EPR.ProducerContentValidation.Data.Models.CompanyDetailsApi; -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Newtonsoft.Json; - -namespace EPR.ProducerContentValidation.Data.UnitTests -{ - [TestClass] - public class CompanyDetailsDataItemTests - { - [TestMethod] - public void SerializeCompanyDetailsDataItem_ToJson_ContainsCorrectJsonPropertyNames() - { - // Arrange - var companyDetails = new CompanyDetailsDataItem - { - ReferenceNumber = "REF123", - CompaniesHouseNumber = "CHN456" - }; - - // Act - var json = JsonConvert.SerializeObject(companyDetails); - - // Assert - json.Should().Contain("\"RN\":\"REF123\"") - .And.Contain("\"CHN\":\"CHN456\""); - } - - [TestMethod] - public void DeserializeCompanyDetailsDataItem_FromJson_HasCorrectPropertyValues() - { - // Arrange - var json = "{\"RN\":\"REF123\", \"CHN\":\"CHN456\"}"; - - // Act - var companyDetails = JsonConvert.DeserializeObject(json); - - // Assert - companyDetails.Should().NotBeNull(); - companyDetails!.ReferenceNumber.Should().Be("REF123"); - companyDetails.CompaniesHouseNumber.Should().Be("CHN456"); - } - - [TestMethod] - public void SerializeCompanyDetailsDataItem_NullValues_HasNullJsonProperties() - { - // Arrange - var companyDetails = new CompanyDetailsDataItem - { - ReferenceNumber = null, - CompaniesHouseNumber = null - }; - - // Act - var json = JsonConvert.SerializeObject(companyDetails); - - // Assert - json.Should().Contain("\"RN\":null") - .And.Contain("\"CHN\":null"); - } - - [TestMethod] - public void DeserializeCompanyDetailsDataItem_NullOrMissingValues_PropertiesAreNull() - { - // Arrange - var jsonWithNulls = "{\"RN\":null, \"CHN\":null}"; - var jsonWithoutKeys = "{}"; - - // Act - var companyDetailsWithNulls = JsonConvert.DeserializeObject(jsonWithNulls); - var companyDetailsWithoutKeys = JsonConvert.DeserializeObject(jsonWithoutKeys); - - // Assert - companyDetailsWithNulls.Should().NotBeNull(); - companyDetailsWithNulls!.ReferenceNumber.Should().BeNull(); - companyDetailsWithNulls.CompaniesHouseNumber.Should().BeNull(); - - companyDetailsWithoutKeys.Should().NotBeNull(); - companyDetailsWithoutKeys!.ReferenceNumber.Should().BeNull(); - companyDetailsWithoutKeys.CompaniesHouseNumber.Should().BeNull(); - } - } -} diff --git a/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj b/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj deleted file mode 100644 index cd4452f..0000000 --- a/src/EPR.ProducerContentValidation.Data.UnitTests/EPR.ProducerContentValidation.Data.UnitTests.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - Exe - net8.0 - enable - enable - - - - - - - - - - - diff --git a/src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj b/src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj deleted file mode 100644 index 3b5b170..0000000 --- a/src/EPR.ProducerContentValidation.Data/EPR.ProducerContentValidation.Data.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - net8.0 - enable - enable - - - - - - - From e900d7abfe1512f223c6db72b76aa2d997ee78d8 Mon Sep 17 00:00:00 2001 From: Fahad Ali Date: Fri, 1 Nov 2024 15:29:19 +0000 Subject: [PATCH 40/44] handler added in DI --- .../ConfigureServices.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs index 352e80d..9d2e524 100644 --- a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs +++ b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs @@ -1,6 +1,7 @@ using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using System.Reflection; +using EPR.ProducerContentValidation.Application.Handlers; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; using EPR.ProducerContentValidation.Application.Services; @@ -42,7 +43,8 @@ private static void RegisterServices(this IServiceCollection services) .AddSingleton() .AddSingleton() .AddSingleton() - .AddScoped(); + .AddScoped() + .AddTransient(); } private static IServiceCollection ConfigureOptions(this IServiceCollection services) From 38019b5f02368a6ed9115150ae1082d4dd02579f Mon Sep 17 00:00:00 2001 From: Fahad Ali Date: Fri, 1 Nov 2024 18:21:46 +0000 Subject: [PATCH 41/44] missing config section added --- .../ConfigureServices.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs index 9d2e524..5d684e1 100644 --- a/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs +++ b/src/EPR.ProducerContentValidation.Application/ConfigureServices.cs @@ -1,6 +1,7 @@ using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using System.Reflection; +using EPR.ProducerContentValidation.Application.Config; using EPR.ProducerContentValidation.Application.Handlers; using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Options; @@ -55,6 +56,7 @@ private static IServiceCollection ConfigureOptions(this IServiceCollection servi services.ConfigureSection(StorageAccountOptions.Section); services.ConfigureSection(RedisOptions.Section); services.ConfigureSection>(SubmissionPeriodOption.Section); + services.ConfigureSection(CompanyDetailsApiConfig.Section); return services; } From 6314a16d7a83056622bbca07fbc9d6100b4b4231 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Sat, 2 Nov 2024 14:29:36 +0000 Subject: [PATCH 42/44] Modifications to use file scoped namespace format --- .../Clients/CompanyDetailsApiClientTests.cs | 233 +++++---- .../Data/CompanyDetailsDataItemTests.cs | 119 +++-- .../Helpers/FindMatchingProducerTests.cs | 227 +++++---- .../Helpers/OrganisationMatcherTests.cs | 225 +++++---- .../ProducerValidationEventFormatterTests.cs | 235 +++++---- ...rValidationEventIssueRequestMergerTests.cs | 471 +++++++++--------- .../Services/Helpers/RequestValidatorTests.cs | 111 ++--- .../Helpers/SubsidiaryMatcherTests.cs | 323 ++++++------ .../SubsidiaryValidationEvaluatorTests.cs | 285 ++++++----- ...idationServiceProducerRowValidatorTests.cs | 383 +++++++------- .../SubsidiaryDetailsRequestBuilderTests.cs | 471 +++++++++--------- .../Clients/CompanyDetailsApiClient.cs | 81 ++- .../Clients/ICompanyDetailsApiClient.cs | 9 +- .../Config/CompanyDetailsApiConfig.cs | 17 +- .../CompanyDetailsApiClientException.cs | 29 +- .../CompanyDetailsApiAuthorisationHandler.cs | 45 +- .../Models/Subsidiary/SubsidiaryDetail.cs | 15 +- .../Subsidiary/SubsidiaryDetailsRequest.cs | 11 +- .../Subsidiary/SubsidiaryDetailsResponse.cs | 11 +- .../SubsidiaryOrganisationDetail.cs | 13 +- .../Services/Helpers/FindMatchingProducer.cs | 47 +- .../Interfaces/IFindMatchingProducer.cs | 9 +- .../Interfaces/IOrganisationMatcher.cs | 9 +- ...cerValidationEventIssueRequestFormatter.cs | 9 +- .../Helpers/Interfaces/IRequestValidator.cs | 9 +- .../Helpers/Interfaces/ISubsidiaryMatcher.cs | 9 +- .../ISubsidiaryValidationEvaluator.cs | 9 +- .../IValidationServiceProducerRowValidator.cs | 11 +- .../Services/Helpers/OrganisationMatcher.cs | 13 +- ...cerValidationEventIssueRequestFormatter.cs | 43 +- ...oducerValidationEventIssueRequestMerger.cs | 103 ++-- .../Services/Helpers/RequestValidator.cs | 11 +- .../Services/Helpers/SubsidiaryMatcher.cs | 13 +- .../Helpers/SubsidiaryValidationEvaluator.cs | 49 +- .../ValidationServiceProducerRowValidator.cs | 37 +- .../ISubsidiaryDetailsRequestBuilder.cs | 9 +- .../SubsidiaryDetailsRequestBuilder.cs | 43 +- 37 files changed, 1863 insertions(+), 1884 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs index 65c41b5..1bb57b5 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Clients/CompanyDetailsApiClientTests.cs @@ -9,142 +9,141 @@ using Moq.Protected; using Newtonsoft.Json; -namespace EPR.ProducerContentValidation.Application.UnitTests.Clients +namespace EPR.ProducerContentValidation.Application.UnitTests.Clients; + +[TestClass] +public class CompanyDetailsApiClientTests { - [TestClass] - public class CompanyDetailsApiClientTests - { - private CompanyDetailsApiConfig? _config; + private CompanyDetailsApiConfig? _config; - [TestInitialize] - public void Setup() + [TestInitialize] + public void Setup() + { + _config = new CompanyDetailsApiConfig { - _config = new CompanyDetailsApiConfig - { - BaseUrl = "https://www.testurl.com", - ClientId = "test-client-id", - Timeout = 5, - }; - } + BaseUrl = "https://www.testurl.com", + ClientId = "test-client-id", + Timeout = 5, + }; + } - [TestMethod] - public async Task GetSubsidiaryDetails_ShouldReturnSubsidiaryDetailsRequest_OnSuccess() + [TestMethod] + public async Task GetSubsidiaryDetails_ShouldReturnSubsidiaryDetailsRequest_OnSuccess() + { + // Arrange + var request = new SubsidiaryDetailsRequest(); + var content = JsonConvert.SerializeObject(request); + var responseMessage = new HttpResponseMessage { - // Arrange - var request = new SubsidiaryDetailsRequest(); - var content = JsonConvert.SerializeObject(request); - var responseMessage = new HttpResponseMessage - { - StatusCode = HttpStatusCode.OK, - Content = new StringContent(content), - }; - var handlerMock = new Mock(MockBehavior.Strict); - handlerMock + StatusCode = HttpStatusCode.OK, + Content = new StringContent(content), + }; + var handlerMock = new Mock(MockBehavior.Strict); + handlerMock + .Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(content), + }) + .Verifiable(); + var httpClient = new HttpClient(handlerMock.Object) + { + BaseAddress = new Uri(_config.BaseUrl), + Timeout = TimeSpan.FromSeconds(_config.Timeout), + }; + var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); + + // Act + var result = await sut.GetSubsidiaryDetails(request); + + // Assert + result.Should().BeEquivalentTo(request); + handlerMock.Protected().Verify( + "SendAsync", + Times.Once(), + ItExpr.Is(req => + req.Method == HttpMethod.Post && + req.RequestUri.ToString().EndsWith("api/subsidiary-details")), + ItExpr.IsAny()); + } + + [DataRow(HttpStatusCode.Conflict)] + [DataRow(HttpStatusCode.BadRequest)] + [DataRow(HttpStatusCode.BadGateway)] + [DataRow(HttpStatusCode.Unauthorized)] + [TestMethod] + public async Task GetSubsidiaryDetails_WhenSendAsyncNotSuccessful_ThrowsError(HttpStatusCode statusCode) + { + // Arrange + var handlerMock = new Mock(MockBehavior.Strict); + handlerMock .Protected() .Setup>( - "SendAsync", - ItExpr.IsAny(), - ItExpr.IsAny()) + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) .ReturnsAsync(new HttpResponseMessage() { - StatusCode = HttpStatusCode.OK, - Content = new StringContent(content), + StatusCode = statusCode, }) .Verifiable(); - var httpClient = new HttpClient(handlerMock.Object) - { - BaseAddress = new Uri(_config.BaseUrl), - Timeout = TimeSpan.FromSeconds(_config.Timeout), - }; - var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); - - // Act - var result = await sut.GetSubsidiaryDetails(request); - // Assert - result.Should().BeEquivalentTo(request); - handlerMock.Protected().Verify( - "SendAsync", - Times.Once(), - ItExpr.Is(req => - req.Method == HttpMethod.Post && - req.RequestUri.ToString().EndsWith("api/subsidiary-details")), - ItExpr.IsAny()); - } - - [DataRow(HttpStatusCode.Conflict)] - [DataRow(HttpStatusCode.BadRequest)] - [DataRow(HttpStatusCode.BadGateway)] - [DataRow(HttpStatusCode.Unauthorized)] - [TestMethod] - public async Task GetSubsidiaryDetails_WhenSendAsyncNotSuccessful_ThrowsError(HttpStatusCode statusCode) + var httpClient = new HttpClient(handlerMock.Object) { - // Arrange - var handlerMock = new Mock(MockBehavior.Strict); - handlerMock - .Protected() - .Setup>( - "SendAsync", - ItExpr.IsAny(), - ItExpr.IsAny()) - .ReturnsAsync(new HttpResponseMessage() - { - StatusCode = statusCode, - }) - .Verifiable(); + BaseAddress = new Uri(_config.BaseUrl), + Timeout = TimeSpan.FromSeconds(_config.Timeout), + }; + var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); - var httpClient = new HttpClient(handlerMock.Object) - { - BaseAddress = new Uri(_config.BaseUrl), - Timeout = TimeSpan.FromSeconds(_config.Timeout), - }; - var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); + // Act + Func act = () => sut.GetSubsidiaryDetails(new SubsidiaryDetailsRequest()); - // Act - Func act = () => sut.GetSubsidiaryDetails(new SubsidiaryDetailsRequest()); + // Assert + await act.Should().ThrowAsync(); + } - // Assert - await act.Should().ThrowAsync(); - } + [TestMethod] + public async Task GetSubsidiaryDetails_ShouldReturnDefault_WhenResponseContentIsEmpty() + { + // Arrange + var request = new SubsidiaryDetailsRequest(); + var handlerMock = new Mock(MockBehavior.Strict); + handlerMock + .Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(string.Empty), // Simulate empty content + }) + .Verifiable(); - [TestMethod] - public async Task GetSubsidiaryDetails_ShouldReturnDefault_WhenResponseContentIsEmpty() + var httpClient = new HttpClient(handlerMock.Object) { - // Arrange - var request = new SubsidiaryDetailsRequest(); - var handlerMock = new Mock(MockBehavior.Strict); - handlerMock - .Protected() - .Setup>( - "SendAsync", - ItExpr.IsAny(), - ItExpr.IsAny()) - .ReturnsAsync(new HttpResponseMessage() - { - StatusCode = HttpStatusCode.OK, - Content = new StringContent(string.Empty), // Simulate empty content - }) - .Verifiable(); + BaseAddress = new Uri(_config.BaseUrl), + Timeout = TimeSpan.FromSeconds(_config.Timeout), + }; + var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); - var httpClient = new HttpClient(handlerMock.Object) - { - BaseAddress = new Uri(_config.BaseUrl), - Timeout = TimeSpan.FromSeconds(_config.Timeout), - }; - var sut = new CompanyDetailsApiClient(httpClient, NullLogger.Instance); - - // Act - var result = await sut.GetSubsidiaryDetails(request); + // Act + var result = await sut.GetSubsidiaryDetails(request); - // Assert - result.Should().BeNull(); // Since default for reference type is null - handlerMock.Protected().Verify( - "SendAsync", - Times.Once(), - ItExpr.Is(req => - req.Method == HttpMethod.Post && - req.RequestUri.ToString().EndsWith("api/subsidiary-details")), - ItExpr.IsAny()); - } + // Assert + result.Should().BeNull(); // Since default for reference type is null + handlerMock.Protected().Verify( + "SendAsync", + Times.Once(), + ItExpr.Is(req => + req.Method == HttpMethod.Post && + req.RequestUri.ToString().EndsWith("api/subsidiary-details")), + ItExpr.IsAny()); } } diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs index 8e5b027..64fe245 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Data/CompanyDetailsDataItemTests.cs @@ -3,81 +3,80 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; -namespace EPR.ProducerContentValidation.Application.UnitTests +namespace EPR.ProducerContentValidation.Application.UnitTests; + +[TestClass] +public class CompanyDetailsDataItemTests { - [TestClass] - public class CompanyDetailsDataItemTests + [TestMethod] + public void SerializeCompanyDetailsDataItem_ToJson_ContainsCorrectJsonPropertyNames() { - [TestMethod] - public void SerializeCompanyDetailsDataItem_ToJson_ContainsCorrectJsonPropertyNames() + // Arrange + var companyDetails = new CompanyDetailsDataItem { - // Arrange - var companyDetails = new CompanyDetailsDataItem - { - ReferenceNumber = "REF123", - CompaniesHouseNumber = "CHN456" - }; + ReferenceNumber = "REF123", + CompaniesHouseNumber = "CHN456" + }; - // Act - var json = JsonConvert.SerializeObject(companyDetails); + // Act + var json = JsonConvert.SerializeObject(companyDetails); - // Assert - json.Should().Contain("\"RN\":\"REF123\"") - .And.Contain("\"CHN\":\"CHN456\""); - } + // Assert + json.Should().Contain("\"RN\":\"REF123\"") + .And.Contain("\"CHN\":\"CHN456\""); + } - [TestMethod] - public void DeserializeCompanyDetailsDataItem_FromJson_HasCorrectPropertyValues() - { - // Arrange - var json = "{\"RN\":\"REF123\", \"CHN\":\"CHN456\"}"; + [TestMethod] + public void DeserializeCompanyDetailsDataItem_FromJson_HasCorrectPropertyValues() + { + // Arrange + var json = "{\"RN\":\"REF123\", \"CHN\":\"CHN456\"}"; - // Act - var companyDetails = JsonConvert.DeserializeObject(json); + // Act + var companyDetails = JsonConvert.DeserializeObject(json); - // Assert - companyDetails.Should().NotBeNull(); - companyDetails!.ReferenceNumber.Should().Be("REF123"); - companyDetails.CompaniesHouseNumber.Should().Be("CHN456"); - } + // Assert + companyDetails.Should().NotBeNull(); + companyDetails!.ReferenceNumber.Should().Be("REF123"); + companyDetails.CompaniesHouseNumber.Should().Be("CHN456"); + } - [TestMethod] - public void SerializeCompanyDetailsDataItem_NullValues_HasNullJsonProperties() + [TestMethod] + public void SerializeCompanyDetailsDataItem_NullValues_HasNullJsonProperties() + { + // Arrange + var companyDetails = new CompanyDetailsDataItem { - // Arrange - var companyDetails = new CompanyDetailsDataItem - { - ReferenceNumber = null, - CompaniesHouseNumber = null - }; + ReferenceNumber = null, + CompaniesHouseNumber = null + }; - // Act - var json = JsonConvert.SerializeObject(companyDetails); + // Act + var json = JsonConvert.SerializeObject(companyDetails); - // Assert - json.Should().Contain("\"RN\":null") - .And.Contain("\"CHN\":null"); - } + // Assert + json.Should().Contain("\"RN\":null") + .And.Contain("\"CHN\":null"); + } - [TestMethod] - public void DeserializeCompanyDetailsDataItem_NullOrMissingValues_PropertiesAreNull() - { - // Arrange - var jsonWithNulls = "{\"RN\":null, \"CHN\":null}"; - var jsonWithoutKeys = "{}"; + [TestMethod] + public void DeserializeCompanyDetailsDataItem_NullOrMissingValues_PropertiesAreNull() + { + // Arrange + var jsonWithNulls = "{\"RN\":null, \"CHN\":null}"; + var jsonWithoutKeys = "{}"; - // Act - var companyDetailsWithNulls = JsonConvert.DeserializeObject(jsonWithNulls); - var companyDetailsWithoutKeys = JsonConvert.DeserializeObject(jsonWithoutKeys); + // Act + var companyDetailsWithNulls = JsonConvert.DeserializeObject(jsonWithNulls); + var companyDetailsWithoutKeys = JsonConvert.DeserializeObject(jsonWithoutKeys); - // Assert - companyDetailsWithNulls.Should().NotBeNull(); - companyDetailsWithNulls!.ReferenceNumber.Should().BeNull(); - companyDetailsWithNulls.CompaniesHouseNumber.Should().BeNull(); + // Assert + companyDetailsWithNulls.Should().NotBeNull(); + companyDetailsWithNulls!.ReferenceNumber.Should().BeNull(); + companyDetailsWithNulls.CompaniesHouseNumber.Should().BeNull(); - companyDetailsWithoutKeys.Should().NotBeNull(); - companyDetailsWithoutKeys!.ReferenceNumber.Should().BeNull(); - companyDetailsWithoutKeys.CompaniesHouseNumber.Should().BeNull(); - } + companyDetailsWithoutKeys.Should().NotBeNull(); + companyDetailsWithoutKeys!.ReferenceNumber.Should().BeNull(); + companyDetailsWithoutKeys.CompaniesHouseNumber.Should().BeNull(); } } diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs index f482ae5..fbc452d 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/FindMatchingProducerTests.cs @@ -8,121 +8,120 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; -namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers; + +[TestClass] +public class FindMatchingProducerTests { - [TestClass] - public class FindMatchingProducerTests + private readonly Mock _organisationMatcherMock; + private readonly Mock _subsidiaryMatcherMock; + private readonly Mock _subsidiaryValidationEvaluatorMock; + private readonly FindMatchingProducer _findMatchingProducer; + + public FindMatchingProducerTests() + { + _organisationMatcherMock = new Mock(); + _subsidiaryMatcherMock = new Mock(); + _subsidiaryValidationEvaluatorMock = new Mock(); + + _findMatchingProducer = new FindMatchingProducer( + _organisationMatcherMock.Object, + _subsidiaryMatcherMock.Object, + _subsidiaryValidationEvaluatorMock.Object); + } + + [TestMethod] + public void Match_NoMatchingOrganisation_ReturnsNull() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1); + var response = new SubsidiaryDetailsResponse(); + + _organisationMatcherMock + .Setup(m => m.FindMatchingOrganisation(row, response)) + .Returns((SubsidiaryOrganisationDetail?)null); + + // Act + var result = _findMatchingProducer.Match(row, response, 1); + + // Assert + result.Should().BeNull(); + _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); + _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(It.IsAny(), It.IsAny()), Times.Never); + _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + } + + [TestMethod] + public void Match_NoMatchingSubsidiary_ReturnsNull() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1); + var response = new SubsidiaryDetailsResponse(); + var matchingOrg = new SubsidiaryOrganisationDetail(); + + _organisationMatcherMock + .Setup(m => m.FindMatchingOrganisation(row, response)) + .Returns(matchingOrg); + + _subsidiaryMatcherMock + .Setup(m => m.FindMatchingSubsidiary(row, matchingOrg)) + .Returns((SubsidiaryDetail?)null); + + // Act + var result = _findMatchingProducer.Match(row, response, 1); + + // Assert + result.Should().BeNull(); + _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); + _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(row, matchingOrg), Times.Once); + _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + } + + [TestMethod] + public void Match_MatchingOrganisationAndSubsidiary_ReturnsValidationResult() { - private readonly Mock _organisationMatcherMock; - private readonly Mock _subsidiaryMatcherMock; - private readonly Mock _subsidiaryValidationEvaluatorMock; - private readonly FindMatchingProducer _findMatchingProducer; - - public FindMatchingProducerTests() - { - _organisationMatcherMock = new Mock(); - _subsidiaryMatcherMock = new Mock(); - _subsidiaryValidationEvaluatorMock = new Mock(); - - _findMatchingProducer = new FindMatchingProducer( - _organisationMatcherMock.Object, - _subsidiaryMatcherMock.Object, - _subsidiaryValidationEvaluatorMock.Object); - } - - [TestMethod] - public void Match_NoMatchingOrganisation_ReturnsNull() - { - // Arrange - var row = ModelGenerator.CreateProducerRow(1); - var response = new SubsidiaryDetailsResponse(); - - _organisationMatcherMock - .Setup(m => m.FindMatchingOrganisation(row, response)) - .Returns((SubsidiaryOrganisationDetail?)null); - - // Act - var result = _findMatchingProducer.Match(row, response, 1); - - // Assert - result.Should().BeNull(); - _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); - _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(It.IsAny(), It.IsAny()), Times.Never); - _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); - } - - [TestMethod] - public void Match_NoMatchingSubsidiary_ReturnsNull() - { - // Arrange - var row = ModelGenerator.CreateProducerRow(1); - var response = new SubsidiaryDetailsResponse(); - var matchingOrg = new SubsidiaryOrganisationDetail(); - - _organisationMatcherMock - .Setup(m => m.FindMatchingOrganisation(row, response)) - .Returns(matchingOrg); - - _subsidiaryMatcherMock - .Setup(m => m.FindMatchingSubsidiary(row, matchingOrg)) - .Returns((SubsidiaryDetail?)null); - - // Act - var result = _findMatchingProducer.Match(row, response, 1); - - // Assert - result.Should().BeNull(); - _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); - _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(row, matchingOrg), Times.Once); - _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); - } - - [TestMethod] - public void Match_MatchingOrganisationAndSubsidiary_ReturnsValidationResult() - { - // Arrange - var row = ModelGenerator.CreateProducerRow(1); - var response = new SubsidiaryDetailsResponse(); - var matchingOrg = new SubsidiaryOrganisationDetail(); - var matchingSub = new SubsidiaryDetail(); - var expectedValidationResult = new ProducerValidationEventIssueRequest( - SubsidiaryId: "S123", - DataSubmissionPeriod: "2024-Q1", - RowNumber: 1, - ProducerId: "P456", - ProducerType: "Large", - ProducerSize: "Large", - WasteType: "Plastic", - PackagingCategory: "Containers", - MaterialType: "Polyethylene", - MaterialSubType: "High-Density", - FromHomeNation: "UK", - ToHomeNation: "Germany", - QuantityKg: "100", - QuantityUnits: "200", - BlobName: "ExampleBlobName", - ErrorCodes: new List { "E001", "E002" }); - - _organisationMatcherMock - .Setup(m => m.FindMatchingOrganisation(row, response)) - .Returns(matchingOrg); - - _subsidiaryMatcherMock - .Setup(m => m.FindMatchingSubsidiary(row, matchingOrg)) - .Returns(matchingSub); - - _subsidiaryValidationEvaluatorMock - .Setup(m => m.EvaluateSubsidiaryValidation(row, matchingSub, 1)) - .Returns(expectedValidationResult); - - // Act - var result = _findMatchingProducer.Match(row, response, 1); - - // Assert - result.Should().Be(expectedValidationResult); - _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); - _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(row, matchingOrg), Times.Once); - _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(row, matchingSub, 1), Times.Once); - } + // Arrange + var row = ModelGenerator.CreateProducerRow(1); + var response = new SubsidiaryDetailsResponse(); + var matchingOrg = new SubsidiaryOrganisationDetail(); + var matchingSub = new SubsidiaryDetail(); + var expectedValidationResult = new ProducerValidationEventIssueRequest( + SubsidiaryId: "S123", + DataSubmissionPeriod: "2024-Q1", + RowNumber: 1, + ProducerId: "P456", + ProducerType: "Large", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "Containers", + MaterialType: "Polyethylene", + MaterialSubType: "High-Density", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + BlobName: "ExampleBlobName", + ErrorCodes: new List { "E001", "E002" }); + + _organisationMatcherMock + .Setup(m => m.FindMatchingOrganisation(row, response)) + .Returns(matchingOrg); + + _subsidiaryMatcherMock + .Setup(m => m.FindMatchingSubsidiary(row, matchingOrg)) + .Returns(matchingSub); + + _subsidiaryValidationEvaluatorMock + .Setup(m => m.EvaluateSubsidiaryValidation(row, matchingSub, 1)) + .Returns(expectedValidationResult); + + // Act + var result = _findMatchingProducer.Match(row, response, 1); + + // Assert + result.Should().Be(expectedValidationResult); + _organisationMatcherMock.Verify(m => m.FindMatchingOrganisation(row, response), Times.Once); + _subsidiaryMatcherMock.Verify(m => m.FindMatchingSubsidiary(row, matchingOrg), Times.Once); + _subsidiaryValidationEvaluatorMock.Verify(m => m.EvaluateSubsidiaryValidation(row, matchingSub, 1), Times.Once); } } diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs index 5759154..cd31f28 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/OrganisationMatcherTests.cs @@ -4,126 +4,125 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers; + +[TestClass] +public class OrganisationMatcherTests { - [TestClass] - public class OrganisationMatcherTests + private readonly OrganisationMatcher _organisationMatcher; + + public OrganisationMatcherTests() { - private readonly OrganisationMatcher _organisationMatcher; + _organisationMatcher = new OrganisationMatcher(); + } - public OrganisationMatcherTests() + [TestMethod] + public void FindMatchingOrganisation_ShouldReturnOrganisation_WhenMatchExists() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: "Sub123", + DataSubmissionPeriod: "2023-Q1", + ProducerId: "Org456", + RowNumber: 1, + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubMaterialX", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + SubmissionPeriod: "2023"); + + var matchingOrg = new SubsidiaryOrganisationDetail { - _organisationMatcher = new OrganisationMatcher(); - } + OrganisationReference = "Org456" + }; + + var response = new SubsidiaryDetailsResponse + { + SubsidiaryOrganisationDetails = new List { matchingOrg } + }; + + // Act + var result = _organisationMatcher.FindMatchingOrganisation(row, response); + + // Assert + result.Should().NotBeNull(); + result!.OrganisationReference.Should().Be("Org456"); + } - [TestMethod] - public void FindMatchingOrganisation_ShouldReturnOrganisation_WhenMatchExists() + [TestMethod] + public void FindMatchingOrganisation_ShouldReturnNull_WhenNoMatchExists() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: "Sub123", + DataSubmissionPeriod: "2023-Q1", + ProducerId: "Org789", // This ID does not match any in the response + RowNumber: 1, + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubMaterialX", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + SubmissionPeriod: "2023"); + + var nonMatchingOrg = new SubsidiaryOrganisationDetail { - // Arrange - var row = new ProducerRow( - SubsidiaryId: "Sub123", - DataSubmissionPeriod: "2023-Q1", - ProducerId: "Org456", - RowNumber: 1, - ProducerType: "TypeA", - ProducerSize: "Large", - WasteType: "Plastic", - PackagingCategory: "CategoryA", - MaterialType: "MaterialX", - MaterialSubType: "SubMaterialX", - FromHomeNation: "UK", - ToHomeNation: "Germany", - QuantityKg: "100", - QuantityUnits: "200", - SubmissionPeriod: "2023"); - - var matchingOrg = new SubsidiaryOrganisationDetail - { - OrganisationReference = "Org456" - }; - - var response = new SubsidiaryDetailsResponse - { - SubsidiaryOrganisationDetails = new List { matchingOrg } - }; - - // Act - var result = _organisationMatcher.FindMatchingOrganisation(row, response); - - // Assert - result.Should().NotBeNull(); - result!.OrganisationReference.Should().Be("Org456"); - } - - [TestMethod] - public void FindMatchingOrganisation_ShouldReturnNull_WhenNoMatchExists() + OrganisationReference = "Org456" // Different ID than the row's ProducerId + }; + + var response = new SubsidiaryDetailsResponse { - // Arrange - var row = new ProducerRow( - SubsidiaryId: "Sub123", - DataSubmissionPeriod: "2023-Q1", - ProducerId: "Org789", // This ID does not match any in the response - RowNumber: 1, - ProducerType: "TypeA", - ProducerSize: "Large", - WasteType: "Plastic", - PackagingCategory: "CategoryA", - MaterialType: "MaterialX", - MaterialSubType: "SubMaterialX", - FromHomeNation: "UK", - ToHomeNation: "Germany", - QuantityKg: "100", - QuantityUnits: "200", - SubmissionPeriod: "2023"); - - var nonMatchingOrg = new SubsidiaryOrganisationDetail - { - OrganisationReference = "Org456" // Different ID than the row's ProducerId - }; - - var response = new SubsidiaryDetailsResponse - { - SubsidiaryOrganisationDetails = new List { nonMatchingOrg } - }; - - // Act - var result = _organisationMatcher.FindMatchingOrganisation(row, response); - - // Assert - result.Should().BeNull(); - } - - [TestMethod] - public void FindMatchingOrganisation_ShouldReturnNull_WhenResponseIsEmpty() + SubsidiaryOrganisationDetails = new List { nonMatchingOrg } + }; + + // Act + var result = _organisationMatcher.FindMatchingOrganisation(row, response); + + // Assert + result.Should().BeNull(); + } + + [TestMethod] + public void FindMatchingOrganisation_ShouldReturnNull_WhenResponseIsEmpty() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: "Sub123", + DataSubmissionPeriod: "2023-Q1", + ProducerId: "Org456", + RowNumber: 1, + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubMaterialX", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + SubmissionPeriod: "2023"); + + var response = new SubsidiaryDetailsResponse { - // Arrange - var row = new ProducerRow( - SubsidiaryId: "Sub123", - DataSubmissionPeriod: "2023-Q1", - ProducerId: "Org456", - RowNumber: 1, - ProducerType: "TypeA", - ProducerSize: "Large", - WasteType: "Plastic", - PackagingCategory: "CategoryA", - MaterialType: "MaterialX", - MaterialSubType: "SubMaterialX", - FromHomeNation: "UK", - ToHomeNation: "Germany", - QuantityKg: "100", - QuantityUnits: "200", - SubmissionPeriod: "2023"); - - var response = new SubsidiaryDetailsResponse - { - SubsidiaryOrganisationDetails = new List() // Empty list - }; - - // Act - var result = _organisationMatcher.FindMatchingOrganisation(row, response); - - // Assert - result.Should().BeNull(); - } + SubsidiaryOrganisationDetails = new List() // Empty list + }; + + // Act + var result = _organisationMatcher.FindMatchingOrganisation(row, response); + + // Assert + result.Should().BeNull(); } } diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs index 953cb31..239bea4 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventFormatterTests.cs @@ -4,137 +4,136 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers; + +[TestClass] +public class ProducerValidationEventFormatterTests { - [TestClass] - public class ProducerValidationEventFormatterTests - { - private readonly IProducerValidationEventIssueRequestFormatter _formatter; + private readonly IProducerValidationEventIssueRequestFormatter _formatter; - public ProducerValidationEventFormatterTests() - { - _formatter = new ProducerValidationEventIssueRequestFormatter(); - } + public ProducerValidationEventFormatterTests() + { + _formatter = new ProducerValidationEventIssueRequestFormatter(); + } - [TestMethod] - public void Format_ShouldReturnFormattedRequest_WithAllFieldsProvided() - { - // Arrange - var row = new ProducerRow( - SubsidiaryId: "Sub123", - DataSubmissionPeriod: "2023-Q1", - ProducerId: "Org456", - RowNumber: 1, - ProducerType: "TypeA", - ProducerSize: "Large", - WasteType: "Plastic", - PackagingCategory: "CategoryA", - MaterialType: "MaterialX", - MaterialSubType: "SubMaterialX", - FromHomeNation: "UK", - ToHomeNation: "Germany", - QuantityKg: "100", - QuantityUnits: "200", - SubmissionPeriod: "2023"); + [TestMethod] + public void Format_ShouldReturnFormattedRequest_WithAllFieldsProvided() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: "Sub123", + DataSubmissionPeriod: "2023-Q1", + ProducerId: "Org456", + RowNumber: 1, + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubMaterialX", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + SubmissionPeriod: "2023"); - string errorCode = "ErrorCode123"; + string errorCode = "ErrorCode123"; - // Act - var result = _formatter.Format(row, errorCode); + // Act + var result = _formatter.Format(row, errorCode); - // Assert - result.Should().NotBeNull(); - result.SubsidiaryId.Should().Be("Sub123"); - result.DataSubmissionPeriod.Should().Be("2023-Q1"); - result.RowNumber.Should().Be(1); - result.ProducerId.Should().Be("Org456"); - result.ProducerType.Should().Be("TypeA"); - result.ProducerSize.Should().Be("Large"); - result.WasteType.Should().Be("Plastic"); - result.PackagingCategory.Should().Be("CategoryA"); - result.MaterialType.Should().Be("MaterialX"); - result.MaterialSubType.Should().Be("SubMaterialX"); - result.FromHomeNation.Should().Be("UK"); - result.ToHomeNation.Should().Be("Germany"); - result.QuantityKg.Should().Be("100"); - result.QuantityUnits.Should().Be("200"); - result.ErrorCodes.Should().Contain(errorCode); - } + // Assert + result.Should().NotBeNull(); + result.SubsidiaryId.Should().Be("Sub123"); + result.DataSubmissionPeriod.Should().Be("2023-Q1"); + result.RowNumber.Should().Be(1); + result.ProducerId.Should().Be("Org456"); + result.ProducerType.Should().Be("TypeA"); + result.ProducerSize.Should().Be("Large"); + result.WasteType.Should().Be("Plastic"); + result.PackagingCategory.Should().Be("CategoryA"); + result.MaterialType.Should().Be("MaterialX"); + result.MaterialSubType.Should().Be("SubMaterialX"); + result.FromHomeNation.Should().Be("UK"); + result.ToHomeNation.Should().Be("Germany"); + result.QuantityKg.Should().Be("100"); + result.QuantityUnits.Should().Be("200"); + result.ErrorCodes.Should().Contain(errorCode); + } - [TestMethod] - public void Format_ShouldHandleNullFields_InProducerRow() - { - // Arrange - var row = new ProducerRow( - SubsidiaryId: null, - DataSubmissionPeriod: null, - ProducerId: null, - RowNumber: 1, - ProducerType: null, - ProducerSize: null, - WasteType: null, - PackagingCategory: null, - MaterialType: null, - MaterialSubType: null, - FromHomeNation: null, - ToHomeNation: null, - QuantityKg: null, - QuantityUnits: null, - SubmissionPeriod: "2023"); + [TestMethod] + public void Format_ShouldHandleNullFields_InProducerRow() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: null, + DataSubmissionPeriod: null, + ProducerId: null, + RowNumber: 1, + ProducerType: null, + ProducerSize: null, + WasteType: null, + PackagingCategory: null, + MaterialType: null, + MaterialSubType: null, + FromHomeNation: null, + ToHomeNation: null, + QuantityKg: null, + QuantityUnits: null, + SubmissionPeriod: "2023"); - string errorCode = "ErrorCode123"; + string errorCode = "ErrorCode123"; - // Act - var result = _formatter.Format(row, errorCode); + // Act + var result = _formatter.Format(row, errorCode); - // Assert - result.Should().NotBeNull(); - result.SubsidiaryId.Should().BeEmpty(); - result.DataSubmissionPeriod.Should().BeEmpty(); - result.RowNumber.Should().Be(1); - result.ProducerId.Should().BeEmpty(); - result.ProducerType.Should().BeEmpty(); - result.ProducerSize.Should().BeEmpty(); - result.WasteType.Should().BeEmpty(); - result.PackagingCategory.Should().BeEmpty(); - result.MaterialType.Should().BeEmpty(); - result.MaterialSubType.Should().BeEmpty(); - result.FromHomeNation.Should().BeEmpty(); - result.ToHomeNation.Should().BeEmpty(); - result.QuantityKg.Should().BeEmpty(); - result.QuantityUnits.Should().BeEmpty(); - result.ErrorCodes.Should().Contain(errorCode); - } + // Assert + result.Should().NotBeNull(); + result.SubsidiaryId.Should().BeEmpty(); + result.DataSubmissionPeriod.Should().BeEmpty(); + result.RowNumber.Should().Be(1); + result.ProducerId.Should().BeEmpty(); + result.ProducerType.Should().BeEmpty(); + result.ProducerSize.Should().BeEmpty(); + result.WasteType.Should().BeEmpty(); + result.PackagingCategory.Should().BeEmpty(); + result.MaterialType.Should().BeEmpty(); + result.MaterialSubType.Should().BeEmpty(); + result.FromHomeNation.Should().BeEmpty(); + result.ToHomeNation.Should().BeEmpty(); + result.QuantityKg.Should().BeEmpty(); + result.QuantityUnits.Should().BeEmpty(); + result.ErrorCodes.Should().Contain(errorCode); + } - [TestMethod] - public void Format_ShouldReturnSingleErrorCode() - { - // Arrange - var row = new ProducerRow( - SubsidiaryId: "Sub123", - DataSubmissionPeriod: "2023-Q1", - ProducerId: "Org456", - RowNumber: 1, - ProducerType: "TypeA", - ProducerSize: "Large", - WasteType: "Plastic", - PackagingCategory: "CategoryA", - MaterialType: "MaterialX", - MaterialSubType: "SubMaterialX", - FromHomeNation: "UK", - ToHomeNation: "Germany", - QuantityKg: "100", - QuantityUnits: "200", - SubmissionPeriod: "2023"); + [TestMethod] + public void Format_ShouldReturnSingleErrorCode() + { + // Arrange + var row = new ProducerRow( + SubsidiaryId: "Sub123", + DataSubmissionPeriod: "2023-Q1", + ProducerId: "Org456", + RowNumber: 1, + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "Plastic", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubMaterialX", + FromHomeNation: "UK", + ToHomeNation: "Germany", + QuantityKg: "100", + QuantityUnits: "200", + SubmissionPeriod: "2023"); - string errorCode = "SingleError"; + string errorCode = "SingleError"; - // Act - var result = _formatter.Format(row, errorCode); + // Act + var result = _formatter.Format(row, errorCode); - // Assert - result.ErrorCodes.Should().HaveCount(1, "Expected exactly one error code in the list.") - .And.ContainSingle(e => e == "SingleError"); - } + // Assert + result.ErrorCodes.Should().HaveCount(1, "Expected exactly one error code in the list.") + .And.ContainSingle(e => e == "SingleError"); } } diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventIssueRequestMergerTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventIssueRequestMergerTests.cs index 89324b4..440c6bb 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventIssueRequestMergerTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ProducerValidationEventIssueRequestMergerTests.cs @@ -3,268 +3,267 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers; + +[TestClass] +public class ProducerValidationEventIssueRequestMergerTests { - [TestClass] - public class ProducerValidationEventIssueRequestMergerTests + [TestMethod] + public void MergeRequests_IdenticalEntries_ShouldMergeErrorCodes() { - [TestMethod] - public void MergeRequests_IdenticalEntries_ShouldMergeErrorCodes() - { - // Arrange - var request1 = new ProducerValidationEventIssueRequest( - "123", - "2024-01", - 1, - "Producer1", - "TypeA", - "Large", - "WasteType", - "CategoryA", - "MaterialX", - "SubTypeX", - "Nation1", - "Nation2", - "100", - "Units", - ErrorCodes: new List { "Error1" }); - var request2 = new ProducerValidationEventIssueRequest( - "123", - "2024-01", - 1, - "Producer1", - "TypeA", - "Large", - "WasteType", - "CategoryA", - "MaterialX", - "SubTypeX", - "Nation1", - "Nation2", - "100", - "Units", - ErrorCodes: new List { "Error2" }); + // Arrange + var request1 = new ProducerValidationEventIssueRequest( + "123", + "2024-01", + 1, + "Producer1", + "TypeA", + "Large", + "WasteType", + "CategoryA", + "MaterialX", + "SubTypeX", + "Nation1", + "Nation2", + "100", + "Units", + ErrorCodes: new List { "Error1" }); + var request2 = new ProducerValidationEventIssueRequest( + "123", + "2024-01", + 1, + "Producer1", + "TypeA", + "Large", + "WasteType", + "CategoryA", + "MaterialX", + "SubTypeX", + "Nation1", + "Nation2", + "100", + "Units", + ErrorCodes: new List { "Error2" }); - var list1 = new List { request1 }; - var list2 = new List { request2 }; + var list1 = new List { request1 }; + var list2 = new List { request2 }; - // Act - var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); - // Assert - result.Should().HaveCount(1); - result[0].ErrorCodes.Should().BeEquivalentTo(new List { "Error1", "Error2" }); - } + // Assert + result.Should().HaveCount(1); + result[0].ErrorCodes.Should().BeEquivalentTo(new List { "Error1", "Error2" }); + } - [TestMethod] - public void MergeRequests_UniqueEntries_ShouldRetainBothEntries() - { - // Arrange - var request1 = new ProducerValidationEventIssueRequest( - "123", - "2024-01", - 1, - "Producer1", - "TypeA", - "Large", - "WasteType", - "CategoryA", - "MaterialX", - "SubTypeX", - "Nation1", - "Nation2", - "100", - "Units", - ErrorCodes: new List { "Error1" }); - var request2 = new ProducerValidationEventIssueRequest( - "456", - "2024-02", - 2, - "Producer2", - "TypeB", - "Medium", - "WasteType", - "CategoryB", - "MaterialY", - "SubTypeY", - "Nation3", - "Nation4", - "200", - "Units", - ErrorCodes: new List { "Error3" }); + [TestMethod] + public void MergeRequests_UniqueEntries_ShouldRetainBothEntries() + { + // Arrange + var request1 = new ProducerValidationEventIssueRequest( + "123", + "2024-01", + 1, + "Producer1", + "TypeA", + "Large", + "WasteType", + "CategoryA", + "MaterialX", + "SubTypeX", + "Nation1", + "Nation2", + "100", + "Units", + ErrorCodes: new List { "Error1" }); + var request2 = new ProducerValidationEventIssueRequest( + "456", + "2024-02", + 2, + "Producer2", + "TypeB", + "Medium", + "WasteType", + "CategoryB", + "MaterialY", + "SubTypeY", + "Nation3", + "Nation4", + "200", + "Units", + ErrorCodes: new List { "Error3" }); - var list1 = new List { request1 }; - var list2 = new List { request2 }; + var list1 = new List { request1 }; + var list2 = new List { request2 }; - // Act - var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); - // Assert - result.Should().HaveCount(2); - result.Should().ContainEquivalentOf(request1); - result.Should().ContainEquivalentOf(request2); - } + // Assert + result.Should().HaveCount(2); + result.Should().ContainEquivalentOf(request1); + result.Should().ContainEquivalentOf(request2); + } - [TestMethod] - public void MergeRequests_MixedEntries_ShouldMergeIdenticalAndRetainUnique() - { - // Arrange - var request1 = new ProducerValidationEventIssueRequest( - SubsidiaryId: "123", - DataSubmissionPeriod: "2024-01", - RowNumber: 1, - ProducerId: "Producer1", - ProducerType: "TypeA", - ProducerSize: "Large", - WasteType: "WasteType", - PackagingCategory: "CategoryA", - MaterialType: "MaterialX", - MaterialSubType: "SubTypeX", - FromHomeNation: "Nation1", - ToHomeNation: "Nation2", - QuantityKg: "100", - QuantityUnits: "Units", - ErrorCodes: new List { "Error1" }); + [TestMethod] + public void MergeRequests_MixedEntries_ShouldMergeIdenticalAndRetainUnique() + { + // Arrange + var request1 = new ProducerValidationEventIssueRequest( + SubsidiaryId: "123", + DataSubmissionPeriod: "2024-01", + RowNumber: 1, + ProducerId: "Producer1", + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "WasteType", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubTypeX", + FromHomeNation: "Nation1", + ToHomeNation: "Nation2", + QuantityKg: "100", + QuantityUnits: "Units", + ErrorCodes: new List { "Error1" }); - var request2 = new ProducerValidationEventIssueRequest( - SubsidiaryId: "123", - DataSubmissionPeriod: "2024-01", - RowNumber: 1, - ProducerId: "Producer1", - ProducerType: "TypeA", - ProducerSize: "Large", - WasteType: "WasteType", - PackagingCategory: "CategoryA", - MaterialType: "MaterialX", - MaterialSubType: "SubTypeX", - FromHomeNation: "Nation1", - ToHomeNation: "Nation2", - QuantityKg: "100", - QuantityUnits: "Units", - ErrorCodes: new List { "Error2" }); + var request2 = new ProducerValidationEventIssueRequest( + SubsidiaryId: "123", + DataSubmissionPeriod: "2024-01", + RowNumber: 1, + ProducerId: "Producer1", + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "WasteType", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubTypeX", + FromHomeNation: "Nation1", + ToHomeNation: "Nation2", + QuantityKg: "100", + QuantityUnits: "Units", + ErrorCodes: new List { "Error2" }); - var uniqueRequest = new ProducerValidationEventIssueRequest( - SubsidiaryId: "789", - DataSubmissionPeriod: "2024-03", - RowNumber: 3, - ProducerId: "Producer3", - ProducerType: "TypeC", - ProducerSize: "Small", - WasteType: "WasteType", - PackagingCategory: "CategoryC", - MaterialType: "MaterialZ", - MaterialSubType: "SubTypeZ", - FromHomeNation: "Nation5", - ToHomeNation: "Nation6", - QuantityKg: "300", - QuantityUnits: "Units", - ErrorCodes: new List { "Error4" }); + var uniqueRequest = new ProducerValidationEventIssueRequest( + SubsidiaryId: "789", + DataSubmissionPeriod: "2024-03", + RowNumber: 3, + ProducerId: "Producer3", + ProducerType: "TypeC", + ProducerSize: "Small", + WasteType: "WasteType", + PackagingCategory: "CategoryC", + MaterialType: "MaterialZ", + MaterialSubType: "SubTypeZ", + FromHomeNation: "Nation5", + ToHomeNation: "Nation6", + QuantityKg: "300", + QuantityUnits: "Units", + ErrorCodes: new List { "Error4" }); - var list1 = new List { request1, uniqueRequest }; - var list2 = new List { request2 }; + var list1 = new List { request1, uniqueRequest }; + var list2 = new List { request2 }; - // Act - var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); - // Assert - result.Should().HaveCount(2); - result.Should().ContainSingle(r => r.SubsidiaryId == "123" && r.ErrorCodes.Contains("Error1") && r.ErrorCodes.Contains("Error2")); - result.Should().ContainEquivalentOf(uniqueRequest); - } + // Assert + result.Should().HaveCount(2); + result.Should().ContainSingle(r => r.SubsidiaryId == "123" && r.ErrorCodes.Contains("Error1") && r.ErrorCodes.Contains("Error2")); + result.Should().ContainEquivalentOf(uniqueRequest); + } - [TestMethod] - public void MergeRequests_EmptyList_ShouldReturnOtherList() - { - // Arrange - var request = new ProducerValidationEventIssueRequest( - SubsidiaryId: "123", - DataSubmissionPeriod: "2024-01", - RowNumber: 1, - ProducerId: "Producer1", - ProducerType: "TypeA", - ProducerSize: "Large", - WasteType: "WasteType", - PackagingCategory: "CategoryA", - MaterialType: "MaterialX", - MaterialSubType: "SubTypeX", - FromHomeNation: "Nation1", - ToHomeNation: "Nation2", - QuantityKg: "100", - QuantityUnits: "Units", - ErrorCodes: new List { "Error1" }); + [TestMethod] + public void MergeRequests_EmptyList_ShouldReturnOtherList() + { + // Arrange + var request = new ProducerValidationEventIssueRequest( + SubsidiaryId: "123", + DataSubmissionPeriod: "2024-01", + RowNumber: 1, + ProducerId: "Producer1", + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "WasteType", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubTypeX", + FromHomeNation: "Nation1", + ToHomeNation: "Nation2", + QuantityKg: "100", + QuantityUnits: "Units", + ErrorCodes: new List { "Error1" }); - var list1 = new List { request }; - var list2 = new List(); + var list1 = new List { request }; + var list2 = new List(); - // Act - var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); - // Assert - result.Should().HaveCount(1); - result.Should().ContainEquivalentOf(request); - } + // Assert + result.Should().HaveCount(1); + result.Should().ContainEquivalentOf(request); + } - [TestMethod] - public void MergeRequests_BothEmpty_ShouldReturnEmpty() - { - // Arrange - var list1 = new List(); - var list2 = new List(); + [TestMethod] + public void MergeRequests_BothEmpty_ShouldReturnEmpty() + { + // Arrange + var list1 = new List(); + var list2 = new List(); - // Act - var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); - // Assert - result.Should().BeEmpty(); - } + // Assert + result.Should().BeEmpty(); + } - [TestMethod] - public void MergeRequests_NullErrorCodes_ShouldHandleGracefully() - { - // Arrange - var request1 = new ProducerValidationEventIssueRequest( - SubsidiaryId: "123", - DataSubmissionPeriod: "2024-01", - RowNumber: 1, - ProducerId: "Producer1", - ProducerType: "TypeA", - ProducerSize: "Large", - WasteType: "WasteType", - PackagingCategory: "CategoryA", - MaterialType: "MaterialX", - MaterialSubType: "SubTypeX", - FromHomeNation: "Nation1", - ToHomeNation: "Nation2", - QuantityKg: "100", - QuantityUnits: "Units", - ErrorCodes: null); + [TestMethod] + public void MergeRequests_NullErrorCodes_ShouldHandleGracefully() + { + // Arrange + var request1 = new ProducerValidationEventIssueRequest( + SubsidiaryId: "123", + DataSubmissionPeriod: "2024-01", + RowNumber: 1, + ProducerId: "Producer1", + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "WasteType", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubTypeX", + FromHomeNation: "Nation1", + ToHomeNation: "Nation2", + QuantityKg: "100", + QuantityUnits: "Units", + ErrorCodes: null); - var request2 = new ProducerValidationEventIssueRequest( - SubsidiaryId: "123", - DataSubmissionPeriod: "2024-01", - RowNumber: 1, - ProducerId: "Producer1", - ProducerType: "TypeA", - ProducerSize: "Large", - WasteType: "WasteType", - PackagingCategory: "CategoryA", - MaterialType: "MaterialX", - MaterialSubType: "SubTypeX", - FromHomeNation: "Nation1", - ToHomeNation: "Nation2", - QuantityKg: "100", - QuantityUnits: "Units", - ErrorCodes: new List { "Error2" }); + var request2 = new ProducerValidationEventIssueRequest( + SubsidiaryId: "123", + DataSubmissionPeriod: "2024-01", + RowNumber: 1, + ProducerId: "Producer1", + ProducerType: "TypeA", + ProducerSize: "Large", + WasteType: "WasteType", + PackagingCategory: "CategoryA", + MaterialType: "MaterialX", + MaterialSubType: "SubTypeX", + FromHomeNation: "Nation1", + ToHomeNation: "Nation2", + QuantityKg: "100", + QuantityUnits: "Units", + ErrorCodes: new List { "Error2" }); - var list1 = new List { request1 }; - var list2 = new List { request2 }; + var list1 = new List { request1 }; + var list2 = new List { request2 }; - // Act - var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); + // Act + var result = ProducerValidationEventIssueRequestMerger.MergeRequests(list1, list2); - // Assert - result.Should().HaveCount(1); - result[0].ErrorCodes.Should().BeEquivalentTo(new List { "Error2" }); - } + // Assert + result.Should().HaveCount(1); + result[0].ErrorCodes.Should().BeEquivalentTo(new List { "Error2" }); } } diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs index 9920490..4a252cd 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/RequestValidatorTests.cs @@ -3,78 +3,77 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers; + +[TestClass] +public class RequestValidatorTests { - [TestClass] - public class RequestValidatorTests - { - private RequestValidator _validator; + private RequestValidator _validator; - [TestInitialize] - public void Setup() - { - _validator = new RequestValidator(); - } + [TestInitialize] + public void Setup() + { + _validator = new RequestValidator(); + } - [TestMethod] - public void IsInvalidRequest_ShouldReturnTrue_WhenRequestIsNull() - { - // Act - var result = _validator.IsInvalidRequest(null); + [TestMethod] + public void IsInvalidRequest_ShouldReturnTrue_WhenRequestIsNull() + { + // Act + var result = _validator.IsInvalidRequest(null); - // Assert - result.Should().BeTrue("because the request is null and should be considered invalid."); - } + // Assert + result.Should().BeTrue("because the request is null and should be considered invalid."); + } - [TestMethod] - public void IsInvalidRequest_ShouldReturnTrue_WhenSubsidiaryOrganisationDetailsIsNull() + [TestMethod] + public void IsInvalidRequest_ShouldReturnTrue_WhenSubsidiaryOrganisationDetailsIsNull() + { + // Arrange + var request = new SubsidiaryDetailsRequest { - // Arrange - var request = new SubsidiaryDetailsRequest - { - SubsidiaryOrganisationDetails = null - }; + SubsidiaryOrganisationDetails = null + }; - // Act - var result = _validator.IsInvalidRequest(request); + // Act + var result = _validator.IsInvalidRequest(request); - // Assert - result.Should().BeTrue("because SubsidiaryOrganisationDetails is null and the request should be invalid."); - } + // Assert + result.Should().BeTrue("because SubsidiaryOrganisationDetails is null and the request should be invalid."); + } - [TestMethod] - public void IsInvalidRequest_ShouldReturnTrue_WhenSubsidiaryOrganisationDetailsIsEmpty() + [TestMethod] + public void IsInvalidRequest_ShouldReturnTrue_WhenSubsidiaryOrganisationDetailsIsEmpty() + { + // Arrange + var request = new SubsidiaryDetailsRequest { - // Arrange - var request = new SubsidiaryDetailsRequest - { - SubsidiaryOrganisationDetails = new List() - }; + SubsidiaryOrganisationDetails = new List() + }; - // Act - var result = _validator.IsInvalidRequest(request); + // Act + var result = _validator.IsInvalidRequest(request); - // Assert - result.Should().BeTrue("because SubsidiaryOrganisationDetails is empty and should be considered invalid."); - } + // Assert + result.Should().BeTrue("because SubsidiaryOrganisationDetails is empty and should be considered invalid."); + } - [TestMethod] - public void IsInvalidRequest_ShouldReturnFalse_WhenSubsidiaryOrganisationDetailsIsNotEmpty() + [TestMethod] + public void IsInvalidRequest_ShouldReturnFalse_WhenSubsidiaryOrganisationDetailsIsNotEmpty() + { + // Arrange + var request = new SubsidiaryDetailsRequest { - // Arrange - var request = new SubsidiaryDetailsRequest + SubsidiaryOrganisationDetails = new List { - SubsidiaryOrganisationDetails = new List - { - new SubsidiaryOrganisationDetail { OrganisationReference = "Org1" } - } - }; + new SubsidiaryOrganisationDetail { OrganisationReference = "Org1" } + } + }; - // Act - var result = _validator.IsInvalidRequest(request); + // Act + var result = _validator.IsInvalidRequest(request); - // Assert - result.Should().BeFalse("because SubsidiaryOrganisationDetails contains entries and should be considered valid."); - } + // Assert + result.Should().BeFalse("because SubsidiaryOrganisationDetails contains entries and should be considered valid."); } } diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs index 09c9103..cea2322 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryMatcherTests.cs @@ -4,176 +4,175 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers; + +[TestClass] +public class SubsidiaryMatcherTests { - [TestClass] - public class SubsidiaryMatcherTests + private SubsidiaryMatcher _matcher; + + [TestInitialize] + public void SetUp() { - private SubsidiaryMatcher _matcher; + _matcher = new SubsidiaryMatcher(); + } - [TestInitialize] - public void SetUp() + [TestMethod] + public void FindMatchingSubsidiary_ShouldReturnMatchingSubsidiary_WhenReferenceNumberMatches() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with { - _matcher = new SubsidiaryMatcher(); - } + SubsidiaryId = "123", + DataSubmissionPeriod = "2024Q1", + ProducerId = "456", + RowNumber = 1, + ProducerType = "Large", + ProducerSize = "1000", + WasteType = "Plastic", + PackagingCategory = "CategoryA", + MaterialType = "TypeA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "500", + QuantityUnits = "10" + }; + + var subsidiaryDetails = new List + { + new SubsidiaryDetail { ReferenceNumber = "123", SubsidiaryExists = true }, + new SubsidiaryDetail { ReferenceNumber = "456", SubsidiaryExists = true } + }; - [TestMethod] - public void FindMatchingSubsidiary_ShouldReturnMatchingSubsidiary_WhenReferenceNumberMatches() + var org = new SubsidiaryOrganisationDetail { - // Arrange - var row = ModelGenerator.CreateProducerRow(1) with - { - SubsidiaryId = "123", - DataSubmissionPeriod = "2024Q1", - ProducerId = "456", - RowNumber = 1, - ProducerType = "Large", - ProducerSize = "1000", - WasteType = "Plastic", - PackagingCategory = "CategoryA", - MaterialType = "TypeA", - MaterialSubType = "SubTypeA", - FromHomeNation = "NationA", - ToHomeNation = "NationB", - QuantityKg = "500", - QuantityUnits = "10" - }; - - var subsidiaryDetails = new List - { - new SubsidiaryDetail { ReferenceNumber = "123", SubsidiaryExists = true }, - new SubsidiaryDetail { ReferenceNumber = "456", SubsidiaryExists = true } - }; - - var org = new SubsidiaryOrganisationDetail - { - OrganisationReference = "456", - SubsidiaryDetails = subsidiaryDetails - }; - - // Act - var result = _matcher.FindMatchingSubsidiary(row, org); - - // Assert - result.Should().NotBeNull("because there is a matching subsidiary with the reference number '123'"); - result?.ReferenceNumber.Should().Be("123", "because the reference number should match the subsidiary ID in the row."); - } - - [TestMethod] - public void FindMatchingSubsidiary_ShouldReturnNull_WhenNoMatchingReferenceNumber() + OrganisationReference = "456", + SubsidiaryDetails = subsidiaryDetails + }; + + // Act + var result = _matcher.FindMatchingSubsidiary(row, org); + + // Assert + result.Should().NotBeNull("because there is a matching subsidiary with the reference number '123'"); + result?.ReferenceNumber.Should().Be("123", "because the reference number should match the subsidiary ID in the row."); + } + + [TestMethod] + public void FindMatchingSubsidiary_ShouldReturnNull_WhenNoMatchingReferenceNumber() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with { - // Arrange - var row = ModelGenerator.CreateProducerRow(1) with - { - SubsidiaryId = "789", - DataSubmissionPeriod = "2024Q1", - ProducerId = "456", - RowNumber = 1, - ProducerType = "Large", - ProducerSize = "1000", - WasteType = "Plastic", - PackagingCategory = "CategoryA", - MaterialType = "TypeA", - MaterialSubType = "SubTypeA", - FromHomeNation = "NationA", - ToHomeNation = "NationB", - QuantityKg = "500", - QuantityUnits = "10" - }; - - var subsidiaryDetails = new List - { - new SubsidiaryDetail { ReferenceNumber = "123", SubsidiaryExists = true }, - new SubsidiaryDetail { ReferenceNumber = "456", SubsidiaryExists = true } - }; - - var org = new SubsidiaryOrganisationDetail - { - OrganisationReference = "456", - SubsidiaryDetails = subsidiaryDetails - }; - - // Act - var result = _matcher.FindMatchingSubsidiary(row, org); - - // Assert - result.Should().BeNull("because there is no matching subsidiary with the reference number '789'."); - } - - [TestMethod] - public void FindMatchingSubsidiary_ShouldReturnNull_WhenSubsidiaryDetailsIsEmpty() + SubsidiaryId = "789", + DataSubmissionPeriod = "2024Q1", + ProducerId = "456", + RowNumber = 1, + ProducerType = "Large", + ProducerSize = "1000", + WasteType = "Plastic", + PackagingCategory = "CategoryA", + MaterialType = "TypeA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "500", + QuantityUnits = "10" + }; + + var subsidiaryDetails = new List { - // Arrange - var row = ModelGenerator.CreateProducerRow(1) with - { - SubsidiaryId = "123", - DataSubmissionPeriod = "2024Q1", - ProducerId = "456", - RowNumber = 1, - ProducerType = "Large", - ProducerSize = "1000", - WasteType = "Plastic", - PackagingCategory = "CategoryA", - MaterialType = "TypeA", - MaterialSubType = "SubTypeA", - FromHomeNation = "NationA", - ToHomeNation = "NationB", - QuantityKg = "500", - QuantityUnits = "10" - }; - - var org = new SubsidiaryOrganisationDetail - { - OrganisationReference = "456", - SubsidiaryDetails = new List() - }; - - // Act - var result = _matcher.FindMatchingSubsidiary(row, org); - - // Assert - result.Should().BeNull("because SubsidiaryDetails is empty and should not contain a matching subsidiary."); - } - - [TestMethod] - public void FindMatchingSubsidiary_ShouldReturnNull_WhenSubsidiaryIdIsNull() + new SubsidiaryDetail { ReferenceNumber = "123", SubsidiaryExists = true }, + new SubsidiaryDetail { ReferenceNumber = "456", SubsidiaryExists = true } + }; + + var org = new SubsidiaryOrganisationDetail { - // Arrange - var row = ModelGenerator.CreateProducerRow(1) with - { - SubsidiaryId = null, - DataSubmissionPeriod = "2024Q1", - ProducerId = "456", - RowNumber = 1, - ProducerType = "Large", - ProducerSize = "1000", - WasteType = "Plastic", - PackagingCategory = "CategoryA", - MaterialType = "TypeA", - MaterialSubType = "SubTypeA", - FromHomeNation = "NationA", - ToHomeNation = "NationB", - QuantityKg = "500", - QuantityUnits = "10" - }; - - var subsidiaryDetails = new List - { - new SubsidiaryDetail { ReferenceNumber = "123", SubsidiaryExists = true }, - new SubsidiaryDetail { ReferenceNumber = "456", SubsidiaryExists = true } - }; - - var org = new SubsidiaryOrganisationDetail - { - OrganisationReference = "456", - SubsidiaryDetails = subsidiaryDetails - }; - - // Act - var result = _matcher.FindMatchingSubsidiary(row, org); - - // Assert - result.Should().BeNull("because the row's SubsidiaryId is null and cannot match any reference number."); - } + OrganisationReference = "456", + SubsidiaryDetails = subsidiaryDetails + }; + + // Act + var result = _matcher.FindMatchingSubsidiary(row, org); + + // Assert + result.Should().BeNull("because there is no matching subsidiary with the reference number '789'."); + } + + [TestMethod] + public void FindMatchingSubsidiary_ShouldReturnNull_WhenSubsidiaryDetailsIsEmpty() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "123", + DataSubmissionPeriod = "2024Q1", + ProducerId = "456", + RowNumber = 1, + ProducerType = "Large", + ProducerSize = "1000", + WasteType = "Plastic", + PackagingCategory = "CategoryA", + MaterialType = "TypeA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "500", + QuantityUnits = "10" + }; + + var org = new SubsidiaryOrganisationDetail + { + OrganisationReference = "456", + SubsidiaryDetails = new List() + }; + + // Act + var result = _matcher.FindMatchingSubsidiary(row, org); + + // Assert + result.Should().BeNull("because SubsidiaryDetails is empty and should not contain a matching subsidiary."); + } + + [TestMethod] + public void FindMatchingSubsidiary_ShouldReturnNull_WhenSubsidiaryIdIsNull() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = null, + DataSubmissionPeriod = "2024Q1", + ProducerId = "456", + RowNumber = 1, + ProducerType = "Large", + ProducerSize = "1000", + WasteType = "Plastic", + PackagingCategory = "CategoryA", + MaterialType = "TypeA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "500", + QuantityUnits = "10" + }; + + var subsidiaryDetails = new List + { + new SubsidiaryDetail { ReferenceNumber = "123", SubsidiaryExists = true }, + new SubsidiaryDetail { ReferenceNumber = "456", SubsidiaryExists = true } + }; + + var org = new SubsidiaryOrganisationDetail + { + OrganisationReference = "456", + SubsidiaryDetails = subsidiaryDetails + }; + + // Act + var result = _matcher.FindMatchingSubsidiary(row, org); + + // Assert + result.Should().BeNull("because the row's SubsidiaryId is null and cannot match any reference number."); } } diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs index 0b5bfea..96099ad 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs @@ -10,155 +10,154 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; -namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers; + +[TestClass] +public class SubsidiaryValidationEvaluatorTests { - [TestClass] - public class SubsidiaryValidationEvaluatorTests + private Mock _mockLogger; + private Mock _mockFormatter; + private SubsidiaryValidationEvaluator _evaluator; + + [TestInitialize] + public void Setup() { - private Mock _mockLogger; - private Mock _mockFormatter; - private SubsidiaryValidationEvaluator _evaluator; + _mockLogger = new Mock(); + _mockFormatter = new Mock(); + _evaluator = new SubsidiaryValidationEvaluator(_mockLogger.Object, _mockFormatter.Object); + } - [TestInitialize] - public void Setup() + [TestMethod] + public void EvaluateSubsidiaryValidation_SubsidiaryDoesNotExist_ShouldLogWarningAndReturnFormattedRequest() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with { - _mockLogger = new Mock(); - _mockFormatter = new Mock(); - _evaluator = new SubsidiaryValidationEvaluator(_mockLogger.Object, _mockFormatter.Object); - } + SubsidiaryId = "123", + DataSubmissionPeriod = "2024-01", + ProducerId = "Producer1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteType", + PackagingCategory = "CategoryA", + MaterialType = "MaterialX", + MaterialSubType = "SubTypeX", + FromHomeNation = "Nation1", + ToHomeNation = "Nation2", + QuantityKg = "100", + QuantityUnits = "Units" + }; + var subsidiary = new SubsidiaryDetail { SubsidiaryExists = false, SubsidiaryBelongsToAnyOtherOrganisation = true }; + var expectedRequest = new ProducerValidationEventIssueRequest( + row.SubsidiaryId, + row.DataSubmissionPeriod, + row.RowNumber, + row.ProducerId, + row.ProducerType, + row.ProducerSize, + row.WasteType, + row.PackagingCategory, + row.MaterialType, + row.MaterialSubType, + row.FromHomeNation, + row.ToHomeNation, + row.QuantityKg, + row.QuantityUnits, + ErrorCodes: new List { ErrorCode.SubsidiaryIdDoesNotExist }); + + _mockFormatter.Setup(f => f.Format(row, ErrorCode.SubsidiaryIdDoesNotExist)).Returns(expectedRequest); + + // Act + var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); + + // Assert + result.Should().NotBeNull("because a request should be returned if the subsidiary does not exist.") + .And.BeEquivalentTo(expectedRequest, "because the returned request should match the expected formatted request."); + + _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdDoesNotExist), Times.Once); + } - [TestMethod] - public void EvaluateSubsidiaryValidation_SubsidiaryDoesNotExist_ShouldLogWarningAndReturnFormattedRequest() - { - // Arrange - var row = ModelGenerator.CreateProducerRow(1) with - { - SubsidiaryId = "123", - DataSubmissionPeriod = "2024-01", - ProducerId = "Producer1", - RowNumber = 1, - ProducerType = "TypeA", - ProducerSize = "Large", - WasteType = "WasteType", - PackagingCategory = "CategoryA", - MaterialType = "MaterialX", - MaterialSubType = "SubTypeX", - FromHomeNation = "Nation1", - ToHomeNation = "Nation2", - QuantityKg = "100", - QuantityUnits = "Units" - }; - var subsidiary = new SubsidiaryDetail { SubsidiaryExists = false, SubsidiaryBelongsToAnyOtherOrganisation = true }; - var expectedRequest = new ProducerValidationEventIssueRequest( - row.SubsidiaryId, - row.DataSubmissionPeriod, - row.RowNumber, - row.ProducerId, - row.ProducerType, - row.ProducerSize, - row.WasteType, - row.PackagingCategory, - row.MaterialType, - row.MaterialSubType, - row.FromHomeNation, - row.ToHomeNation, - row.QuantityKg, - row.QuantityUnits, - ErrorCodes: new List { ErrorCode.SubsidiaryIdDoesNotExist }); - - _mockFormatter.Setup(f => f.Format(row, ErrorCode.SubsidiaryIdDoesNotExist)).Returns(expectedRequest); - - // Act - var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); - - // Assert - result.Should().NotBeNull("because a request should be returned if the subsidiary does not exist.") - .And.BeEquivalentTo(expectedRequest, "because the returned request should match the expected formatted request."); - - _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdDoesNotExist), Times.Once); - } - - [TestMethod] - public void EvaluateSubsidiaryValidation_SubsidiaryBelongsToDifferentOrganisation_ShouldLogWarningAndReturnFormattedRequest() + [TestMethod] + public void EvaluateSubsidiaryValidation_SubsidiaryBelongsToDifferentOrganisation_ShouldLogWarningAndReturnFormattedRequest() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with { - // Arrange - var row = ModelGenerator.CreateProducerRow(1) with - { - SubsidiaryId = "123", - DataSubmissionPeriod = "2024-01", - ProducerId = "Producer1", - RowNumber = 1, - ProducerType = "TypeA", - ProducerSize = "Large", - WasteType = "WasteType", - PackagingCategory = "CategoryA", - MaterialType = "MaterialX", - MaterialSubType = "SubTypeX", - FromHomeNation = "Nation1", - ToHomeNation = "Nation2", - QuantityKg = "100", - QuantityUnits = "Units" - }; - var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToAnyOtherOrganisation = true }; - var expectedRequest = new ProducerValidationEventIssueRequest( - row.SubsidiaryId, - row.DataSubmissionPeriod, - row.RowNumber, - row.ProducerId, - row.ProducerType, - row.ProducerSize, - row.WasteType, - row.PackagingCategory, - row.MaterialType, - row.MaterialSubType, - row.FromHomeNation, - row.ToHomeNation, - row.QuantityKg, - row.QuantityUnits, - ErrorCodes: new List { ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation }); - - _mockFormatter.Setup(f => f.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation)).Returns(expectedRequest); - - // Act - var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); - - // Assert - result.Should().NotBeNull("because a request should be returned if the subsidiary belongs to a different organisation.") - .And.BeEquivalentTo(expectedRequest, "because the returned request should match the expected formatted request."); - - _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation), Times.Once); - } - - [TestMethod] - public void EvaluateSubsidiaryValidation_SubsidiaryIsValid_ShouldReturnNull() + SubsidiaryId = "123", + DataSubmissionPeriod = "2024-01", + ProducerId = "Producer1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteType", + PackagingCategory = "CategoryA", + MaterialType = "MaterialX", + MaterialSubType = "SubTypeX", + FromHomeNation = "Nation1", + ToHomeNation = "Nation2", + QuantityKg = "100", + QuantityUnits = "Units" + }; + var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToAnyOtherOrganisation = true }; + var expectedRequest = new ProducerValidationEventIssueRequest( + row.SubsidiaryId, + row.DataSubmissionPeriod, + row.RowNumber, + row.ProducerId, + row.ProducerType, + row.ProducerSize, + row.WasteType, + row.PackagingCategory, + row.MaterialType, + row.MaterialSubType, + row.FromHomeNation, + row.ToHomeNation, + row.QuantityKg, + row.QuantityUnits, + ErrorCodes: new List { ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation }); + + _mockFormatter.Setup(f => f.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation)).Returns(expectedRequest); + + // Act + var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); + + // Assert + result.Should().NotBeNull("because a request should be returned if the subsidiary belongs to a different organisation.") + .And.BeEquivalentTo(expectedRequest, "because the returned request should match the expected formatted request."); + + _mockFormatter.Verify(f => f.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation), Times.Once); + } + + [TestMethod] + public void EvaluateSubsidiaryValidation_SubsidiaryIsValid_ShouldReturnNull() + { + // Arrange + var row = ModelGenerator.CreateProducerRow(1) with { - // Arrange - var row = ModelGenerator.CreateProducerRow(1) with - { - SubsidiaryId = "123", - DataSubmissionPeriod = "2024-01", - ProducerId = "Producer1", - RowNumber = 1, - ProducerType = "TypeA", - ProducerSize = "Large", - WasteType = "WasteType", - PackagingCategory = "CategoryA", - MaterialType = "MaterialX", - MaterialSubType = "SubTypeX", - FromHomeNation = "Nation1", - ToHomeNation = "Nation2", - QuantityKg = "100", - QuantityUnits = "Units" - }; - var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToAnyOtherOrganisation = false }; - - // Act - var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); - - // Assert - result.Should().BeNull("because the subsidiary is valid and should not generate any validation issue."); - - _mockFormatter.Verify(f => f.Format(It.IsAny(), It.IsAny()), Times.Never); - } + SubsidiaryId = "123", + DataSubmissionPeriod = "2024-01", + ProducerId = "Producer1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteType", + PackagingCategory = "CategoryA", + MaterialType = "MaterialX", + MaterialSubType = "SubTypeX", + FromHomeNation = "Nation1", + ToHomeNation = "Nation2", + QuantityKg = "100", + QuantityUnits = "Units" + }; + var subsidiary = new SubsidiaryDetail { SubsidiaryExists = true, SubsidiaryBelongsToAnyOtherOrganisation = false }; + + // Act + var result = _evaluator.EvaluateSubsidiaryValidation(row, subsidiary, row.RowNumber); + + // Assert + result.Should().BeNull("because the subsidiary is valid and should not generate any validation issue."); + + _mockFormatter.Verify(f => f.Format(It.IsAny(), It.IsAny()), Times.Never); } } diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs index 48b27a3..84f2ff5 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/ValidationServiceProducerRowValidatorTests.cs @@ -8,209 +8,208 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; -namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers; + +[TestClass] +public class ValidationServiceProducerRowValidatorTests { - [TestClass] - public class ValidationServiceProducerRowValidatorTests + private Mock _mockFindMatchingProducer; + private ValidationServiceProducerRowValidator _validator; + + [TestInitialize] + public void Setup() { - private Mock _mockFindMatchingProducer; - private ValidationServiceProducerRowValidator _validator; + _mockFindMatchingProducer = new Mock(); + _validator = new ValidationServiceProducerRowValidator(_mockFindMatchingProducer.Object); + } - [TestInitialize] - public void Setup() - { - _mockFindMatchingProducer = new Mock(); - _validator = new ValidationServiceProducerRowValidator(_mockFindMatchingProducer.Object); - } + [TestMethod] + public void ProcessRowsForValidationErrors_NoValidationErrors_ReturnsEmptyList() + { + // Arrange + var producerRow = ModelGenerator.CreateProducerRow(1); + var producerRowTwo = ModelGenerator.CreateProducerRow(2); + var rows = new List { producerRow, producerRowTwo }; - [TestMethod] - public void ProcessRowsForValidationErrors_NoValidationErrors_ReturnsEmptyList() + var response = new SubsidiaryDetailsResponse { - // Arrange - var producerRow = ModelGenerator.CreateProducerRow(1); - var producerRowTwo = ModelGenerator.CreateProducerRow(2); - var rows = new List { producerRow, producerRowTwo }; + // Initialize response data if needed + }; - var response = new SubsidiaryDetailsResponse - { - // Initialize response data if needed - }; + _mockFindMatchingProducer.Setup(x => x.Match(It.IsAny(), response, It.IsAny())).Returns((ProducerValidationEventIssueRequest)null); - _mockFindMatchingProducer.Setup(x => x.Match(It.IsAny(), response, It.IsAny())).Returns((ProducerValidationEventIssueRequest)null); + // Act + var result = _validator.ProcessRowsForValidationErrors(rows, response); - // Act - var result = _validator.ProcessRowsForValidationErrors(rows, response); + // Assert + result.Should().NotBeNull("the result should not be null, even if it contains no errors.") + .And.BeEmpty("because there are no validation errors expected in this case."); + } - // Assert - result.Should().NotBeNull("the result should not be null, even if it contains no errors.") - .And.BeEmpty("because there are no validation errors expected in this case."); - } + [TestMethod] + public void ProcessRowsForValidationErrors_SingleValidationError_ReturnsListWithOneError() + { + // Arrange + var row1 = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub1", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteTypeA", + PackagingCategory = "CategoryA", + MaterialType = "MaterialA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "100", + QuantityUnits = "10" + }; + + var row2 = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub2", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod2", + RowNumber = 2, + ProducerType = "TypeB", + ProducerSize = "Small", + WasteType = "WasteTypeB", + PackagingCategory = "CategoryB", + MaterialType = "MaterialB", + MaterialSubType = "SubTypeB", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "200", + QuantityUnits = "20" + }; + + var rows = new List { row1, row2 }; + var response = new SubsidiaryDetailsResponse + { + // Initialize response data if needed + }; + + var errorRequest = new ProducerValidationEventIssueRequest( + "Sub1", + "2024Q1", + 1, + "Prod1", + "TypeA", + "Large", + "WasteTypeA", + "CategoryA", + "MaterialA", + "SubTypeA", + "NationA", + "NationB", + "100", + "10", + ErrorCodes: new List { "Error1" }); + + _mockFindMatchingProducer.Setup(x => x.Match(row1, response, 0)).Returns(errorRequest); + _mockFindMatchingProducer.Setup(x => x.Match(row2, response, 1)).Returns((ProducerValidationEventIssueRequest)null); + + // Act + var result = _validator.ProcessRowsForValidationErrors(rows, response); + + // Assert + result.Should().NotBeNull("the result should contain errors if one row has a validation issue.") + .And.HaveCount(1, "because there is only one expected validation error.") + .And.ContainSingle(error => error.Equals(errorRequest), "the single error returned should match the expected error request."); + } - [TestMethod] - public void ProcessRowsForValidationErrors_SingleValidationError_ReturnsListWithOneError() + [TestMethod] + public void ProcessRowsForValidationErrors_MultipleValidationErrors_ReturnsListWithAllErrors() + { + // Arrange + var row1 = ModelGenerator.CreateProducerRow(1) with + { + SubsidiaryId = "Sub1", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod1", + RowNumber = 1, + ProducerType = "TypeA", + ProducerSize = "Large", + WasteType = "WasteTypeA", + PackagingCategory = "CategoryA", + MaterialType = "MaterialA", + MaterialSubType = "SubTypeA", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "100", + QuantityUnits = "10" + }; + + var row2 = ModelGenerator.CreateProducerRow(1) with { - // Arrange - var row1 = ModelGenerator.CreateProducerRow(1) with - { - SubsidiaryId = "Sub1", - DataSubmissionPeriod = "2024Q1", - ProducerId = "Prod1", - RowNumber = 1, - ProducerType = "TypeA", - ProducerSize = "Large", - WasteType = "WasteTypeA", - PackagingCategory = "CategoryA", - MaterialType = "MaterialA", - MaterialSubType = "SubTypeA", - FromHomeNation = "NationA", - ToHomeNation = "NationB", - QuantityKg = "100", - QuantityUnits = "10" - }; - - var row2 = ModelGenerator.CreateProducerRow(1) with - { - SubsidiaryId = "Sub2", - DataSubmissionPeriod = "2024Q1", - ProducerId = "Prod2", - RowNumber = 2, - ProducerType = "TypeB", - ProducerSize = "Small", - WasteType = "WasteTypeB", - PackagingCategory = "CategoryB", - MaterialType = "MaterialB", - MaterialSubType = "SubTypeB", - FromHomeNation = "NationA", - ToHomeNation = "NationB", - QuantityKg = "200", - QuantityUnits = "20" - }; - - var rows = new List { row1, row2 }; - var response = new SubsidiaryDetailsResponse - { - // Initialize response data if needed - }; - - var errorRequest = new ProducerValidationEventIssueRequest( - "Sub1", - "2024Q1", - 1, - "Prod1", - "TypeA", - "Large", - "WasteTypeA", - "CategoryA", - "MaterialA", - "SubTypeA", - "NationA", - "NationB", - "100", - "10", - ErrorCodes: new List { "Error1" }); - - _mockFindMatchingProducer.Setup(x => x.Match(row1, response, 0)).Returns(errorRequest); - _mockFindMatchingProducer.Setup(x => x.Match(row2, response, 1)).Returns((ProducerValidationEventIssueRequest)null); - - // Act - var result = _validator.ProcessRowsForValidationErrors(rows, response); - - // Assert - result.Should().NotBeNull("the result should contain errors if one row has a validation issue.") - .And.HaveCount(1, "because there is only one expected validation error.") - .And.ContainSingle(error => error.Equals(errorRequest), "the single error returned should match the expected error request."); - } - - [TestMethod] - public void ProcessRowsForValidationErrors_MultipleValidationErrors_ReturnsListWithAllErrors() + SubsidiaryId = "Sub2", + DataSubmissionPeriod = "2024Q1", + ProducerId = "Prod2", + RowNumber = 2, + ProducerType = "TypeB", + ProducerSize = "Small", + WasteType = "WasteTypeB", + PackagingCategory = "CategoryB", + MaterialType = "MaterialB", + MaterialSubType = "SubTypeB", + FromHomeNation = "NationA", + ToHomeNation = "NationB", + QuantityKg = "200", + QuantityUnits = "20" + }; + + var rows = new List { row1, row2 }; + var response = new SubsidiaryDetailsResponse { - // Arrange - var row1 = ModelGenerator.CreateProducerRow(1) with - { - SubsidiaryId = "Sub1", - DataSubmissionPeriod = "2024Q1", - ProducerId = "Prod1", - RowNumber = 1, - ProducerType = "TypeA", - ProducerSize = "Large", - WasteType = "WasteTypeA", - PackagingCategory = "CategoryA", - MaterialType = "MaterialA", - MaterialSubType = "SubTypeA", - FromHomeNation = "NationA", - ToHomeNation = "NationB", - QuantityKg = "100", - QuantityUnits = "10" - }; - - var row2 = ModelGenerator.CreateProducerRow(1) with - { - SubsidiaryId = "Sub2", - DataSubmissionPeriod = "2024Q1", - ProducerId = "Prod2", - RowNumber = 2, - ProducerType = "TypeB", - ProducerSize = "Small", - WasteType = "WasteTypeB", - PackagingCategory = "CategoryB", - MaterialType = "MaterialB", - MaterialSubType = "SubTypeB", - FromHomeNation = "NationA", - ToHomeNation = "NationB", - QuantityKg = "200", - QuantityUnits = "20" - }; - - var rows = new List { row1, row2 }; - var response = new SubsidiaryDetailsResponse - { - // Initialize response data if needed - }; - - var errorRequest1 = new ProducerValidationEventIssueRequest( - "Sub1", - "2024Q1", - 1, - "Prod1", - "TypeA", - "Large", - "WasteTypeA", - "CategoryA", - "MaterialA", - "SubTypeA", - "NationA", - "NationB", - "100", - "10", - ErrorCodes: new List { "Error1" }); - - var errorRequest2 = new ProducerValidationEventIssueRequest( - "Sub2", - "2024Q1", - 2, - "Prod2", - "TypeB", - "Small", - "WasteTypeB", - "CategoryB", - "MaterialB", - "SubTypeB", - "NationA", - "NationB", - "200", - "20", - ErrorCodes: new List { "Error2" }); - - _mockFindMatchingProducer.Setup(x => x.Match(row1, response, 0)).Returns(errorRequest1); - _mockFindMatchingProducer.Setup(x => x.Match(row2, response, 1)).Returns(errorRequest2); - - // Act - var result = _validator.ProcessRowsForValidationErrors(rows, response); - - // Assert - result.Should().NotBeNull("the result should contain all validation errors if multiple rows have issues.") - .And.HaveCount(2, "because two validation errors are expected.") - .And.Contain(new[] { errorRequest1, errorRequest2 }, "the list of errors returned should match the expected errors."); - } + // Initialize response data if needed + }; + + var errorRequest1 = new ProducerValidationEventIssueRequest( + "Sub1", + "2024Q1", + 1, + "Prod1", + "TypeA", + "Large", + "WasteTypeA", + "CategoryA", + "MaterialA", + "SubTypeA", + "NationA", + "NationB", + "100", + "10", + ErrorCodes: new List { "Error1" }); + + var errorRequest2 = new ProducerValidationEventIssueRequest( + "Sub2", + "2024Q1", + 2, + "Prod2", + "TypeB", + "Small", + "WasteTypeB", + "CategoryB", + "MaterialB", + "SubTypeB", + "NationA", + "NationB", + "200", + "20", + ErrorCodes: new List { "Error2" }); + + _mockFindMatchingProducer.Setup(x => x.Match(row1, response, 0)).Returns(errorRequest1); + _mockFindMatchingProducer.Setup(x => x.Match(row2, response, 1)).Returns(errorRequest2); + + // Act + var result = _validator.ProcessRowsForValidationErrors(rows, response); + + // Assert + result.Should().NotBeNull("the result should contain all validation errors if multiple rows have issues.") + .And.HaveCount(2, "because two validation errors are expected.") + .And.Contain(new[] { errorRequest1, errorRequest2 }, "the list of errors returned should match the expected errors."); } } diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs index f8f82d6..e61988c 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Subsidiary/SubsidiaryDetailsRequestBuilderTests.cs @@ -2,252 +2,251 @@ using EPR.ProducerContentValidation.Application.Services.Subsidiary; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Subsidiary +namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Subsidiary; + +[TestClass] +public class SubsidiaryDetailsRequestBuilderTests { - [TestClass] - public class SubsidiaryDetailsRequestBuilderTests - { - private SubsidiaryDetailsRequestBuilder _subsidiaryDetailsRequestBuilder; + private SubsidiaryDetailsRequestBuilder _subsidiaryDetailsRequestBuilder; - [TestInitialize] - public void Setup() - { - _subsidiaryDetailsRequestBuilder = new SubsidiaryDetailsRequestBuilder(); - } + [TestInitialize] + public void Setup() + { + _subsidiaryDetailsRequestBuilder = new SubsidiaryDetailsRequestBuilder(); + } - [TestMethod] - public void CreateRequest_ShouldReturnEmptyRequest_WhenRowsIsEmpty() - { - // Arrange - var rows = new List(); + [TestMethod] + public void CreateRequest_ShouldReturnEmptyRequest_WhenRowsIsEmpty() + { + // Arrange + var rows = new List(); - // Act - var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); - // Assert - Assert.IsNotNull(result); - Assert.IsNotNull(result.SubsidiaryOrganisationDetails); - Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); - } + // Assert + Assert.IsNotNull(result); + Assert.IsNotNull(result.SubsidiaryOrganisationDetails); + Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); + } - [TestMethod] - public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() + [TestMethod] + public void CreateRequest_ShouldExcludeRowsWithEmptySubsidiaryId() + { + // Arrange + var rows = new List { - // Arrange - var rows = new List - { - new ProducerRow( - SubsidiaryId: "Subsidiary Id 1", - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1"), - new ProducerRow( - SubsidiaryId: string.Empty, - DataSubmissionPeriod: "Period 2", - ProducerId: "1", - RowNumber: 2, - ProducerType: "Type 2", - ProducerSize: "Size 2", - WasteType: "Waste 2", - PackagingCategory: "Category 2", - MaterialType: "Type 2", - MaterialSubType: "SubType 2", - FromHomeNation: "Nation 2", - ToHomeNation: "Nation 2", - QuantityKg: "200", - QuantityUnits: "1000", - SubmissionPeriod: "Period 2") - }; - - // Act - var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); - - // Assert - Assert.IsNotNull(result); - Assert.AreEqual(1, result.SubsidiaryOrganisationDetails.Count); - var org = result.SubsidiaryOrganisationDetails.First(); - Assert.IsNotNull(org); - Assert.AreEqual("1", org.OrganisationReference); - Assert.AreEqual(1, org.SubsidiaryDetails.Count); - Assert.AreEqual("Subsidiary Id 1", org.SubsidiaryDetails[0].ReferenceNumber); - } - - [TestMethod] - public void CreateRequest_ShouldHandleNoValidSubsidiaryIds() + new ProducerRow( + SubsidiaryId: "Subsidiary Id 1", + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Period 2", + ProducerId: "1", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") + }; + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(1, result.SubsidiaryOrganisationDetails.Count); + var org = result.SubsidiaryOrganisationDetails.First(); + Assert.IsNotNull(org); + Assert.AreEqual("1", org.OrganisationReference); + Assert.AreEqual(1, org.SubsidiaryDetails.Count); + Assert.AreEqual("Subsidiary Id 1", org.SubsidiaryDetails[0].ReferenceNumber); + } + + [TestMethod] + public void CreateRequest_ShouldHandleNoValidSubsidiaryIds() + { + // Arrange + var rows = new List { - // Arrange - var rows = new List - { - new ProducerRow( - SubsidiaryId: string.Empty, - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1") - }; - - // Act - var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); - - // Assert - Assert.IsNotNull(result); - Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); - } - - [TestMethod] - public void CreateRequest_ShouldGroupByProducerId_WithMultipleValidSubsidiaryIds() + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1") + }; + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); + } + + [TestMethod] + public void CreateRequest_ShouldGroupByProducerId_WithMultipleValidSubsidiaryIds() + { + // Arrange + var rows = new List { - // Arrange - var rows = new List - { - new ProducerRow( - SubsidiaryId: "SubId1", - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1"), - new ProducerRow( - SubsidiaryId: "SubId2", - DataSubmissionPeriod: "Period 2", - ProducerId: "1", - RowNumber: 2, - ProducerType: "Type 2", - ProducerSize: "Size 2", - WasteType: "Waste 2", - PackagingCategory: "Category 2", - MaterialType: "Type 2", - MaterialSubType: "SubType 2", - FromHomeNation: "Nation 2", - ToHomeNation: "Nation 2", - QuantityKg: "200", - QuantityUnits: "1000", - SubmissionPeriod: "Period 2") - }; - - // Act - var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); - - // Assert - Assert.IsNotNull(result); - Assert.AreEqual(1, result.SubsidiaryOrganisationDetails.Count); - var org = result.SubsidiaryOrganisationDetails.First(); - Assert.AreEqual("1", org.OrganisationReference); - Assert.AreEqual(2, org.SubsidiaryDetails.Count); - Assert.IsTrue(org.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "SubId1")); - Assert.IsTrue(org.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "SubId2")); - } - - [TestMethod] - public void CreateRequest_ShouldReturnMultipleOrganisationsWithValidSubsidiaryIds() + new ProducerRow( + SubsidiaryId: "SubId1", + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: "SubId2", + DataSubmissionPeriod: "Period 2", + ProducerId: "1", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") + }; + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(1, result.SubsidiaryOrganisationDetails.Count); + var org = result.SubsidiaryOrganisationDetails.First(); + Assert.AreEqual("1", org.OrganisationReference); + Assert.AreEqual(2, org.SubsidiaryDetails.Count); + Assert.IsTrue(org.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "SubId1")); + Assert.IsTrue(org.SubsidiaryDetails.Any(sub => sub.ReferenceNumber == "SubId2")); + } + + [TestMethod] + public void CreateRequest_ShouldReturnMultipleOrganisationsWithValidSubsidiaryIds() + { + // Arrange + var rows = new List { - // Arrange - var rows = new List - { - new ProducerRow( - SubsidiaryId: "SubId1", - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1"), - new ProducerRow( - SubsidiaryId: "SubId2", - DataSubmissionPeriod: "Period 2", - ProducerId: "2", - RowNumber: 2, - ProducerType: "Type 2", - ProducerSize: "Size 2", - WasteType: "Waste 2", - PackagingCategory: "Category 2", - MaterialType: "Type 2", - MaterialSubType: "SubType 2", - FromHomeNation: "Nation 2", - ToHomeNation: "Nation 2", - QuantityKg: "200", - QuantityUnits: "1000", - SubmissionPeriod: "Period 2") - }; - - // Act - var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); - - // Assert - Assert.IsNotNull(result); - Assert.AreEqual(2, result.SubsidiaryOrganisationDetails.Count); - Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(o => o.OrganisationReference == "1")); - Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(o => o.OrganisationReference == "2")); - } - - [TestMethod] - public void CreateRequest_ShouldIgnoreRowsWithWhitespaceSubsidiaryId() + new ProducerRow( + SubsidiaryId: "SubId1", + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1"), + new ProducerRow( + SubsidiaryId: "SubId2", + DataSubmissionPeriod: "Period 2", + ProducerId: "2", + RowNumber: 2, + ProducerType: "Type 2", + ProducerSize: "Size 2", + WasteType: "Waste 2", + PackagingCategory: "Category 2", + MaterialType: "Type 2", + MaterialSubType: "SubType 2", + FromHomeNation: "Nation 2", + ToHomeNation: "Nation 2", + QuantityKg: "200", + QuantityUnits: "1000", + SubmissionPeriod: "Period 2") + }; + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(2, result.SubsidiaryOrganisationDetails.Count); + Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(o => o.OrganisationReference == "1")); + Assert.IsTrue(result.SubsidiaryOrganisationDetails.Any(o => o.OrganisationReference == "2")); + } + + [TestMethod] + public void CreateRequest_ShouldIgnoreRowsWithWhitespaceSubsidiaryId() + { + // Arrange + var rows = new List { - // Arrange - var rows = new List - { - new ProducerRow( - SubsidiaryId: string.Empty, - DataSubmissionPeriod: "Period 1", - ProducerId: "1", - RowNumber: 1, - ProducerType: "Type 1", - ProducerSize: "Size 1", - WasteType: "Waste 1", - PackagingCategory: "Category 1", - MaterialType: "Type 1", - MaterialSubType: "SubType 1", - FromHomeNation: "Nation 1", - ToHomeNation: "Nation 1", - QuantityKg: "100", - QuantityUnits: "500", - SubmissionPeriod: "Period 1") - }; - - // Act - var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); - - // Assert - Assert.IsNotNull(result); - Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); - } + new ProducerRow( + SubsidiaryId: string.Empty, + DataSubmissionPeriod: "Period 1", + ProducerId: "1", + RowNumber: 1, + ProducerType: "Type 1", + ProducerSize: "Size 1", + WasteType: "Waste 1", + PackagingCategory: "Category 1", + MaterialType: "Type 1", + MaterialSubType: "SubType 1", + FromHomeNation: "Nation 1", + ToHomeNation: "Nation 1", + QuantityKg: "100", + QuantityUnits: "500", + SubmissionPeriod: "Period 1") + }; + + // Act + var result = _subsidiaryDetailsRequestBuilder.CreateRequest(rows); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(0, result.SubsidiaryOrganisationDetails.Count); } } diff --git a/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs b/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs index c08c2db..8b4718e 100644 --- a/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs +++ b/src/EPR.ProducerContentValidation.Application/Clients/CompanyDetailsApiClient.cs @@ -2,57 +2,56 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json; -namespace EPR.ProducerContentValidation.Application.Clients +namespace EPR.ProducerContentValidation.Application.Clients; + +public class CompanyDetailsApiClient : ICompanyDetailsApiClient { - public class CompanyDetailsApiClient : ICompanyDetailsApiClient - { - private readonly HttpClient _httpClient; - private readonly ILogger _logger; + private readonly HttpClient _httpClient; + private readonly ILogger _logger; - public CompanyDetailsApiClient( - HttpClient httpClient, - ILogger logger) - { - _httpClient = httpClient; - _logger = logger; - } + public CompanyDetailsApiClient( + HttpClient httpClient, + ILogger logger) + { + _httpClient = httpClient; + _logger = logger; + } - public async Task GetSubsidiaryDetails(SubsidiaryDetailsRequest subsidiaryDetailsRequest) + public async Task GetSubsidiaryDetails(SubsidiaryDetailsRequest subsidiaryDetailsRequest) + { + try { - try - { - var uriString = "api/subsidiary-details"; - var httpContent = CreateHttpContent(subsidiaryDetailsRequest); - - var response = await _httpClient.PostAsync(uriString, httpContent); - - response.EnsureSuccessStatusCode(); - - return await DeserializeResponseData(response); - } - catch (HttpRequestException ex) - { - _logger.LogError(ex, "Error occurred while requesting subsidiary details"); - throw; - } - } + var uriString = "api/subsidiary-details"; + var httpContent = CreateHttpContent(subsidiaryDetailsRequest); - private static async Task DeserializeResponseData(HttpResponseMessage response) - { - var content = await response.Content.ReadAsStringAsync(); + var response = await _httpClient.PostAsync(uriString, httpContent); - if (!string.IsNullOrEmpty(content)) - { - return JsonConvert.DeserializeObject(content); - } + response.EnsureSuccessStatusCode(); - return default; + return await DeserializeResponseData(response); } + catch (HttpRequestException ex) + { + _logger.LogError(ex, "Error occurred while requesting subsidiary details"); + throw; + } + } + + private static async Task DeserializeResponseData(HttpResponseMessage response) + { + var content = await response.Content.ReadAsStringAsync(); - private StringContent CreateHttpContent(object data) + if (!string.IsNullOrEmpty(content)) { - var json = JsonConvert.SerializeObject(data); - return new StringContent(json, System.Text.Encoding.UTF8, "application/json"); + return JsonConvert.DeserializeObject(content); } + + return default; + } + + private StringContent CreateHttpContent(object data) + { + var json = JsonConvert.SerializeObject(data); + return new StringContent(json, System.Text.Encoding.UTF8, "application/json"); } } diff --git a/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs b/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs index a197b06..490e428 100644 --- a/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs +++ b/src/EPR.ProducerContentValidation.Application/Clients/ICompanyDetailsApiClient.cs @@ -1,9 +1,8 @@ using EPR.ProducerContentValidation.Application.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Clients +namespace EPR.ProducerContentValidation.Application.Clients; + +public interface ICompanyDetailsApiClient { - public interface ICompanyDetailsApiClient - { - Task GetSubsidiaryDetails(SubsidiaryDetailsRequest subsidiaryDetailsRequest); - } + Task GetSubsidiaryDetails(SubsidiaryDetailsRequest subsidiaryDetailsRequest); } diff --git a/src/EPR.ProducerContentValidation.Application/Config/CompanyDetailsApiConfig.cs b/src/EPR.ProducerContentValidation.Application/Config/CompanyDetailsApiConfig.cs index 35cdd8d..e262acf 100644 --- a/src/EPR.ProducerContentValidation.Application/Config/CompanyDetailsApiConfig.cs +++ b/src/EPR.ProducerContentValidation.Application/Config/CompanyDetailsApiConfig.cs @@ -1,16 +1,15 @@ using System.ComponentModel.DataAnnotations; -namespace EPR.ProducerContentValidation.Application.Config +namespace EPR.ProducerContentValidation.Application.Config; + +public class CompanyDetailsApiConfig { - public class CompanyDetailsApiConfig - { - public const string Section = "CompanyDetailsApi"; + public const string Section = "CompanyDetailsApi"; - [Required] - public string BaseUrl { get; init; } + [Required] + public string BaseUrl { get; init; } - public string? ClientId { get; set; } + public string? ClientId { get; set; } - public int Timeout { get; set; } - } + public int Timeout { get; set; } } diff --git a/src/EPR.ProducerContentValidation.Application/Exceptions/CompanyDetailsApiClientException.cs b/src/EPR.ProducerContentValidation.Application/Exceptions/CompanyDetailsApiClientException.cs index 6f415be..f008317 100644 --- a/src/EPR.ProducerContentValidation.Application/Exceptions/CompanyDetailsApiClientException.cs +++ b/src/EPR.ProducerContentValidation.Application/Exceptions/CompanyDetailsApiClientException.cs @@ -1,23 +1,22 @@ using System.Diagnostics.CodeAnalysis; -namespace EPR.ProducerContentValidation.Application.Exceptions +namespace EPR.ProducerContentValidation.Application.Exceptions; + +[ExcludeFromCodeCoverage] +[Serializable] +public class CompanyDetailsApiClientException : Exception { - [ExcludeFromCodeCoverage] - [Serializable] - public class CompanyDetailsApiClientException : Exception + public CompanyDetailsApiClientException() { - public CompanyDetailsApiClientException() - { - } + } - public CompanyDetailsApiClientException(string message) - : base(message) - { - } + public CompanyDetailsApiClientException(string message) + : base(message) + { + } - public CompanyDetailsApiClientException(string message, Exception inner) - : base(message, inner) - { - } + public CompanyDetailsApiClientException(string message, Exception inner) + : base(message, inner) + { } } diff --git a/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs b/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs index 1b3e179..038281f 100644 --- a/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs +++ b/src/EPR.ProducerContentValidation.Application/Handlers/CompanyDetailsApiAuthorisationHandler.cs @@ -5,35 +5,34 @@ using EPR.ProducerContentValidation.Application.Config; using Microsoft.Extensions.Options; -namespace EPR.ProducerContentValidation.Application.Handlers +namespace EPR.ProducerContentValidation.Application.Handlers; + +[ExcludeFromCodeCoverage(Justification = "Dependency on Azure to acquire token, will be assured via end to end testing.")] +public class CompanyDetailsApiAuthorisationHandler : DelegatingHandler { - [ExcludeFromCodeCoverage(Justification = "Dependency on Azure to acquire token, will be assured via end to end testing.")] - public class CompanyDetailsApiAuthorisationHandler : DelegatingHandler - { - private const string BearerScheme = "Bearer"; - private readonly TokenRequestContext _tokenRequestContext; - private readonly DefaultAzureCredential? _credentials; + private const string BearerScheme = "Bearer"; + private readonly TokenRequestContext _tokenRequestContext; + private readonly DefaultAzureCredential? _credentials; - public CompanyDetailsApiAuthorisationHandler(IOptions options) + public CompanyDetailsApiAuthorisationHandler(IOptions options) + { + if (string.IsNullOrEmpty(options.Value.ClientId)) { - if (string.IsNullOrEmpty(options.Value.ClientId)) - { - return; - } - - _tokenRequestContext = new TokenRequestContext(new[] { options.Value.ClientId }); - _credentials = new DefaultAzureCredential(); + return; } - protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) - { - if (_credentials != null) - { - var tokenResult = await _credentials.GetTokenAsync(_tokenRequestContext, cancellationToken); - request.Headers.Authorization = new AuthenticationHeaderValue(BearerScheme, tokenResult.Token); - } + _tokenRequestContext = new TokenRequestContext(new[] { options.Value.ClientId }); + _credentials = new DefaultAzureCredential(); + } - return await base.SendAsync(request, cancellationToken); + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + if (_credentials != null) + { + var tokenResult = await _credentials.GetTokenAsync(_tokenRequestContext, cancellationToken); + request.Headers.Authorization = new AuthenticationHeaderValue(BearerScheme, tokenResult.Token); } + + return await base.SendAsync(request, cancellationToken); } } diff --git a/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetail.cs b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetail.cs index 415cd8c..58851bb 100644 --- a/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetail.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetail.cs @@ -1,14 +1,13 @@ using System.Diagnostics.CodeAnalysis; -namespace EPR.ProducerContentValidation.Application.Models.Subsidiary +namespace EPR.ProducerContentValidation.Application.Models.Subsidiary; + +[ExcludeFromCodeCoverage] +public class SubsidiaryDetail { - [ExcludeFromCodeCoverage] - public class SubsidiaryDetail - { - public string ReferenceNumber { get; set; } + public string ReferenceNumber { get; set; } - public bool SubsidiaryExists { get; set; } + public bool SubsidiaryExists { get; set; } - public bool SubsidiaryBelongsToAnyOtherOrganisation { get; set; } - } + public bool SubsidiaryBelongsToAnyOtherOrganisation { get; set; } } diff --git a/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsRequest.cs b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsRequest.cs index edecc9d..7ab86d9 100644 --- a/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsRequest.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsRequest.cs @@ -1,10 +1,9 @@ using System.Diagnostics.CodeAnalysis; -namespace EPR.ProducerContentValidation.Application.Models.Subsidiary +namespace EPR.ProducerContentValidation.Application.Models.Subsidiary; + +[ExcludeFromCodeCoverage] +public class SubsidiaryDetailsRequest { - [ExcludeFromCodeCoverage] - public class SubsidiaryDetailsRequest - { - public List SubsidiaryOrganisationDetails { get; set; } - } + public List SubsidiaryOrganisationDetails { get; set; } } diff --git a/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsResponse.cs b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsResponse.cs index 669fff7..a21a6ad 100644 --- a/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsResponse.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryDetailsResponse.cs @@ -1,10 +1,9 @@ using System.Diagnostics.CodeAnalysis; -namespace EPR.ProducerContentValidation.Application.Models.Subsidiary +namespace EPR.ProducerContentValidation.Application.Models.Subsidiary; + +[ExcludeFromCodeCoverage] +public class SubsidiaryDetailsResponse { - [ExcludeFromCodeCoverage] - public class SubsidiaryDetailsResponse - { - public List SubsidiaryOrganisationDetails { get; set; } - } + public List SubsidiaryOrganisationDetails { get; set; } } diff --git a/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryOrganisationDetail.cs b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryOrganisationDetail.cs index 9ca2695..791f182 100644 --- a/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryOrganisationDetail.cs +++ b/src/EPR.ProducerContentValidation.Application/Models/Subsidiary/SubsidiaryOrganisationDetail.cs @@ -1,12 +1,11 @@ using System.Diagnostics.CodeAnalysis; -namespace EPR.ProducerContentValidation.Application.Models.Subsidiary +namespace EPR.ProducerContentValidation.Application.Models.Subsidiary; + +[ExcludeFromCodeCoverage] +public class SubsidiaryOrganisationDetail { - [ExcludeFromCodeCoverage] - public class SubsidiaryOrganisationDetail - { - public string OrganisationReference { get; set; } + public string OrganisationReference { get; set; } - public List SubsidiaryDetails { get; set; } - } + public List SubsidiaryDetails { get; set; } } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs index 5d4474e..fcc0f3d 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/FindMatchingProducer.cs @@ -3,37 +3,36 @@ using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers; + +public class FindMatchingProducer : IFindMatchingProducer { - public class FindMatchingProducer : IFindMatchingProducer + private readonly IOrganisationMatcher _organisationMatcher; + private readonly ISubsidiaryMatcher _subsidiaryMatcher; + private readonly ISubsidiaryValidationEvaluator _subsidiaryValidationEvaluator; + + public FindMatchingProducer(IOrganisationMatcher organisationMatcher, ISubsidiaryMatcher subsidiaryMatcher, ISubsidiaryValidationEvaluator subsidiaryValidationEvaluator) { - private readonly IOrganisationMatcher _organisationMatcher; - private readonly ISubsidiaryMatcher _subsidiaryMatcher; - private readonly ISubsidiaryValidationEvaluator _subsidiaryValidationEvaluator; + _organisationMatcher = organisationMatcher; + _subsidiaryMatcher = subsidiaryMatcher; + _subsidiaryValidationEvaluator = subsidiaryValidationEvaluator; + } - public FindMatchingProducer(IOrganisationMatcher organisationMatcher, ISubsidiaryMatcher subsidiaryMatcher, ISubsidiaryValidationEvaluator subsidiaryValidationEvaluator) + public ProducerValidationEventIssueRequest? Match( + ProducerRow row, SubsidiaryDetailsResponse response, int rowIndex) + { + var matchingOrg = _organisationMatcher.FindMatchingOrganisation(row, response); + if (matchingOrg == null) { - _organisationMatcher = organisationMatcher; - _subsidiaryMatcher = subsidiaryMatcher; - _subsidiaryValidationEvaluator = subsidiaryValidationEvaluator; + return null; } - public ProducerValidationEventIssueRequest? Match( - ProducerRow row, SubsidiaryDetailsResponse response, int rowIndex) + var matchingSub = _subsidiaryMatcher.FindMatchingSubsidiary(row, matchingOrg); + if (matchingSub == null) { - var matchingOrg = _organisationMatcher.FindMatchingOrganisation(row, response); - if (matchingOrg == null) - { - return null; - } - - var matchingSub = _subsidiaryMatcher.FindMatchingSubsidiary(row, matchingOrg); - if (matchingSub == null) - { - return null; - } - - return _subsidiaryValidationEvaluator.EvaluateSubsidiaryValidation(row, matchingSub, rowIndex); + return null; } + + return _subsidiaryValidationEvaluator.EvaluateSubsidiaryValidation(row, matchingSub, rowIndex); } } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs index 97bc2b2..77cde03 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IFindMatchingProducer.cs @@ -2,10 +2,9 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; + +public interface IFindMatchingProducer { - public interface IFindMatchingProducer - { - ProducerValidationEventIssueRequest? Match(ProducerRow row, SubsidiaryDetailsResponse response, int rowIndex); - } + ProducerValidationEventIssueRequest? Match(ProducerRow row, SubsidiaryDetailsResponse response, int rowIndex); } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs index 2aca078..7555b10 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IOrganisationMatcher.cs @@ -1,10 +1,9 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; + +public interface IOrganisationMatcher { - public interface IOrganisationMatcher - { - SubsidiaryOrganisationDetail? FindMatchingOrganisation(ProducerRow row, SubsidiaryDetailsResponse response); - } + SubsidiaryOrganisationDetail? FindMatchingOrganisation(ProducerRow row, SubsidiaryDetailsResponse response); } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IProducerValidationEventIssueRequestFormatter.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IProducerValidationEventIssueRequestFormatter.cs index cef13c5..872fe51 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IProducerValidationEventIssueRequestFormatter.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IProducerValidationEventIssueRequestFormatter.cs @@ -1,10 +1,9 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; using EPR.ProducerContentValidation.Application.Models; -namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; + +public interface IProducerValidationEventIssueRequestFormatter { - public interface IProducerValidationEventIssueRequestFormatter - { - ProducerValidationEventIssueRequest Format(ProducerRow row, string errorCode); - } + ProducerValidationEventIssueRequest Format(ProducerRow row, string errorCode); } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs index f332719..ca25b78 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IRequestValidator.cs @@ -1,9 +1,8 @@ using EPR.ProducerContentValidation.Application.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; + +public interface IRequestValidator { - public interface IRequestValidator - { - bool IsInvalidRequest(SubsidiaryDetailsRequest request); - } + bool IsInvalidRequest(SubsidiaryDetailsRequest request); } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs index bed05ee..6ddfe91 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryMatcher.cs @@ -1,10 +1,9 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; + +public interface ISubsidiaryMatcher { - public interface ISubsidiaryMatcher - { - SubsidiaryDetail? FindMatchingSubsidiary(ProducerRow row, SubsidiaryOrganisationDetail org); - } + SubsidiaryDetail? FindMatchingSubsidiary(ProducerRow row, SubsidiaryOrganisationDetail org); } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs index 41781d4..9dfd246 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/ISubsidiaryValidationEvaluator.cs @@ -2,10 +2,9 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; + +public interface ISubsidiaryValidationEvaluator { - public interface ISubsidiaryValidationEvaluator - { - ProducerValidationEventIssueRequest? EvaluateSubsidiaryValidation(ProducerRow row, SubsidiaryDetail subsidiary, int rowIndex); - } + ProducerValidationEventIssueRequest? EvaluateSubsidiaryValidation(ProducerRow row, SubsidiaryDetail subsidiary, int rowIndex); } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs index 09e628a..77dd135 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/Interfaces/IValidationServiceProducerRowValidator.cs @@ -2,11 +2,10 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces +namespace EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; + +public interface IValidationServiceProducerRowValidator { - public interface IValidationServiceProducerRowValidator - { - IEnumerable ProcessRowsForValidationErrors( - List rows, SubsidiaryDetailsResponse response); - } + IEnumerable ProcessRowsForValidationErrors( + List rows, SubsidiaryDetailsResponse response); } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs index 514ef72..c6c013f 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/OrganisationMatcher.cs @@ -2,14 +2,13 @@ using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers; + +public class OrganisationMatcher : IOrganisationMatcher { - public class OrganisationMatcher : IOrganisationMatcher + public SubsidiaryOrganisationDetail? FindMatchingOrganisation(ProducerRow row, SubsidiaryDetailsResponse response) { - public SubsidiaryOrganisationDetail? FindMatchingOrganisation(ProducerRow row, SubsidiaryDetailsResponse response) - { - return response.SubsidiaryOrganisationDetails - .FirstOrDefault(org => org.OrganisationReference == row.ProducerId); - } + return response.SubsidiaryOrganisationDetails + .FirstOrDefault(org => org.OrganisationReference == row.ProducerId); } } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs index 52e56da..b6ea46b 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestFormatter.cs @@ -2,30 +2,29 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers; + +public class ProducerValidationEventIssueRequestFormatter : IProducerValidationEventIssueRequestFormatter { - public class ProducerValidationEventIssueRequestFormatter : IProducerValidationEventIssueRequestFormatter + public ProducerValidationEventIssueRequest Format(ProducerRow row, string errorCode) { - public ProducerValidationEventIssueRequest Format(ProducerRow row, string errorCode) - { - var errorCodes = new List { errorCode }; + var errorCodes = new List { errorCode }; - return new ProducerValidationEventIssueRequest( - SubsidiaryId: row.SubsidiaryId ?? string.Empty, - DataSubmissionPeriod: row.DataSubmissionPeriod ?? string.Empty, - RowNumber: row.RowNumber, - ProducerId: row.ProducerId ?? string.Empty, - ProducerType: row.ProducerType ?? string.Empty, - ProducerSize: row.ProducerSize ?? string.Empty, - WasteType: row.WasteType ?? string.Empty, - PackagingCategory: row.PackagingCategory ?? string.Empty, - MaterialType: row.MaterialType ?? string.Empty, - MaterialSubType: row.MaterialSubType ?? string.Empty, - FromHomeNation: row.FromHomeNation ?? string.Empty, - ToHomeNation: row.ToHomeNation ?? string.Empty, - QuantityKg: row.QuantityKg ?? string.Empty, - QuantityUnits: row.QuantityUnits ?? string.Empty, - ErrorCodes: errorCodes); - } + return new ProducerValidationEventIssueRequest( + SubsidiaryId: row.SubsidiaryId ?? string.Empty, + DataSubmissionPeriod: row.DataSubmissionPeriod ?? string.Empty, + RowNumber: row.RowNumber, + ProducerId: row.ProducerId ?? string.Empty, + ProducerType: row.ProducerType ?? string.Empty, + ProducerSize: row.ProducerSize ?? string.Empty, + WasteType: row.WasteType ?? string.Empty, + PackagingCategory: row.PackagingCategory ?? string.Empty, + MaterialType: row.MaterialType ?? string.Empty, + MaterialSubType: row.MaterialSubType ?? string.Empty, + FromHomeNation: row.FromHomeNation ?? string.Empty, + ToHomeNation: row.ToHomeNation ?? string.Empty, + QuantityKg: row.QuantityKg ?? string.Empty, + QuantityUnits: row.QuantityUnits ?? string.Empty, + ErrorCodes: errorCodes); } } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestMerger.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestMerger.cs index 54e928b..5c31442 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestMerger.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ProducerValidationEventIssueRequestMerger.cs @@ -1,56 +1,71 @@ using EPR.ProducerContentValidation.Application.DTOs.SubmissionApi; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers; + +public static class ProducerValidationEventIssueRequestMerger { - public static class ProducerValidationEventIssueRequestMerger + public static List MergeRequests( + List list1, + List list2) { - public static List MergeRequests( - List list1, - List list2) - { - // Combine both lists - var combinedList = list1.Concat(list2); + // Combine both lists + var combinedList = list1.Concat(list2); - // Use a dictionary to group and merge ErrorCodes for identical records - var mergedDict = new Dictionary<(string, string, int, string, string, string, string, string, string, string, string, string, string, string, string), ProducerValidationEventIssueRequest>(); + // Use a dictionary to group and merge ErrorCodes for identical records + var mergedDict = new Dictionary<( + string SubsidiaryId, + string DataSubmissionPeriod, + int RowNumber, + string ProducerId, + string ProducerType, + string ProducerSize, + string WasteType, + string PackagingCategory, + string MaterialType, + string MaterialSubType, + string FromHomeNation, + string ToHomeNation, + string QuantityKg, + string QuantityUnits, + string BlobName), + ProducerValidationEventIssueRequest>(); - foreach (var request in combinedList) - { - var key = ( - request.SubsidiaryId, - request.DataSubmissionPeriod, - request.RowNumber, - request.ProducerId, - request.ProducerType, - request.ProducerSize, - request.WasteType, - request.PackagingCategory, - request.MaterialType, - request.MaterialSubType, - request.FromHomeNation, - request.ToHomeNation, - request.QuantityKg, - request.QuantityUnits, - request.BlobName); + foreach (var request in combinedList) + { + var key = ( + request.SubsidiaryId, + request.DataSubmissionPeriod, + request.RowNumber, + request.ProducerId, + request.ProducerType, + request.ProducerSize, + request.WasteType, + request.PackagingCategory, + request.MaterialType, + request.MaterialSubType, + request.FromHomeNation, + request.ToHomeNation, + request.QuantityKg, + request.QuantityUnits, + request.BlobName); - if (mergedDict.TryGetValue(key, out var existingRequest)) - { - // Merge ErrorCodes if they exist - var mergedErrorCodes = existingRequest.ErrorCodes?.Union(request.ErrorCodes ?? new List()).ToList() - ?? request.ErrorCodes ?? new List(); + if (mergedDict.TryGetValue(key, out var existingRequest)) + { + // Merge ErrorCodes if they exist + var mergedErrorCodes = existingRequest.ErrorCodes?.Union(request.ErrorCodes ?? new List()).ToList() + ?? request.ErrorCodes ?? new List(); - // Update the dictionary with the merged ErrorCodes - mergedDict[key] = existingRequest with { ErrorCodes = mergedErrorCodes }; - } - else - { - // Add the request to the dictionary if it doesn't exist - mergedDict[key] = request; - } + // Update the dictionary with the merged ErrorCodes + mergedDict[key] = existingRequest with { ErrorCodes = mergedErrorCodes }; + } + else + { + // Add the request to the dictionary if it doesn't exist + mergedDict[key] = request; } - - // Return the merged list - return mergedDict.Values.ToList(); } + + // Return the merged list + return mergedDict.Values.ToList(); } } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs index 0818036..d486d8d 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/RequestValidator.cs @@ -1,11 +1,10 @@ using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers; + +public class RequestValidator : IRequestValidator { - public class RequestValidator : IRequestValidator - { - public bool IsInvalidRequest(SubsidiaryDetailsRequest request) => - request?.SubsidiaryOrganisationDetails == null || !request.SubsidiaryOrganisationDetails.Any(); - } + public bool IsInvalidRequest(SubsidiaryDetailsRequest request) => + request?.SubsidiaryOrganisationDetails == null || !request.SubsidiaryOrganisationDetails.Any(); } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs index cf29478..51a66e0 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryMatcher.cs @@ -2,14 +2,13 @@ using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers; + +public class SubsidiaryMatcher : ISubsidiaryMatcher { - public class SubsidiaryMatcher : ISubsidiaryMatcher + public SubsidiaryDetail? FindMatchingSubsidiary(ProducerRow row, SubsidiaryOrganisationDetail org) { - public SubsidiaryDetail? FindMatchingSubsidiary(ProducerRow row, SubsidiaryOrganisationDetail org) - { - return org.SubsidiaryDetails - .FirstOrDefault(sub => sub.ReferenceNumber == row.SubsidiaryId); - } + return org.SubsidiaryDetails + .FirstOrDefault(sub => sub.ReferenceNumber == row.SubsidiaryId); } } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs index 1a28614..1391e05 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs @@ -5,39 +5,38 @@ using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; using Microsoft.Extensions.Logging; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers; + +public class SubsidiaryValidationEvaluator : ISubsidiaryValidationEvaluator { - public class SubsidiaryValidationEvaluator : ISubsidiaryValidationEvaluator + private readonly ILogger _logger; + private readonly IProducerValidationEventIssueRequestFormatter _producerValidationEventIssueRequestFormatter; + + public SubsidiaryValidationEvaluator(ILogger logger, IProducerValidationEventIssueRequestFormatter producerValidationEventIssueRequestFormatter) { - private readonly ILogger _logger; - private readonly IProducerValidationEventIssueRequestFormatter _producerValidationEventIssueRequestFormatter; + _logger = logger; + _producerValidationEventIssueRequestFormatter = producerValidationEventIssueRequestFormatter; + } - public SubsidiaryValidationEvaluator(ILogger logger, IProducerValidationEventIssueRequestFormatter producerValidationEventIssueRequestFormatter) + public ProducerValidationEventIssueRequest? EvaluateSubsidiaryValidation(ProducerRow row, SubsidiaryDetail subsidiary, int rowIndex) + { + if (!subsidiary.SubsidiaryExists) { - _logger = logger; - _producerValidationEventIssueRequestFormatter = producerValidationEventIssueRequestFormatter; + LogValidationWarning(rowIndex + 1, "Subsidiary ID does not exist", ErrorCode.SubsidiaryIdDoesNotExist); + return _producerValidationEventIssueRequestFormatter.Format(row, ErrorCode.SubsidiaryIdDoesNotExist); } - public ProducerValidationEventIssueRequest? EvaluateSubsidiaryValidation(ProducerRow row, SubsidiaryDetail subsidiary, int rowIndex) + if (subsidiary.SubsidiaryBelongsToAnyOtherOrganisation) { - if (!subsidiary.SubsidiaryExists) - { - LogValidationWarning(rowIndex + 1, "Subsidiary ID does not exist", ErrorCode.SubsidiaryIdDoesNotExist); - return _producerValidationEventIssueRequestFormatter.Format(row, ErrorCode.SubsidiaryIdDoesNotExist); - } - - if (subsidiary.SubsidiaryBelongsToAnyOtherOrganisation) - { - LogValidationWarning(rowIndex + 1, "Subsidiary ID is assigned to a different organisation", ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); - return _producerValidationEventIssueRequestFormatter.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); - } - - return null; + LogValidationWarning(rowIndex + 1, "Subsidiary ID is assigned to a different organisation", ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); + return _producerValidationEventIssueRequestFormatter.Format(row, ErrorCode.SubsidiaryIdIsAssignedToADifferentOrganisation); } - private void LogValidationWarning(int rowNumber, string message, string errorCode) - { - _logger.LogWarning("Validation Warning at row {RowNumber}: {Message} (ErrorCode: {ErrorCode})", rowNumber, message, errorCode); - } + return null; + } + + private void LogValidationWarning(int rowNumber, string message, string errorCode) + { + _logger.LogWarning("Validation Warning at row {RowNumber}: {Message} (ErrorCode: {ErrorCode})", rowNumber, message, errorCode); } } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs index d681b9c..2d10ef2 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/ValidationServiceProducerRowValidator.cs @@ -3,32 +3,31 @@ using EPR.ProducerContentValidation.Application.Models.Subsidiary; using EPR.ProducerContentValidation.Application.Services.Helpers.Interfaces; -namespace EPR.ProducerContentValidation.Application.Services.Helpers +namespace EPR.ProducerContentValidation.Application.Services.Helpers; + +public class ValidationServiceProducerRowValidator : IValidationServiceProducerRowValidator { - public class ValidationServiceProducerRowValidator : IValidationServiceProducerRowValidator + private readonly IFindMatchingProducer _findMatchingProducer; + + public ValidationServiceProducerRowValidator(IFindMatchingProducer findMatchingProducer) { - private readonly IFindMatchingProducer _findMatchingProducer; + _findMatchingProducer = findMatchingProducer; + } - public ValidationServiceProducerRowValidator(IFindMatchingProducer findMatchingProducer) - { - _findMatchingProducer = findMatchingProducer; - } + public IEnumerable ProcessRowsForValidationErrors( + List rows, SubsidiaryDetailsResponse response) + { + var validationErrors = new List(); - public IEnumerable ProcessRowsForValidationErrors( - List rows, SubsidiaryDetailsResponse response) + for (var i = 0; i < rows.Count; i++) { - var validationErrors = new List(); - - for (var i = 0; i < rows.Count; i++) + var error = _findMatchingProducer.Match(rows[i], response, i); + if (error != null) { - var error = _findMatchingProducer.Match(rows[i], response, i); - if (error != null) - { - validationErrors.Add(error); - } + validationErrors.Add(error); } - - return validationErrors; } + + return validationErrors; } } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs index cdc1b25..092543e 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/ISubsidiaryDetailsRequestBuilder.cs @@ -1,10 +1,9 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Subsidiary +namespace EPR.ProducerContentValidation.Application.Services.Subsidiary; + +public interface ISubsidiaryDetailsRequestBuilder { - public interface ISubsidiaryDetailsRequestBuilder - { - SubsidiaryDetailsRequest CreateRequest(List rows); - } + SubsidiaryDetailsRequest CreateRequest(List rows); } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs index 6342e2b..49d4fe4 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Subsidiary/SubsidiaryDetailsRequestBuilder.cs @@ -1,30 +1,29 @@ using EPR.ProducerContentValidation.Application.Models; using EPR.ProducerContentValidation.Application.Models.Subsidiary; -namespace EPR.ProducerContentValidation.Application.Services.Subsidiary +namespace EPR.ProducerContentValidation.Application.Services.Subsidiary; + +public class SubsidiaryDetailsRequestBuilder : ISubsidiaryDetailsRequestBuilder { - public class SubsidiaryDetailsRequestBuilder : ISubsidiaryDetailsRequestBuilder + public SubsidiaryDetailsRequest CreateRequest(List rows) { - public SubsidiaryDetailsRequest CreateRequest(List rows) + var subsidiaryDetailsRequest = new SubsidiaryDetailsRequest { - var subsidiaryDetailsRequest = new SubsidiaryDetailsRequest - { - SubsidiaryOrganisationDetails = rows - .GroupBy(row => row.ProducerId) - .Where(group => group.Any(row => !string.IsNullOrEmpty(row.SubsidiaryId))) - .Select(group => new SubsidiaryOrganisationDetail - { - OrganisationReference = group.Key, - SubsidiaryDetails = group - .Where(row => !string.IsNullOrEmpty(row.SubsidiaryId)) - .Select(row => new SubsidiaryDetail - { - ReferenceNumber = row.SubsidiaryId, - }).ToList(), - }) - .ToList(), - }; - return subsidiaryDetailsRequest; - } + SubsidiaryOrganisationDetails = rows + .GroupBy(row => row.ProducerId) + .Where(group => group.Any(row => !string.IsNullOrEmpty(row.SubsidiaryId))) + .Select(group => new SubsidiaryOrganisationDetail + { + OrganisationReference = group.Key, + SubsidiaryDetails = group + .Where(row => !string.IsNullOrEmpty(row.SubsidiaryId)) + .Select(row => new SubsidiaryDetail + { + ReferenceNumber = row.SubsidiaryId, + }).ToList(), + }) + .ToList(), + }; + return subsidiaryDetailsRequest; } } From 4297850f8cff3428914d142c248a429b58203d12 Mon Sep 17 00:00:00 2001 From: Idris Abu Date: Sat, 2 Nov 2024 16:52:48 +0000 Subject: [PATCH 43/44] Augmented ValidationServiceTests to better highlight the aggregation of error code entries --- .../Services/ValidationServiceTests.cs | 60 +++++++++++++++++-- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs index 635d368..cd828bd 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/ValidationServiceTests.cs @@ -503,7 +503,7 @@ public async Task ValidateAsync_EnabledSubsidiaryValidation_NoErrorsFromSubsidia } [TestMethod] - public async Task ValidateAsync_EnabledSubsidiaryValidation_ErrorsFromSubsidiaryValidation_AggregatesErrors() + public async Task ValidateAsync_EnabledSubsidiaryValidation_ErrorsFromSubsidiaryValidation_AggregatesErrorsDistinctEntryPerErrorCode() { // Arrange var producerRows = new List @@ -515,11 +515,11 @@ public async Task ValidateAsync_EnabledSubsidiaryValidation_ErrorsFromSubsidiary var expectedErrors = new List { - new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Error1" }) + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", "Any old Blob Name", new List { "Error1" }) }; var validationErrors = new List { - new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", ErrorCodes: new List { "Error1" }) + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", "Any old Blob Name", ErrorCodes: new List { "Error1" }) }; _validationServiceProducerRowValidatorMock.Setup(x => x.ProcessRowsForValidationErrors(It.IsAny>(), It.IsAny())).Returns(validationErrors); @@ -532,7 +532,55 @@ public async Task ValidateAsync_EnabledSubsidiaryValidation_ErrorsFromSubsidiary .Callback, List, List, string>((rows, errors, warnings, blob) => { // No warnings - errors.Add(new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", string.Empty, new List { "Error1" })); + errors.Add(new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", "Any old Blob Name", new List { "Error2" })); + }); + + _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)).ReturnsAsync(true); + + var service = CreateSystemUnderTest(); + + // Act + var result = await service.ValidateAsync(producer); + + // Assert + result.ValidationWarnings.Should().BeEmpty(); + result.ValidationErrors.Count.Should().Be(1); + result.ValidationErrors[0].ErrorCodes.Count.Should().Be(2); + result.ValidationErrors[0].ErrorCodes[0].Should().Be("Error2"); + result.ValidationErrors[0].ErrorCodes[1].Should().Be("Error1"); + } + + [TestMethod] + public async Task ValidateAsync_EnabledSubsidiaryValidation_ErrorsFromSubsidiaryValidation_AggregatesErrorsSingleEntryForSameErrorCode() + { + // Arrange + var producerRows = new List + { + ModelGenerator.CreateProducerRow(1) + }; + + var producer = new Producer(_submissionId, ProducerId, BlobName, producerRows); + + var expectedErrors = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", "Any old Blob Name", new List { "Error1" }) + }; + var validationErrors = new List + { + new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", "Any old Blob Name", ErrorCodes: new List { "Error1" }) + }; + + _validationServiceProducerRowValidatorMock.Setup(x => x.ProcessRowsForValidationErrors(It.IsAny>(), It.IsAny())).Returns(validationErrors); + + // Mocking + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + _issueCountServiceMock.Setup(x => x.GetRemainingIssueCapacityAsync(It.IsAny())).ReturnsAsync(5); + + _compositeValidatorMock.Setup(x => x.ValidateAndFetchForIssuesAsync(It.IsAny>(), It.IsAny>(), It.IsAny>(), BlobName)) + .Callback, List, List, string>((rows, errors, warnings, blob) => + { + // No warnings + errors.Add(new ProducerValidationEventIssueRequest("Sub1", "2024Q1", 1, "Prod1", "TypeA", "Large", "WasteTypeA", "CategoryA", "MaterialA", "SubTypeA", "NationA", "NationB", "100", "10", "Any old Blob Name", new List { "Error1" })); }); _featureManagerMock.Setup(x => x.IsEnabledAsync(FeatureFlags.EnableSubsidiaryValidationPom)).ReturnsAsync(true); @@ -544,7 +592,9 @@ public async Task ValidateAsync_EnabledSubsidiaryValidation_ErrorsFromSubsidiary // Assert result.ValidationWarnings.Should().BeEmpty(); - result.ValidationErrors.Count.Should().Be(2); + result.ValidationErrors.Count.Should().Be(1); + result.ValidationErrors[0].ErrorCodes.Count.Should().Be(1); + result.ValidationErrors[0].ErrorCodes[0].Should().Be("Error1"); } [TestMethod] From a5af31b20486efec6812b8b8beaace888d715aba Mon Sep 17 00:00:00 2001 From: Fahad Ali Date: Mon, 4 Nov 2024 13:39:09 +0000 Subject: [PATCH 44/44] logger issue fixed --- .../Services/Helpers/SubsidiaryValidationEvaluatorTests.cs | 4 ++-- .../Services/Helpers/SubsidiaryValidationEvaluator.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs index 96099ad..751378b 100644 --- a/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs +++ b/src/EPR.ProducerContentValidation.Application.UnitTests/Services/Helpers/SubsidiaryValidationEvaluatorTests.cs @@ -15,14 +15,14 @@ namespace EPR.ProducerContentValidation.Application.UnitTests.Services.Helpers; [TestClass] public class SubsidiaryValidationEvaluatorTests { - private Mock _mockLogger; + private Mock> _mockLogger; private Mock _mockFormatter; private SubsidiaryValidationEvaluator _evaluator; [TestInitialize] public void Setup() { - _mockLogger = new Mock(); + _mockLogger = new Mock>(); _mockFormatter = new Mock(); _evaluator = new SubsidiaryValidationEvaluator(_mockLogger.Object, _mockFormatter.Object); } diff --git a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs index 1391e05..6975380 100644 --- a/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs +++ b/src/EPR.ProducerContentValidation.Application/Services/Helpers/SubsidiaryValidationEvaluator.cs @@ -9,10 +9,10 @@ namespace EPR.ProducerContentValidation.Application.Services.Helpers; public class SubsidiaryValidationEvaluator : ISubsidiaryValidationEvaluator { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IProducerValidationEventIssueRequestFormatter _producerValidationEventIssueRequestFormatter; - public SubsidiaryValidationEvaluator(ILogger logger, IProducerValidationEventIssueRequestFormatter producerValidationEventIssueRequestFormatter) + public SubsidiaryValidationEvaluator(ILogger logger, IProducerValidationEventIssueRequestFormatter producerValidationEventIssueRequestFormatter) { _logger = logger; _producerValidationEventIssueRequestFormatter = producerValidationEventIssueRequestFormatter;