using NUnit.Framework; using e_suite.Database.Core.Helpers; using Microsoft.EntityFrameworkCore; using Moq; namespace e_suite.Database.Core.UnitTests; [TestFixture] public class DeltaUnitTests { private static DbSet GetQueryableMockDbSet(List sourceList) where T : class { var queryable = sourceList.AsQueryable(); var dbSet = new Mock>(); dbSet.As>().Setup(m => m.Provider).Returns(queryable.Provider); dbSet.As>().Setup(m => m.Expression).Returns(queryable.Expression); dbSet.As>().Setup(m => m.ElementType).Returns(queryable.ElementType); dbSet.As>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator()); dbSet.Setup(d => d.Add(It.IsAny())).Callback((s) => sourceList.Add(s)); dbSet.Setup(d => d.RemoveRange(It.IsAny>())).Callback>( items => { foreach (var item in items) { sourceList.Remove(item); } }); dbSet.Setup(d => d.AddRangeAsync(It.IsAny>(), It.IsAny())).Callback, CancellationToken>( (items, cancellationToken) => { foreach (var item in items) { cancellationToken.ThrowIfCancellationRequested(); sourceList.Add(item); } }); return dbSet.Object; } private static void AssertListContents(IReadOnlyList listToTest, List list) { foreach (var item in list) Assert.That(listToTest.Contains(item), Is.True); } private static void AssertDeltaMatches(IReadOnlyList> actualResultMatches, List list) { foreach (var item in actualResultMatches) { var originalIndex = list.IndexOf(item.Original); var updatedIndex = list.IndexOf(item.Updated); Assert.That(originalIndex, Is.GreaterThan(-1)); Assert.That(updatedIndex, Is.GreaterThan(-1)); Assert.That(originalIndex, Is.EqualTo(updatedIndex)); } } [Test] public void CalculateDelta_CalculatesAdditions() { //Arrange var originalList = new List(); var updatedList = new List { "a", "b", "c" }; //Act var actualResult = Delta.CalculateDelta(updatedList, originalList, StringComparer.InvariantCultureIgnoreCase ); //Assert Assert.That(actualResult.Additions.Count, Is.EqualTo(3)); AssertListContents(actualResult.Additions, ["a", "b", "c"]); Assert.That(actualResult.Deletions.Count, Is.EqualTo(0)); Assert.That(actualResult.Matches.Count, Is.EqualTo(0)); } [Test] public void CalculateDelta_CalculatesDeletions() { //Arrange var originalList = new List { "d", "e", "f" }; var updatedList = new List(); //Act var actualResult = Delta.CalculateDelta(updatedList, originalList, StringComparer.InvariantCultureIgnoreCase); //Assert Assert.That(actualResult.Additions.Count, Is.EqualTo(0)); Assert.That(actualResult.Deletions.Count, Is.EqualTo(3)); AssertListContents(actualResult.Deletions, ["d", "e", "f"]); Assert.That(actualResult.Matches.Count, Is.EqualTo(0)); } [Test] public void CalculateDelta_CalculatesMatches() { //Arrange var originalList = new List { "g", "h", "i" }; var updatedList = new List { "g", "h", "i" }; //Act var actualResult = Delta.CalculateDelta(updatedList, originalList, StringComparer.InvariantCultureIgnoreCase); //Assert Assert.That(actualResult.Additions.Count, Is.EqualTo(0)); Assert.That(actualResult.Deletions.Count, Is.EqualTo(0)); Assert.That(actualResult.Matches.Count, Is.EqualTo(3)); AssertDeltaMatches(actualResult.Matches, ["g", "h", "i"]); } [Test] public void CalculateDelta_CanCalulateACombinationOfAddDeleteAndMatch() { //Arrange var originalList = new List { "j", "k", "l", "p", "q", "r" }; var updatedList = new List { "m", "n", "o", "p", "q", "r" }; //Act var actualResult = Delta.CalculateDelta(updatedList, originalList, StringComparer.InvariantCultureIgnoreCase); //Assert Assert.That(actualResult.Additions.Count, Is.EqualTo(3)); AssertListContents(actualResult.Additions, ["m", "n", "o"]); Assert.That(actualResult.Deletions.Count, Is.EqualTo(3)); AssertListContents(actualResult.Deletions, ["j", "k", "l"]); Assert.That(actualResult.Matches.Count, Is.EqualTo(3)); AssertDeltaMatches(actualResult.Matches, ["p", "q", "r"]); } [Test] public void CalculateDelta_CancellationTokenThrowsExceptionWhenCancelled() { //Arrange var originalList = new List { "j", "k", "l", "p", "q", "r" }; var updatedList = new List { "m", "n", "o", "p", "q", "r" }; CancellationTokenSource cts = new(); CancellationToken cancellationToken = cts.Token; cts.Cancel(); //Assert Assert.Throws(() => { //Act var actualResult = Delta.CalculateDelta(updatedList, originalList, StringComparer.InvariantCultureIgnoreCase, cancellationToken); }); } [Test] public void UpdateDbSetAsync_TokenCancelled_ThrowsException() { //Arrange var originalList = new List { "j", "k", "l", "p", "q", "r" }; var updatedList = new List { "m", "n", "o", "p", "q", "r" }; CancellationTokenSource cts = new(); CancellationToken cancellationToken = cts.Token; var delta = Delta.CalculateDelta(updatedList, originalList, StringComparer.InvariantCultureIgnoreCase, cancellationToken); cts.Cancel(); var mockDBSet = GetQueryableMockDbSet(originalList); //Assert Assert.ThrowsAsync(async () => { //Act await delta.UpdateDbSetAsync(mockDBSet, cancellationToken); }); } [Test] public async Task UpdateDbSetAsync_UpdateCompletes_UpdatedDBSetContainsExpectedValues() { //Arrange var sourceList = new List { "j", "k", "l", "p", "q", "r" }; var mockDbSet = GetQueryableMockDbSet(sourceList); var originalList = new List(sourceList); var updatedList = new List { "m", "n", "o", "p", "q", "r" }; CancellationTokenSource cts = new(); CancellationToken cancellationToken = cts.Token; var delta = Delta.CalculateDelta(updatedList, originalList, StringComparer.InvariantCultureIgnoreCase, cancellationToken); //Act await delta.UpdateDbSetAsync(mockDbSet, cancellationToken); //Assert Assert.That(mockDbSet.Count(), Is.EqualTo(6) ); foreach (var entry in mockDbSet) Assert.That(updatedList.Contains(entry), Is.True); } }