using System.Threading; using System.Threading.Tasks; using FrameworkBLL.Page; using FrameworkBLL.Promotion.Adapters; using FrameworkDAL.CustomCode.Promotion; using FrameworkDAL.DTO.Page; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Promotion; using Moq; using Newtonsoft.Json; using Xunit; namespace FrameworkTests; /// /// PagePromotionAdapter — parent row only (MPAGE has no child rows). Covers ModuleCode resolution, /// blocking DefaultCriteriaConfigId/ImageId when set to a real value, and that Import never maps /// those two fields onto the destination row even when they were carried in Flags for validation. /// public class PagePromotionAdapterTests { private static LoginDTO Login() => new() { ClientId = -1, UserId = 7 }; private static PageDTO CleanDto(int pageId = 42) => new() { PageId = pageId, PageCode = "SALES_DASH_PAGE", PageName = "Sales Dashboard Page", PageLayOut = "2-column", ModuleId = 0, DefaultCriteriaConfigId = -1, ImageId = -1, PageSortOrder = 1 }; private static (Mock bll, Mock pageLookup, Mock moduleLookup) Mocks() => (new Mock(), new Mock(), new Mock()); private static async Task BuildBundle(PageDTO dto) { var (bll, pageLookup, moduleLookup) = Mocks(); bll.Setup(b => b.GetPage(dto.PageId, It.IsAny())).ReturnsAsync(JsonConvert.SerializeObject(dto)); if (dto.ModuleId != 0 && dto.ModuleId != -1) moduleLookup.Setup(l => l.GetModuleCodeById(dto.ModuleId, It.IsAny(), It.IsAny())) .ReturnsAsync("SALES"); var adapter = new PagePromotionAdapter(bll.Object, pageLookup.Object, moduleLookup.Object); return await adapter.ExportForPromotionAsync(dto.PageId, Login(), CancellationToken.None); } [Fact] public async Task Validate_CleanPage_IsOk() { var bundle = await BuildBundle(CleanDto()); var (bll, pageLookup, moduleLookup) = Mocks(); var adapter = new PagePromotionAdapter(bll.Object, pageLookup.Object, moduleLookup.Object); var result = await adapter.ValidateForPromotionAsync(bundle, CancellationToken.None); Assert.True(result.IsPromotable); } [Fact] public async Task Validate_DefaultCriteriaConfigIdSet_Blocks() { var dto = CleanDto(); dto.DefaultCriteriaConfigId = 55; var bundle = await BuildBundle(dto); var (bll, pageLookup, moduleLookup) = Mocks(); var adapter = new PagePromotionAdapter(bll.Object, pageLookup.Object, moduleLookup.Object); var result = await adapter.ValidateForPromotionAsync(bundle, CancellationToken.None); Assert.False(result.IsPromotable); Assert.Contains(result.BlockingReasons, r => r.Contains("DefaultCriteriaConfigId")); } [Fact] public async Task Validate_ImageIdSet_Blocks() { var dto = CleanDto(); dto.ImageId = 77; var bundle = await BuildBundle(dto); var (bll, pageLookup, moduleLookup) = Mocks(); var adapter = new PagePromotionAdapter(bll.Object, pageLookup.Object, moduleLookup.Object); var result = await adapter.ValidateForPromotionAsync(bundle, CancellationToken.None); Assert.False(result.IsPromotable); Assert.Contains(result.BlockingReasons, r => r.Contains("ImageId")); } [Fact] public async Task Import_ResolvesModuleCodeAndNeverMapsBlockedFields() { var dto = CleanDto(); dto.ModuleId = 900; var bundle = await BuildBundle(dto); var (bll, pageLookup, moduleLookup) = Mocks(); moduleLookup.Setup(l => l.GetModuleIdByCode("SALES", It.IsAny(), It.IsAny())) .ReturnsAsync(123); pageLookup.Setup(l => l.GetPageIdByCode("SALES_DASH_PAGE", It.IsAny(), It.IsAny())) .ReturnsAsync((int?)null); PageDTO? captured = null; bll.Setup(b => b.SavePage(It.IsAny(), It.IsAny())) .Callback((d, _) => { captured = new PageDTO { PageId = d.PageId, ModuleId = d.ModuleId, DefaultCriteriaConfigId = d.DefaultCriteriaConfigId, ImageId = d.ImageId, PageSourceType = d.PageSourceType }; d.PageId = 901; }) .ReturnsAsync("Saved"); var adapter = new PagePromotionAdapter(bll.Object, pageLookup.Object, moduleLookup.Object); var newId = await adapter.ImportPromotedAsync(bundle, destinationSourceType: 3, existingDestinationId: null, Login(), CancellationToken.None); Assert.Equal(901, newId); Assert.NotNull(captured); Assert.Equal(123, captured!.ModuleId); Assert.Equal(-1, captured.DefaultCriteriaConfigId); // never mapped Assert.Equal(-1, captured.ImageId); // never mapped Assert.Equal((byte)3, captured.PageSourceType); } [Fact] public async Task Import_PageCodeAlreadyExistsAtDestination_UpdatesRatherThanDuplicating() { var bundle = await BuildBundle(CleanDto()); var (bll, pageLookup, moduleLookup) = Mocks(); pageLookup.Setup(l => l.GetPageIdByCode("SALES_DASH_PAGE", It.IsAny(), It.IsAny())) .ReturnsAsync(700); int? capturedId = null; bll.Setup(b => b.SavePage(It.IsAny(), It.IsAny())) .Callback((d, _) => capturedId = d.PageId) .ReturnsAsync("Updated"); var adapter = new PagePromotionAdapter(bll.Object, pageLookup.Object, moduleLookup.Object); var resultId = await adapter.ImportPromotedAsync(bundle, 3, existingDestinationId: null, Login(), CancellationToken.None); Assert.Equal(700, resultId); Assert.Equal(700, capturedId); } }