Skip to content

Commit

Permalink
Refactor collection diffing to use class/object for add, delete, move…
Browse files Browse the repository at this point in the history
… & replace
  • Loading branch information
myieye committed Dec 10, 2024
1 parent cebb3d5 commit b82d56b
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 313 deletions.
64 changes: 24 additions & 40 deletions backend/FwLite/MiniLcm.Tests/DiffCollectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public async Task MatchingCollections_NoChangesAreGenerated()
{
var value1 = Orderable(1, Guid.NewGuid());
var value2 = Orderable(2, Guid.NewGuid());
var (changeCount, _, _) = await Diff([value1, value2], [value1, value2]);
var (changeCount, _) = await Diff([value1, value2], [value1, value2]);

changeCount.Should().Be(0);
}
Expand All @@ -22,17 +22,17 @@ public async Task AddedValues()
var value1 = Orderable(1, Guid.NewGuid());
var value2 = Orderable(2, Guid.NewGuid());
var value3 = Orderable(3, Guid.NewGuid());
var (changeCount, diffApi, api) = await Diff([value1], [value2, value1, value3]);
var (changeCount, diffApi) = await Diff([value1], [value2, value1, value3]);

changeCount.Should().Be(2);

var x_v1 = Between(next: value1);
diffApi.Verify(dApi => dApi.Add(api, value2, x_v1), Times.Once);
diffApi.Verify(dApi => dApi.Add(value2, x_v1), Times.Once);

var v1_x = Between(previous: value1);
diffApi.Verify(dApi => dApi.Add(api, value3, v1_x), Times.Once);
diffApi.Verify(dApi => dApi.Add(value3, v1_x), Times.Once);

diffApi.Verify(dApi => dApi.Replace(api, value1, value1), Times.Once);
diffApi.Verify(dApi => dApi.Replace(value1, value1), Times.Once);
diffApi.VerifyNoOtherCalls();
}

Expand All @@ -42,12 +42,12 @@ public async Task RemovedValues()
var value1 = Orderable(1, Guid.NewGuid());
var value2 = Orderable(2, Guid.NewGuid());
var value3 = Orderable(3, Guid.NewGuid());
var (changeCount, diffApi, api) = await Diff([value2, value1, value3], [value1]);
var (changeCount, diffApi) = await Diff([value2, value1, value3], [value1]);

changeCount.Should().Be(2);
diffApi.Verify(dApi => dApi.Remove(api, value2), Times.Once);
diffApi.Verify(dApi => dApi.Remove(api, value3), Times.Once);
diffApi.Verify(dApi => dApi.Replace(api, value1, value1), Times.Once);
diffApi.Verify(dApi => dApi.Remove(value2), Times.Once);
diffApi.Verify(dApi => dApi.Remove(value3), Times.Once);
diffApi.Verify(dApi => dApi.Replace(value1, value1), Times.Once);
diffApi.VerifyNoOtherCalls();
}

Expand All @@ -56,13 +56,13 @@ public async Task SwappedValues()
{
var value1 = Orderable(1, Guid.NewGuid());
var value2 = Orderable(2, Guid.NewGuid());
var (changeCount, diffApi, api) = await Diff([value1, value2], [value2, value1]);
var (changeCount, diffApi) = await Diff([value1, value2], [value2, value1]);

changeCount.Should().Be(1);
var v2_x = Between(previous: value2);
diffApi.Verify(dApi => dApi.Move(api, value1, v2_x), Times.Once);
diffApi.Verify(dApi => dApi.Replace(api, value1, value1), Times.Once);
diffApi.Verify(dApi => dApi.Replace(api, value2, value2), Times.Once);
diffApi.Verify(dApi => dApi.Move(value1, v2_x), Times.Once);
diffApi.Verify(dApi => dApi.Replace(value1, value1), Times.Once);
diffApi.Verify(dApi => dApi.Replace(value2, value2), Times.Once);
diffApi.VerifyNoOtherCalls();
}

Expand Down Expand Up @@ -148,14 +148,14 @@ public async Task DiffTests(CollectionDiffTestCase testCase)
}
}

var (changeCount, diffApi, api) = await Diff(testCase.OldValues, testCase.NewValues);
var (changeCount, diffApi) = await Diff(testCase.OldValues, testCase.NewValues);

using var scope = new AssertionScope();

changeCount.Should().Be(testCase.ExpectedOperations.Count);

var expectedReplaceCount = testCase.OldValues.Select(v => v.Id).Intersect(testCase.NewValues.Select(v => v.Id)).Count();
diffApi.Verify(dApi => dApi.Replace(api, It.IsAny<IOrderable>(), It.IsAny<IOrderable>()), Times.Exactly(expectedReplaceCount));
diffApi.Verify(dApi => dApi.Replace(It.IsAny<IOrderable>(), It.IsAny<IOrderable>()), Times.Exactly(expectedReplaceCount));

foreach (var operation in testCase.ExpectedOperations)
{
Expand All @@ -167,7 +167,6 @@ public async Task DiffTests(CollectionDiffTestCase testCase)
var movedValue = testCase.OldValues[operation.From.Value];
diffApi.Verify(
dApi => dApi.Move(
api,
movedValue,
operation.Between
),
Expand All @@ -179,7 +178,6 @@ public async Task DiffTests(CollectionDiffTestCase testCase)
var removedValue = testCase.OldValues[operation.From.Value];
diffApi.Verify(
dApi => dApi.Remove(
api,
removedValue
),
Times.Once
Expand All @@ -191,7 +189,6 @@ public async Task DiffTests(CollectionDiffTestCase testCase)
var addedValue = testCase.NewValues[operation.To.Value];
diffApi.Verify(
dApi => dApi.Add(
api,
addedValue,
operation.Between
),
Expand Down Expand Up @@ -231,17 +228,16 @@ private static BetweenPosition Between(Guid? previous = null, Guid? next = null)
};
}

private static async Task<(int, Mock<DiffApi>, IMiniLcmApi)> Diff(IOrderable[] oldValues, IOrderable[] newValues)
private static async Task<(int, Mock<OrderableCollectionDiffApi<IOrderable>>)> Diff(IOrderable[] oldValues, IOrderable[] newValues)
{
var api = new Mock<IMiniLcmApi>().Object;
var diffApi = new Mock<DiffApi>();
diffApi.Setup(f => f.Add(api, It.IsAny<IOrderable>(), It.IsAny<BetweenPosition?>()))
var diffApi = new Mock<OrderableCollectionDiffApi<IOrderable>>();
diffApi.Setup(f => f.Add(It.IsAny<IOrderable>(), It.IsAny<BetweenPosition>()))
.ReturnsAsync(1);
diffApi.Setup(f => f.Remove(api, It.IsAny<IOrderable>()))
diffApi.Setup(f => f.Remove(It.IsAny<IOrderable>()))
.ReturnsAsync(1);
diffApi.Setup(f => f.Move(api, It.IsAny<IOrderable>(), It.IsAny<BetweenPosition>()))
diffApi.Setup(f => f.Move(It.IsAny<IOrderable>(), It.IsAny<BetweenPosition>()))
.ReturnsAsync(1);
diffApi.Setup(f => f.Replace(api, It.IsAny<IOrderable>(), It.IsAny<IOrderable>()))
diffApi.Setup(f => f.Replace(It.IsAny<IOrderable>(), It.IsAny<IOrderable>()))
.Returns((IMiniLcmApi api, IOrderable oldValue, IOrderable newValue) =>
{
try
Expand All @@ -255,31 +251,19 @@ private static BetweenPosition Between(Guid? previous = null, Guid? next = null)
}
});

var changeCount = await DiffCollection.DiffOrderable(api, oldValues, newValues,
diffApi.Object.Add,
diffApi.Object.Remove,
diffApi.Object.Move,
diffApi.Object.Replace);
var changeCount = await DiffCollection.DiffOrderable(oldValues, newValues, diffApi.Object);

return (changeCount, diffApi, api);
return (changeCount, diffApi);
}
}

public class DiffResult
{
public required int ChangeCount { get; init; }
public required Mock<DiffApi> DiffApi { get; init; }
public required Mock<OrderableCollectionDiffApi<IOrderable>> DiffApi { get; init; }
public required IMiniLcmApi Api { get; init; }
}

public interface DiffApi
{
Task<int> Add(IMiniLcmApi api, IOrderable value, BetweenPosition? between);
Task<int> Remove(IMiniLcmApi api, IOrderable value);
Task<int> Move(IMiniLcmApi api, IOrderable value, BetweenPosition? between);
Task<int> Replace(IMiniLcmApi api, IOrderable oldValue, IOrderable newValue);
}

public class CollectionDiffTestCase
{
public required IOrderable[] OldValues { get; init; }
Expand Down
35 changes: 22 additions & 13 deletions backend/FwLite/MiniLcm/SyncHelpers/ComplexFormTypeSync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,10 @@ public static async Task<int> Sync(ComplexFormType[] afterComplexFormTypes,
ComplexFormType[] beforeComplexFormTypes,
IMiniLcmApi api)
{
return await DiffCollection.Diff(api,
return await DiffCollection.Diff(
beforeComplexFormTypes,
afterComplexFormTypes,
complexFormType => complexFormType.Id,
static async (api, afterComplexFormType) =>
{
await api.CreateComplexFormType(afterComplexFormType);
return 1;
},
static async (api, beforeComplexFormType) =>
{
await api.DeleteComplexFormType(beforeComplexFormType.Id);
return 1;
},
static (api, beforeComplexFormType, afterComplexFormType) => Sync(beforeComplexFormType, afterComplexFormType, api));
new ComplexFormTypesDiffApi(api));
}

public static async Task<int> Sync(ComplexFormType before,
Expand All @@ -44,4 +33,24 @@ public static async Task<int> Sync(ComplexFormType before,
if (patchDocument.Operations.Count == 0) return null;
return new UpdateObjectInput<ComplexFormType>(patchDocument);
}

private class ComplexFormTypesDiffApi(IMiniLcmApi api) : ObjectWithIdCollectionDiffApi<ComplexFormType>
{
public override async Task<int> Add(ComplexFormType afterComplexFormType)
{
await api.CreateComplexFormType(afterComplexFormType);
return 1;
}

public override async Task<int> Remove(ComplexFormType beforeComplexFormType)
{
await api.DeleteComplexFormType(beforeComplexFormType.Id);
return 1;
}

public override Task<int> Replace(ComplexFormType beforeComplexFormType, ComplexFormType afterComplexFormType)
{
return Sync(beforeComplexFormType, afterComplexFormType, api);
}
}
}
Loading

0 comments on commit b82d56b

Please sign in to comment.