using Distribution.Features.Region; using Distribution.Infra.UoW; using Distribution.Models; using Moq; using Xunit; namespace Distribution.Tests.Services; public class RegionServiceTests { private readonly Mock _repo = new(); private readonly Mock _uow = new(); private readonly RegionService _sut; public RegionServiceTests() { _sut = new RegionService(_repo.Object, _uow.Object); } private static Region ActiveRegion(string name = "North") => new() { Id = Guid.NewGuid(), Name = name, IsActive = true }; private static Region InactiveRegion() => new() { Id = Guid.NewGuid(), Name = "Old", IsActive = false }; // GetAllAsync [Fact] public async Task GetAllAsync_ReturnsOnlyActiveRegions() { _repo.Setup(r => r.GetAllAsync()).ReturnsAsync([ActiveRegion(), InactiveRegion()]); var result = await _sut.GetAllAsync(); Assert.Single(result); Assert.True(result[0].IsActive); } [Fact] public async Task GetAllAsync_ReturnsEmpty_WhenNoneActive() { _repo.Setup(r => r.GetAllAsync()).ReturnsAsync([InactiveRegion()]); var result = await _sut.GetAllAsync(); Assert.Empty(result); } // GetByIdAsync [Fact] public async Task GetByIdAsync_ReturnsNull_WhenNotFound() { _repo.Setup(r => r.GetByIdAsync(It.IsAny())).ReturnsAsync((Region?)null); var result = await _sut.GetByIdAsync(Guid.NewGuid()); Assert.Null(result); } [Fact] public async Task GetByIdAsync_ReturnsNull_WhenInactive() { _repo.Setup(r => r.GetByIdAsync(It.IsAny())).ReturnsAsync(InactiveRegion()); var result = await _sut.GetByIdAsync(Guid.NewGuid()); Assert.Null(result); } [Fact] public async Task GetByIdAsync_ReturnsResponse_WhenActiveRegionFound() { var region = ActiveRegion("South"); _repo.Setup(r => r.GetByIdAsync(region.Id)).ReturnsAsync(region); var result = await _sut.GetByIdAsync(region.Id); Assert.NotNull(result); Assert.Equal("South", result.Name); Assert.Equal(region.Id, result.Id); } // CreateAsync [Fact] public async Task CreateAsync_AddsRegion_AndCommits() { var request = new CreateRegionRequest("East"); var result = await _sut.CreateAsync(request); _uow.Verify(u => u.BeginAsync(default), Times.Once); _repo.Verify(r => r.AddAsync(It.Is(x => x.Name == "East")), Times.Once); _uow.Verify(u => u.CommitAsync(default), Times.Once); Assert.Equal("East", result.Name); } [Fact] public async Task CreateAsync_Rollbacks_WhenAddThrows() { _repo.Setup(r => r.AddAsync(It.IsAny())).ThrowsAsync(new Exception("db error")); await Assert.ThrowsAsync(() => _sut.CreateAsync(new CreateRegionRequest("X"))); _uow.Verify(u => u.RollbackAsync(default), Times.Once); _uow.Verify(u => u.CommitAsync(default), Times.Never); } // UpdateAsync [Fact] public async Task UpdateAsync_ReturnsNull_WhenNotFound() { _repo.Setup(r => r.GetByIdAsync(It.IsAny())).ReturnsAsync((Region?)null); var result = await _sut.UpdateAsync(Guid.NewGuid(), new UpdateRegionRequest("New")); Assert.Null(result); _uow.Verify(u => u.BeginAsync(default), Times.Never); } [Fact] public async Task UpdateAsync_ReturnsNull_WhenInactive() { _repo.Setup(r => r.GetByIdAsync(It.IsAny())).ReturnsAsync(InactiveRegion()); var result = await _sut.UpdateAsync(Guid.NewGuid(), new UpdateRegionRequest("New")); Assert.Null(result); } [Fact] public async Task UpdateAsync_UpdatesName_AndCommits() { var region = ActiveRegion("Old Name"); _repo.Setup(r => r.GetByIdAsync(region.Id)).ReturnsAsync(region); var result = await _sut.UpdateAsync(region.Id, new UpdateRegionRequest("New Name")); Assert.NotNull(result); Assert.Equal("New Name", result.Name); _uow.Verify(u => u.BeginAsync(default), Times.Once); _uow.Verify(u => u.CommitAsync(default), Times.Once); } // DeleteAsync [Fact] public async Task DeleteAsync_ReturnsFalse_WhenNotFound() { _repo.Setup(r => r.GetByIdAsync(It.IsAny())).ReturnsAsync((Region?)null); var result = await _sut.DeleteAsync(Guid.NewGuid()); Assert.False(result); _uow.Verify(u => u.BeginAsync(default), Times.Never); } [Fact] public async Task DeleteAsync_ReturnsFalse_WhenInactive() { _repo.Setup(r => r.GetByIdAsync(It.IsAny())).ReturnsAsync(InactiveRegion()); var result = await _sut.DeleteAsync(Guid.NewGuid()); Assert.False(result); } [Fact] public async Task DeleteAsync_CallsRemove_AndCommits() { var region = ActiveRegion(); _repo.Setup(r => r.GetByIdAsync(region.Id)).ReturnsAsync(region); var result = await _sut.DeleteAsync(region.Id); Assert.True(result); _repo.Verify(r => r.Remove(region), Times.Once); _uow.Verify(u => u.CommitAsync(default), Times.Once); } [Fact] public async Task DeleteAsync_Rollbacks_WhenRemoveThrows() { var region = ActiveRegion(); _repo.Setup(r => r.GetByIdAsync(region.Id)).ReturnsAsync(region); _repo.Setup(r => r.Remove(It.IsAny())).Throws(new Exception("db error")); await Assert.ThrowsAsync(() => _sut.DeleteAsync(region.Id)); _uow.Verify(u => u.RollbackAsync(default), Times.Once); } }