using ApplicationLayer.InfrastructureServicesInterfaces; using ApplicationLayer.Services.VisaApplications.NeededServices; using Domains.VisaApplicationDomain; using FluentAssertions; using Infrastructure.Database; using Infrastructure.Database.VisaApplications.Repositories; using Infrastructure.Database.VisaApplications.Repositories.Exceptions; using VisaApi.Fakers.Applicants; using VisaApi.Fakers.Users; using VisaApi.Fakers.VisaApplications; using VisaApi.Services; using Xunit; namespace VisaApi.Tests.Infrastructure.Database.Repositories; [Collection(Collections.ContextUsingTestCollection)] public class VisaApplicationsRepositoryTests { private readonly static UserFaker userFaker = new(); private readonly static ApplicantFaker applicantFaker = new(GetDateTimeProvider()); private readonly static VisaApplicationFaker applicationFaker = new(GetDateTimeProvider()); /// Returns /// Database context /// Repository private static IVisaApplicationsRepository GetRepository(DatabaseContext context) => new VisaApplicationsRepository(context, context); /// Returns private static IDateTimeProvider GetDateTimeProvider() => new TestDateTimeProvider(); /// /// Test for method that should return empty if no applications added /// [Fact] private async Task GetOfApplicantForEmptyShouldReturnEmpty() { await using var context = InMemoryContextProvider.GetDbContext(); var repository = GetRepository(context); var user = userFaker.Generate(); var applicant = applicantFaker.Generate(); applicant.UserId = user.Id; await context.AddAsync(user); await context.AddAsync(applicant); await context.SaveChangesAsync(); var result = await repository.GetOfApplicantAsync(applicant.Id, CancellationToken.None); result.Should().BeEmpty(); } /// /// Test for method that should return added entities /// [Fact] private async Task GetOfApplicantForExistingShouldReturnEntities() { await using var context = InMemoryContextProvider.GetDbContext(); var repository = GetRepository(context); var user = userFaker.Generate(); var applicant = applicantFaker.Generate(); applicant.UserId = user.Id; await context.AddAsync(user); await context.AddAsync(applicant); var applications = new List(); for (var i = 0; i < 5; i++) { var application = applicationFaker.GenerateValid(applicant); applications.Add(application); await context.AddAsync(application); } await context.SaveChangesAsync(); var result = await repository.GetOfApplicantAsync(applicant.Id, CancellationToken.None); result.Should().Contain(applications).And.HaveSameCount(applications); } /// /// Test for method that should throw exception for not existing entities /// [Fact] private async Task GetApplicantIdByUserIdForNotExistingShouldThrow() { await using var context = InMemoryContextProvider.GetDbContext(); var repository = GetRepository(context); ApplicationNotFoundByApplicantAndApplicationIdException? result = null; await context.SaveChangesAsync(); try { await repository.GetByApplicantAndApplicationIdAsync(Guid.NewGuid(), Guid.NewGuid(), CancellationToken.None); } catch (Exception e) { result = e as ApplicationNotFoundByApplicantAndApplicationIdException; } result.Should().NotBeNull(); } /// /// Test for method that should throw exception for not existing applicant /// [Fact] private async Task GetApplicantIdByUserIdForNotExistingApplicantShouldThrow() { await using var context = InMemoryContextProvider.GetDbContext(); var repository = GetRepository(context); var user = userFaker.Generate(); var applicant = applicantFaker.Generate(); applicant.UserId = user.Id; var application = applicationFaker.GenerateValid(applicant); await context.AddAsync(user); await context.AddAsync(applicant); await context.AddAsync(application); ApplicationNotFoundByApplicantAndApplicationIdException? result = null; await context.SaveChangesAsync(); try { await repository.GetByApplicantAndApplicationIdAsync(Guid.NewGuid(), application.Id, CancellationToken.None); } catch (Exception e) { result = e as ApplicationNotFoundByApplicantAndApplicationIdException; } result.Should().NotBeNull(); } /// /// Test for method that should throw exception for not existing application /// [Fact] private async Task GetApplicantIdByUserIdForNotExistingApplicationShouldThrow() { await using var context = InMemoryContextProvider.GetDbContext(); var repository = GetRepository(context); var user = userFaker.Generate(); var applicant = applicantFaker.Generate(); applicant.UserId = user.Id; await context.AddAsync(user); await context.AddAsync(applicant); ApplicationNotFoundByApplicantAndApplicationIdException? result = null; await context.SaveChangesAsync(); try { await repository.GetByApplicantAndApplicationIdAsync(applicant.Id, Guid.NewGuid(), CancellationToken.None); } catch (Exception e) { result = e as ApplicationNotFoundByApplicantAndApplicationIdException; } result.Should().NotBeNull(); } /// /// Test for method /// that should throw exception for not accessible application /// [Fact] private async Task GetApplicantIdByUserIdForNotAccessibleApplicationShouldThrow() { await using var context = InMemoryContextProvider.GetDbContext(); var repository = GetRepository(context); var user = userFaker.Generate(); var applicant = applicantFaker.Generate(); applicant.UserId = user.Id; var otherUser = userFaker.Generate(); var otherApplicant = applicantFaker.Generate(); otherApplicant.UserId = user.Id; var notAccessibleApplication = applicationFaker.GenerateValid(otherApplicant); await context.AddAsync(user); await context.AddAsync(applicant); await context.AddAsync(otherUser); await context.AddAsync(otherApplicant); await context.AddAsync(notAccessibleApplication); ApplicationNotFoundByApplicantAndApplicationIdException? result = null; await context.SaveChangesAsync(); try { await repository.GetByApplicantAndApplicationIdAsync(applicant.Id, notAccessibleApplication.Id, CancellationToken.None); } catch (Exception e) { result = e as ApplicationNotFoundByApplicantAndApplicationIdException; } result.Should().NotBeNull(); } /// /// Test for method /// that should return application for valid identifiers /// [Fact] private async Task GetApplicantIdByUserIdForValidIdsShouldReturnApplication() { await using var context = InMemoryContextProvider.GetDbContext(); var repository = GetRepository(context); var user = userFaker.Generate(); var applicant = applicantFaker.Generate(); applicant.UserId = user.Id; var application = applicationFaker.GenerateValid(applicant); await context.AddAsync(user); await context.AddAsync(applicant); await context.AddAsync(application); await context.SaveChangesAsync(); var result = await repository.GetByApplicantAndApplicationIdAsync(applicant.Id, application.Id, CancellationToken.None); result.Should().Be(application); } /// /// Test for method that should return empty from empty db /// [Fact] private async Task GetPendingApplicationsForEmptyShouldReturnEmpty() { await using var context = InMemoryContextProvider.GetDbContext(); var repository = GetRepository(context); var result = await repository.GetPendingApplicationsAsync(CancellationToken.None); result.Should().BeEmpty(); } /// /// Test for method that should return pending applications from not empty db /// [Fact] private async Task GetPendingApplicationsForExistingShouldReturnExistingPending() { await using var context = InMemoryContextProvider.GetDbContext(); var repository = GetRepository(context); var user = userFaker.Generate(); var applicant = applicantFaker.Generate(); applicant.UserId = user.Id; var applicationPending = applicationFaker.GenerateValid(applicant); applicationPending.Status = ApplicationStatus.Pending; var applicationNotPending = applicationFaker.GenerateValid(applicant); applicationNotPending.Status = ApplicationStatus.Approved; await context.AddAsync(user); await context.AddAsync(applicant); await context.AddAsync(applicationPending); await context.AddAsync(applicationNotPending); await context.SaveChangesAsync(); var result = await repository.GetPendingApplicationsAsync(CancellationToken.None); result.Should().Contain(applicationPending).And.HaveCount(1); } }