using Distribution.Infra.Authorization; using Moq; using Xunit; namespace Distribution.Tests.Services; public class ScopeAccessServiceTests { private readonly Mock _repo = new(); private readonly ScopeAccessService _sut; private readonly Guid _userId = Guid.NewGuid(); public ScopeAccessServiceTests() { _sut = new ScopeAccessService(_repo.Object); } // Delegation tests [Fact] public async Task HasStoreScopeAsync_DelegatesToRepository() { var storeId = Guid.NewGuid(); _repo.Setup(r => r.HasStoreScopeAsync(_userId, storeId)).ReturnsAsync(true); var result = await _sut.HasStoreScopeAsync(_userId, storeId); Assert.True(result); _repo.Verify(r => r.HasStoreScopeAsync(_userId, storeId), Times.Once); } [Fact] public async Task HasRouteScopeAsync_DelegatesToRepository() { var routeId = Guid.NewGuid(); _repo.Setup(r => r.HasRouteScopeAsync(_userId, routeId)).ReturnsAsync(false); var result = await _sut.HasRouteScopeAsync(_userId, routeId); Assert.False(result); } [Fact] public async Task HasRegionScopeAsync_DelegatesToRepository() { var regionId = Guid.NewGuid(); _repo.Setup(r => r.HasRegionScopeAsync(_userId, regionId)).ReturnsAsync(true); var result = await _sut.HasRegionScopeAsync(_userId, regionId); Assert.True(result); } // GetAccessibleStoreIdsAsync [Fact] public async Task GetAccessibleStoreIdsAsync_ReturnsEmpty_WhenNoAssignments() { _repo.Setup(r => r.GetDirectStoreIdsAsync(_userId)).ReturnsAsync([]); _repo.Setup(r => r.GetRouteIdsAsync(_userId)).ReturnsAsync([]); _repo.Setup(r => r.GetRegionIdsAsync(_userId)).ReturnsAsync([]); _repo.Setup(r => r.GetStoreIdsByRouteIdsAsync(It.IsAny>())).ReturnsAsync([]); _repo.Setup(r => r.GetRouteIdsByRegionIdsAsync(It.IsAny>())).ReturnsAsync([]); var result = await _sut.GetAccessibleStoreIdsAsync(_userId); Assert.Empty(result); } [Fact] public async Task GetAccessibleStoreIdsAsync_ReturnsDirectStores() { var storeId = Guid.NewGuid(); _repo.Setup(r => r.GetDirectStoreIdsAsync(_userId)).ReturnsAsync([storeId]); _repo.Setup(r => r.GetRouteIdsAsync(_userId)).ReturnsAsync([]); _repo.Setup(r => r.GetRegionIdsAsync(_userId)).ReturnsAsync([]); _repo.Setup(r => r.GetStoreIdsByRouteIdsAsync(It.IsAny>())).ReturnsAsync([]); _repo.Setup(r => r.GetRouteIdsByRegionIdsAsync(It.IsAny>())).ReturnsAsync([]); var result = await _sut.GetAccessibleStoreIdsAsync(_userId); Assert.Single(result); Assert.Contains(storeId, result); } [Fact] public async Task GetAccessibleStoreIdsAsync_IncludesStoresViaRoute() { var routeId = Guid.NewGuid(); var storeViaRoute = Guid.NewGuid(); _repo.Setup(r => r.GetDirectStoreIdsAsync(_userId)).ReturnsAsync([]); _repo.Setup(r => r.GetRouteIdsAsync(_userId)).ReturnsAsync([routeId]); _repo.Setup(r => r.GetRegionIdsAsync(_userId)).ReturnsAsync([]); _repo.Setup(r => r.GetStoreIdsByRouteIdsAsync(new List { routeId })).ReturnsAsync([storeViaRoute]); _repo.Setup(r => r.GetRouteIdsByRegionIdsAsync(It.IsAny>())).ReturnsAsync([]); _repo.Setup(r => r.GetStoreIdsByRouteIdsAsync(new List())).ReturnsAsync([]); var result = await _sut.GetAccessibleStoreIdsAsync(_userId); Assert.Contains(storeViaRoute, result); } [Fact] public async Task GetAccessibleStoreIdsAsync_IncludesStoresViaRegion() { var regionId = Guid.NewGuid(); var routeViaRegion = Guid.NewGuid(); var storeViaRegion = Guid.NewGuid(); _repo.Setup(r => r.GetDirectStoreIdsAsync(_userId)).ReturnsAsync([]); _repo.Setup(r => r.GetRouteIdsAsync(_userId)).ReturnsAsync([]); _repo.Setup(r => r.GetRegionIdsAsync(_userId)).ReturnsAsync([regionId]); _repo.Setup(r => r.GetStoreIdsByRouteIdsAsync(new List())).ReturnsAsync([]); _repo.Setup(r => r.GetRouteIdsByRegionIdsAsync(new List { regionId })).ReturnsAsync([routeViaRegion]); _repo.Setup(r => r.GetStoreIdsByRouteIdsAsync(new List { routeViaRegion })).ReturnsAsync([storeViaRegion]); var result = await _sut.GetAccessibleStoreIdsAsync(_userId); Assert.Contains(storeViaRegion, result); } [Fact] public async Task GetAccessibleStoreIdsAsync_DeduplicatesStores() { var sharedStoreId = Guid.NewGuid(); var routeId = Guid.NewGuid(); _repo.Setup(r => r.GetDirectStoreIdsAsync(_userId)).ReturnsAsync([sharedStoreId]); _repo.Setup(r => r.GetRouteIdsAsync(_userId)).ReturnsAsync([routeId]); _repo.Setup(r => r.GetRegionIdsAsync(_userId)).ReturnsAsync([]); _repo.Setup(r => r.GetStoreIdsByRouteIdsAsync(new List { routeId })).ReturnsAsync([sharedStoreId]); _repo.Setup(r => r.GetRouteIdsByRegionIdsAsync(It.IsAny>())).ReturnsAsync([]); _repo.Setup(r => r.GetStoreIdsByRouteIdsAsync(new List())).ReturnsAsync([]); var result = await _sut.GetAccessibleStoreIdsAsync(_userId); Assert.Single(result); Assert.Equal(sharedStoreId, result[0]); } [Fact] public async Task GetAccessibleStoreIdsAsync_CombinesAllSources() { var directStore = Guid.NewGuid(); var routeStore = Guid.NewGuid(); var regionStore = Guid.NewGuid(); var routeId = Guid.NewGuid(); var regionId = Guid.NewGuid(); var routeViaRegion = Guid.NewGuid(); _repo.Setup(r => r.GetDirectStoreIdsAsync(_userId)).ReturnsAsync([directStore]); _repo.Setup(r => r.GetRouteIdsAsync(_userId)).ReturnsAsync([routeId]); _repo.Setup(r => r.GetRegionIdsAsync(_userId)).ReturnsAsync([regionId]); _repo.Setup(r => r.GetStoreIdsByRouteIdsAsync(new List { routeId })).ReturnsAsync([routeStore]); _repo.Setup(r => r.GetRouteIdsByRegionIdsAsync(new List { regionId })).ReturnsAsync([routeViaRegion]); _repo.Setup(r => r.GetStoreIdsByRouteIdsAsync(new List { routeViaRegion })).ReturnsAsync([regionStore]); var result = await _sut.GetAccessibleStoreIdsAsync(_userId); Assert.Equal(3, result.Count); Assert.Contains(directStore, result); Assert.Contains(routeStore, result); Assert.Contains(regionStore, result); } }