diff --git a/Streetcode/Streetcode.BLL/MediatR/Toponyms/GetByStreetcodeId/GetToponymsByStreetcodeIdHandler.cs b/Streetcode/Streetcode.BLL/MediatR/Toponyms/GetByStreetcodeId/GetToponymsByStreetcodeIdHandler.cs index cbbe319..11cf5ef 100644 --- a/Streetcode/Streetcode.BLL/MediatR/Toponyms/GetByStreetcodeId/GetToponymsByStreetcodeIdHandler.cs +++ b/Streetcode/Streetcode.BLL/MediatR/Toponyms/GetByStreetcodeId/GetToponymsByStreetcodeIdHandler.cs @@ -1,6 +1,8 @@ using AutoMapper; +using AutoMapper.QueryableExtensions; using FluentResults; using MediatR; +using Microsoft.EntityFrameworkCore; using Streetcode.BLL.DTO.Toponyms; using Microsoft.EntityFrameworkCore; using Streetcode.BLL.Interfaces.Logging; @@ -27,11 +29,11 @@ public GetToponymsByStreetcodeIdHandler(IRepositoryWrapper repositoryWrapper, IM public async Task>> Handle(GetToponymsByStreetcodeIdQuery request, CancellationToken cancellationToken) { - List toponyms = await _repositoryWrapper.ToponymRepository.FindAll( + List toponyms = _repositoryWrapper.ToponymRepository.FindAll( sc => sc.Streetcodes.Any(s => s.Id == request.StreetcodeId) - ).DistinctBy(t => t.StreetName).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(cancellationToken); + ).DistinctBy(t => t.StreetName).ProjectTo(_mapper.ConfigurationProvider).ToList(); - if(toponyms.Count == 0) + if (toponyms.Count == 0) { string errorMsg = $"Cannot find any toponym by the streetcode id: {request.StreetcodeId}"; _logger.LogError(request, errorMsg); diff --git a/Streetcode/Streetcode.XUnitTest/BLL/MediatR/Toponyms/GetAllToponymsHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/BLL/MediatR/Toponyms/GetAllToponymsHandlerTests.cs new file mode 100644 index 0000000..db8b552 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/BLL/MediatR/Toponyms/GetAllToponymsHandlerTests.cs @@ -0,0 +1,202 @@ +namespace Streetcode.XUnitTest.BLL.MediatR.Toponyms +{ + using AutoMapper; + using FluentAssertions; + using Moq; + using Streetcode.BLL.DTO.Toponyms; + using Streetcode.BLL.Interfaces.Logging; + using Streetcode.BLL.MediatR.Toponyms.GetAll; + using Streetcode.DAL.Entities.Toponyms; + using Streetcode.DAL.Repositories.Interfaces.Base; + using Streetcode.DAL.Repositories.Interfaces.Toponyms; + using Xunit; + + /// + /// Contains tests for . + /// + public sealed class GetAllToponymsHandlerTests + { + private readonly IMapper mapper; + private readonly Mock loggerMock; + private readonly Mock repositoryWrapperMock; + private readonly Mock toponymRepositoryMock; + private readonly GetAllToponymsHandler handler; + + /// + /// Initializes a new instance of the class. + /// + public GetAllToponymsHandlerTests() + { + this.mapper = new MapperConfiguration(cfg => + { + cfg.CreateMap(); + }).CreateMapper(); + this.loggerMock = new Mock(); + this.repositoryWrapperMock = new Mock(); + this.toponymRepositoryMock = new Mock(); + this.repositoryWrapperMock.Setup(r => r.ToponymRepository).Returns(this.toponymRepositoryMock.Object); + this.handler = new GetAllToponymsHandler(this.repositoryWrapperMock.Object, this.mapper, this.loggerMock.Object); + } + + /// + /// Should return all toponyms when . + /// + /// Awaitable task. + [Fact] + public async Task Handle_ShouldReturnAllToponyms_WhenNoTitleProvided() + { + // Arrange + IQueryable toponyms = new List + { + new() + { + Id = 1, + StreetName = "Шевченка", + }, + new() + { + Id = 2, + StreetName = "Бандери", + }, + }.AsQueryable(); + List expected_toponyms = new() + { + this.mapper.Map(toponyms.ElementAt(0)), + this.mapper.Map(toponyms.ElementAt(1)), + }; + GetAllToponymsQuery query = new(new GetAllToponymsRequestDTO + { + Title = null, + }); + this.toponymRepositoryMock.Setup(r => r.FindAll(null)).Returns(toponyms); + + // Act + var result = await this.handler.Handle(query, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Toponyms.Should().BeEquivalentTo(expected_toponyms); + this.toponymRepositoryMock.Verify(r => r.FindAll(null), Times.Once); + } + + /// + /// Should return filtered toponyms when . + /// Must be case-insensitive. + /// + /// Awaitable task. + [Fact] + public async Task Handle_ShouldFilterToponyms_WhenTitleProvided_CaseInsensitive() + { + // Arrange + IQueryable toponyms = new List + { + new() + { + Id = 1, + StreetName = "Шевченка", + }, + new() + { + Id = 2, + StreetName = "Бандери", + }, + }.AsQueryable(); + List expected_toponyms = new() + { + this.mapper.Map(toponyms.ElementAt(1)), + }; + GetAllToponymsQuery query = new(new GetAllToponymsRequestDTO + { + Title = "аНдЕр", + }); + this.toponymRepositoryMock.Setup(r => r.FindAll(null)).Returns(toponyms); + + // Act + var result = await this.handler.Handle(query, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Toponyms.Should().BeEquivalentTo(expected_toponyms); + this.toponymRepositoryMock.Verify(r => r.FindAll(null), Times.Once); + } + + /// + /// Should return unique toponyms when . + /// + /// Awaitable task. + [Fact] + public async Task Handle_ShouldReturnUniqueToponyms_WhenTitleProvided() + { + // Arrange + IQueryable toponyms = new List + { + new() + { + Id = 1, + StreetName = "Шевченка", + Oblast = "Київська", + }, + new() + { + Id = 2, + StreetName = "Шевченка", + Oblast = "Львівська", + }, + }.AsQueryable(); + List expected_toponyms = new() + { + this.mapper.Map(toponyms.ElementAt(0)), + }; + GetAllToponymsQuery query = new(new GetAllToponymsRequestDTO + { + Title = "евч", + }); + this.toponymRepositoryMock.Setup(r => r.FindAll(null)).Returns(toponyms); + + // Act + var result = await this.handler.Handle(query, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Toponyms.Should().BeEquivalentTo(expected_toponyms); + this.toponymRepositoryMock.Verify(r => r.FindAll(null), Times.Once); + } + + /// + /// Should return empty collection when no matches found. + /// + /// Awaitable task. + [Fact] + public async Task Handle_ShouldReturnEmptyCollection_WhenNoMatchesFound() + { + // Arrange + IQueryable toponyms = new List + { + new() + { + Id = 1, + StreetName = "Шевченка", + }, + new() + { + Id = 2, + StreetName = "Бандери", + }, + }.AsQueryable(); + List expected_toponyms = new(); + GetAllToponymsQuery query = new(new GetAllToponymsRequestDTO + { + Title = "ийськ", + }); + this.toponymRepositoryMock.Setup(r => r.FindAll(null)).Returns(toponyms); + + // Act + var result = await this.handler.Handle(query, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Toponyms.Should().BeEquivalentTo(expected_toponyms); + this.toponymRepositoryMock.Verify(r => r.FindAll(null), Times.Once); + } + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/BLL/MediatR/Toponyms/GetToponymByIdHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/BLL/MediatR/Toponyms/GetToponymByIdHandlerTests.cs new file mode 100644 index 0000000..0b88c8a --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/BLL/MediatR/Toponyms/GetToponymByIdHandlerTests.cs @@ -0,0 +1,117 @@ +namespace Streetcode.XUnitTest.BLL.MediatR.Toponyms +{ + using System.Linq.Expressions; + using AutoMapper; + using FluentAssertions; + using Moq; + using Streetcode.BLL.DTO.Toponyms; + using Streetcode.BLL.Interfaces.Logging; + using Streetcode.BLL.MediatR.Toponyms.GetById; + using Streetcode.DAL.Entities.Toponyms; + using Streetcode.DAL.Repositories.Interfaces.Base; + using Streetcode.DAL.Repositories.Interfaces.Toponyms; + using Xunit; + + /// + /// Contains tests for . + /// + public sealed class GetToponymByIdHandlerTests + { + private readonly IMapper mapper; + private readonly Mock loggerMock; + private readonly Mock repositoryWrapperMock; + private readonly Mock toponymRepositoryMock; + private readonly GetToponymByIdHandler handler; + + /// + /// Initializes a new instance of the class. + /// + public GetToponymByIdHandlerTests() + { + this.mapper = new MapperConfiguration(cfg => + { + cfg.CreateMap(); + }).CreateMapper(); + this.loggerMock = new Mock(); + this.repositoryWrapperMock = new Mock(); + this.toponymRepositoryMock = new Mock(); + this.repositoryWrapperMock.Setup(r => r.ToponymRepository).Returns(this.toponymRepositoryMock.Object); + this.handler = new GetToponymByIdHandler(this.repositoryWrapperMock.Object, this.mapper, this.loggerMock.Object); + } + + /// + /// Should return toponym when found by id. + /// + /// Awaitable task. + [Fact] + public async Task Handle_ShouldReturnToponym_WhenFound() + { + // Arrange + Toponym toponym = new() + { + Id = 2, + StreetName = "Бандери", + }; + ToponymDTO expected_toponym = this.mapper.Map(toponym); + GetToponymByIdQuery query = new(2); + this.toponymRepositoryMock.Setup( + r => r.GetFirstOrDefaultAsync( + It.IsAny>>(), + null + ) + ).ReturnsAsync(toponym); + + // Act + var result = await this.handler.Handle(query, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Should().BeEquivalentTo(expected_toponym); + this.toponymRepositoryMock.Verify( + r => r.GetFirstOrDefaultAsync( + It.IsAny>>(), + null + ), + Times.Once + ); + } + + /// + /// Should return error and log it when toponym not found by id. + /// + /// Awaitable task. + [Fact] + public async Task Handle_ShouldReturnError_WhenNotFound() + { + // Arrange + GetToponymByIdQuery query = new(1); + this.toponymRepositoryMock.Setup( + r => r.GetFirstOrDefaultAsync( + It.IsAny>>(), + null + ) + ).ReturnsAsync(null as Toponym); + this.loggerMock.Setup( + l => l.LogError(query, It.IsAny()) + ); + + // Act + var result = await this.handler.Handle(query, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeFalse(); + result.Errors.Should().NotBeEmpty(); + this.toponymRepositoryMock.Verify( + r => r.GetFirstOrDefaultAsync( + It.IsAny>>(), + null + ), + Times.Once + ); + this.loggerMock.Verify( + l => l.LogError(query, It.IsAny()), + Times.Once + ); + } + } +} \ No newline at end of file diff --git a/Streetcode/Streetcode.XUnitTest/BLL/MediatR/Toponyms/GetToponymsByStreetcodeIdHandlerTests.cs b/Streetcode/Streetcode.XUnitTest/BLL/MediatR/Toponyms/GetToponymsByStreetcodeIdHandlerTests.cs new file mode 100644 index 0000000..de85c04 --- /dev/null +++ b/Streetcode/Streetcode.XUnitTest/BLL/MediatR/Toponyms/GetToponymsByStreetcodeIdHandlerTests.cs @@ -0,0 +1,210 @@ +namespace Streetcode.XUnitTest.BLL.MediatR.Toponyms +{ + using AutoMapper; + using Moq; + using Streetcode.BLL.DTO.Toponyms; + using Streetcode.BLL.Interfaces.Logging; + using Streetcode.DAL.Entities.Toponyms; + using Streetcode.DAL.Repositories.Interfaces.Base; + using Streetcode.DAL.Repositories.Interfaces.Toponyms; + using Xunit; + using DAL.Entities.Streetcode; + using Streetcode.BLL.MediatR.Toponyms.GetByStreetcodeId; + using System.Linq.Expressions; + using Streetcode.BLL.DTO.Streetcode; + using FluentAssertions; + using Streetcode.DAL.Entities.AdditionalContent.Coordinates.Types; + using Streetcode.BLL.DTO.AdditionalContent.Coordinates.Types; + using Streetcode.DAL.Entities.AdditionalContent; + using Streetcode.BLL.DTO.AdditionalContent.Tag; + + /// + /// Initializes a new instance of the class. + /// + public sealed class GetToponymsByStreetcodeIdHandlerTests + { + private readonly IMapper mapper; + private readonly Mock loggerMock; + private readonly Mock repositoryWrapperMock; + private readonly Mock toponymRepositoryMock; + private readonly GetToponymsByStreetcodeIdHandler handler; + + /// + /// Initializes a new instance of the class. + /// + public GetToponymsByStreetcodeIdHandlerTests() + { + this.mapper = new MapperConfiguration(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap(); + }).CreateMapper(); + this.loggerMock = new Mock(); + this.repositoryWrapperMock = new Mock(); + this.toponymRepositoryMock = new Mock(); + this.repositoryWrapperMock.Setup(r => r.ToponymRepository).Returns(this.toponymRepositoryMock.Object); + this.handler = new GetToponymsByStreetcodeIdHandler(this.repositoryWrapperMock.Object, this.mapper, this.loggerMock.Object); + } + + /// + /// Should return toponyms when found by streetcode id. + /// + /// Awaitable task. + [Fact] + public async Task Handle_ShouldReturnToponyms_WhenFound() + { + // Arrange + IQueryable toponyms = new List() + { + new() + { + Id = 1, + StreetName = "Шевченка", + Oblast = "Київська", + Streetcodes = new List() + { + new() + { + Id = 1, + }, + new() + { + Id = 2, + }, + }, + }, + }.AsQueryable(); + List expected_toponyms = new() + { + this.mapper.Map(toponyms.First()), + }; + GetToponymsByStreetcodeIdQuery query = new(1); + this.toponymRepositoryMock.Setup( + r => r.FindAll( + It.IsAny>>() + ) + ).Returns(toponyms); + + // Act + var result = await this.handler.Handle(query, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Should().BeEquivalentTo(expected_toponyms); + this.toponymRepositoryMock.Verify( + r => r.FindAll( + It.IsAny>>() + ), + Times.Once + ); + } + + /// + /// Should return toponyms with unique street name when found by streetcode id. + /// + /// Awaitable task. + [Fact] + public async Task Handle_ShouldReturnUniqueToponyms_WhenFound() + { + // Arrange + IQueryable toponyms = new List() + { + new() + { + Id = 1, + StreetName = "Шевченка", + Oblast = "Київська", + Streetcodes = new List() + { + new() + { + Id = 1, + }, + new() + { + Id = 2, + }, + }, + }, + new() + { + Id = 2, + StreetName = "Шевченка", + Oblast = "Львівська", + Streetcodes = new List() + { + new() + { + Id = 1, + }, + new() + { + Id = 2, + }, + }, + }, + }.AsQueryable(); + List expected_toponyms = new() + { + this.mapper.Map(toponyms.First()), + }; + GetToponymsByStreetcodeIdQuery query = new(1); + this.toponymRepositoryMock.Setup( + r => r.FindAll( + It.IsAny>>() + ) + ).Returns(toponyms); + + // Act + var result = await this.handler.Handle(query, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeTrue(); + result.Value.Should().BeEquivalentTo(expected_toponyms); + this.toponymRepositoryMock.Verify( + r => r.FindAll( + It.IsAny>>() + ), + Times.Once + ); + } + + /// + /// Should return error and log it when toponyms not found by streetcode id. + /// + /// Awaitable task. + [Fact] + public async Task Handle_ShouldReturnError_WhenNotFound() + { + // Arrange + GetToponymsByStreetcodeIdQuery query = new(3); + this.toponymRepositoryMock.Setup( + r => r.FindAll( + It.IsAny>>() + ) + ).Returns(Enumerable.Empty().AsQueryable()); + this.loggerMock.Setup( + l => l.LogError(query, It.IsAny()) + ); + + // Act + var result = await this.handler.Handle(query, CancellationToken.None); + + // Assert + result.IsSuccess.Should().BeFalse(); + result.Errors.Should().NotBeEmpty(); + this.toponymRepositoryMock.Verify( + r => r.FindAll( + It.IsAny>>() + ), + Times.Once + ); + this.loggerMock.Verify( + l => l.LogError(query, It.IsAny()), + Times.Once + ); + } + } +} \ No newline at end of file