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);
}
}