original
", + Title = "Seeded Block", + System = "Viper", + ViperSectionPath = "cats", + Page = "home", + BlockOrder = 1, + FriendlyName = "seeded-block-" + Guid.NewGuid().ToString("N")[..8], + ModifiedOn = DateTime.Now.AddDays(-2), + ModifiedBy = "originalAuthor" + }; + customize?.Invoke(block); + _context.ContentBlocks.Add(block); + await _context.SaveChangesAsync(TestContext.Current.CancellationToken); + return block; + } + + private static CMSBlockAddEdit MakeRequest(ContentBlock block, Actionoriginal
", dto!.Content); + Assert.Equal(new Listnew
", + Title = "New Block", + System = "Viper", + AllowPublicAccess = false, + Permissions = new Listupdated
"); + + var dto = await _service.UpdateContentBlockAsync(block.ContentBlockId, request, TestContext.Current.CancellationToken); + + Assert.Equal("updated
", dto!.Content); + var history = Assert.Single(_context.ContentHistories.Where(h => h.ContentBlockId == block.ContentBlockId)); + Assert.Equal("original
", history.ContentBlockContent); + Assert.Equal("originalAuthor", history.ModifiedBy); + Assert.Equal(originalModifiedOn, history.ModifiedOn); + } + + [Fact] + public async Task Update_StaleLastModifiedOn_ThrowsConcurrency() + { + var block = await SeedBlockAsync(); + var request = MakeRequest(block, r => r.LastModifiedOn = block.ModifiedOn.AddMinutes(-5)); + + await Assert.ThrowsAsyncquick edit
", block.ModifiedOn, + TestContext.Current.CancellationToken); + + Assert.Equal("quick edit
", dto!.Content); + Assert.Equal("Seeded Block", dto.Title); + var history = Assert.Single(_context.ContentHistories.Where(h => h.ContentBlockId == block.ContentBlockId)); + Assert.Equal("original
", history.ContentBlockContent); + } + + #endregion + + #region Delete / Restore / History + + [Fact] + public async Task SoftDeleteAndRestore_ToggleDeletedOn() + { + var block = await SeedBlockAsync(); + + Assert.True(await _service.SoftDeleteAsync(block.ContentBlockId, TestContext.Current.CancellationToken)); + Assert.NotNull((await _context.ContentBlocks.SingleAsync(TestContext.Current.CancellationToken)).DeletedOn); + + Assert.True(await _service.RestoreAsync(block.ContentBlockId, TestContext.Current.CancellationToken)); + Assert.Null((await _context.ContentBlocks.SingleAsync(TestContext.Current.CancellationToken)).DeletedOn); + } + + [Fact] + public async Task PermanentDelete_RemovesBlockAndChildren() + { + var block = await SeedBlockAsync(b => + { + b.ContentBlockToPermissions.Add(new ContentBlockToPermission { Permission = "SVMSecure" }); + b.ContentHistories.Add(new ContentHistory + { + ContentBlockContent = "old", + ModifiedOn = DateTime.Now.AddDays(-3), + ModifiedBy = "x" + }); + }); + + var result = await _service.PermanentlyDeleteAsync(block.ContentBlockId, TestContext.Current.CancellationToken); + + Assert.True(result); + Assert.Empty(await _context.ContentBlocks.ToListAsync(TestContext.Current.CancellationToken)); + Assert.Empty(await _context.ContentHistories.ToListAsync(TestContext.Current.CancellationToken)); + Assert.Empty(await _context.ContentBlockToPermissions.ToListAsync(TestContext.Current.CancellationToken)); + } + + [Fact] + public async Task History_ListAndVersionRetrieval() + { + var block = await SeedBlockAsync(); + await _service.UpdateContentOnlyAsync(block.ContentBlockId, "v2
", block.ModifiedOn, TestContext.Current.CancellationToken); + await _service.UpdateContentOnlyAsync(block.ContentBlockId, "v3
", block.ModifiedOn, TestContext.Current.CancellationToken); + + var history = await _service.GetHistoryAsync(block.ContentBlockId, TestContext.Current.CancellationToken); + Assert.Equal(2, history.Count); + + var oldest = await _service.GetHistoryVersionAsync(block.ContentBlockId, history[^1].ContentHistoryId, + TestContext.Current.CancellationToken); + Assert.Equal("original
", oldest!.Content); + } + + #endregion +} diff --git a/test/CMS/CmsLeftNavServiceTests.cs b/test/CMS/CmsLeftNavServiceTests.cs new file mode 100644 index 000000000..f3e04d87c --- /dev/null +++ b/test/CMS/CmsLeftNavServiceTests.cs @@ -0,0 +1,181 @@ +using Microsoft.EntityFrameworkCore; +using NSubstitute; +using Viper.Areas.CMS.Models.DTOs; +using Viper.Areas.CMS.Services; +using Viper.Classes.SQLContext; +using Viper.Models.VIPER; + +namespace Viper.test.CMS; + +///