using FluentAssertions; using Moq; using TakeoutSaaS.Application.App.Tenants.Handlers; using TakeoutSaaS.Application.App.Tenants.Queries; using TakeoutSaaS.Application.Tests.TestUtilities; using TakeoutSaaS.Domain.Tenants.Repositories; using TakeoutSaaS.Shared.Abstractions.Security; using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.Tests.App.Tenants.Handlers; public sealed class GetTenantsAnnouncementsQueryHandlerTests { [Fact] public async Task GivenQuery_WhenHandle_ThenUsesTenantProviderAndOrdersAndPaginates() { // Arrange var tenantProvider = new Mock(); tenantProvider.Setup(x => x.GetCurrentTenantId()).Returns(42); var currentUserAccessor = new Mock(); currentUserAccessor.SetupGet(x => x.UserId).Returns(0); currentUserAccessor.SetupGet(x => x.IsAuthenticated).Returns(false); var announcements = new List { AnnouncementTestData.CreateAnnouncement(1, 42, priority: 1, effectiveFrom: DateTime.UtcNow.AddDays(-1)), AnnouncementTestData.CreateAnnouncement(2, 42, priority: 2, effectiveFrom: DateTime.UtcNow.AddDays(-3)), AnnouncementTestData.CreateAnnouncement(3, 42, priority: 2, effectiveFrom: DateTime.UtcNow.AddDays(-1)), AnnouncementTestData.CreateAnnouncement(4, 42, priority: 0, effectiveFrom: DateTime.UtcNow) }; // 模拟数据库端排序:按 priority DESC, effectiveFrom DESC var sortedAnnouncements = announcements .OrderByDescending(x => x.Priority) .ThenByDescending(x => x.EffectiveFrom) .ToList(); var announcementRepository = new Mock(); announcementRepository .Setup(x => x.SearchAsync( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(sortedAnnouncements); var announcementReadRepository = new Mock(); announcementReadRepository .Setup(x => x.GetByAnnouncementAsync( It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny())) .ReturnsAsync(Array.Empty()); var handler = new GetTenantsAnnouncementsQueryHandler( announcementRepository.Object, announcementReadRepository.Object, tenantProvider.Object, currentUserAccessor.Object); var query = new GetTenantsAnnouncementsQuery { TenantId = 999, Page = 2, PageSize = 2 }; // Act var result = await handler.Handle(query, CancellationToken.None); // Assert announcementRepository.Verify(x => x.SearchAsync( 42, query.Keyword, query.Status, query.AnnouncementType, query.IsActive, query.EffectiveFrom, query.EffectiveTo, null, true, 12, // estimatedLimit = page * size * 3 = 2 * 2 * 3 = 12 It.IsAny()), Times.Once); result.TotalCount.Should().Be(4); result.Items.Select(x => x.Id).Should().Equal(1, 4); result.Page.Should().Be(2); result.PageSize.Should().Be(2); } [Fact] public async Task GivenOnlyEffective_WhenHandle_ThenFiltersScheduledPublish() { // Arrange var tenantProvider = new Mock(); tenantProvider.Setup(x => x.GetCurrentTenantId()).Returns(42); var announcement1 = AnnouncementTestData.CreateAnnouncement(1, 42, priority: 1, effectiveFrom: DateTime.UtcNow.AddDays(-1)); announcement1.ScheduledPublishAt = DateTime.UtcNow.AddMinutes(-10); var announcement2 = AnnouncementTestData.CreateAnnouncement(2, 42, priority: 1, effectiveFrom: DateTime.UtcNow.AddDays(-1)); announcement2.ScheduledPublishAt = DateTime.UtcNow.AddMinutes(30); var announcements = new List { announcement1, announcement2 }; var announcementRepository = new Mock(); announcementRepository .Setup(x => x.SearchAsync( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(announcements); var announcementReadRepository = new Mock(); announcementReadRepository .Setup(x => x.GetByAnnouncementAsync( It.IsAny(), It.IsAny>(), It.IsAny(), It.IsAny())) .ReturnsAsync(Array.Empty()); var handler = new GetTenantsAnnouncementsQueryHandler( announcementRepository.Object, announcementReadRepository.Object, tenantProvider.Object); var query = new GetTenantsAnnouncementsQuery { OnlyEffective = true, Page = 1, PageSize = 10 }; // Act var result = await handler.Handle(query, CancellationToken.None); // Assert result.Items.Should().ContainSingle(); result.Items[0].Id.Should().Be(1); } }