In tree diffing, better handle scenario where both old and new sequences loop back but to different locations
This commit is contained in:
parent
6b37494e7c
commit
7a1abbaca3
|
|
@ -63,12 +63,20 @@ namespace Microsoft.Blazor.RenderTree
|
|||
// preordered merge join (picking from whichever side brings us closer to being
|
||||
// back in sync)
|
||||
treatAsInsert = newSeq < oldSeq;
|
||||
|
||||
if (oldLoopedBack)
|
||||
{
|
||||
// If both old and new have now looped back, we must reset their 'looped back'
|
||||
// tracker so we can treat them as proceeding through the same loop block
|
||||
prevOldSeq = prevNewSeq = -1;
|
||||
}
|
||||
}
|
||||
else if (oldLoopedBack)
|
||||
{
|
||||
// Old sequence looped back but new one didn't
|
||||
// The new sequence either has some extra trailing elements in the current loop block
|
||||
// which we should insert, or omits some old trailing loop blocks which we should delete
|
||||
// TODO: Find a way of not recomputing this next flag on every iteration
|
||||
var newLoopsBackLater = false;
|
||||
for (var testIndex = newStartIndex + 1; testIndex < newEndIndexExcl; testIndex++)
|
||||
{
|
||||
|
|
@ -91,6 +99,7 @@ namespace Microsoft.Blazor.RenderTree
|
|||
// The old sequence either has some extra trailing elements in the current loop block
|
||||
// which we should delete, or the new sequence has extra trailing loop blocks which we
|
||||
// should insert
|
||||
// TODO: Find a way of not recomputing this next flag on every iteration
|
||||
var oldLoopsBackLater = false;
|
||||
for (var testIndex = oldStartIndex + 1; testIndex < oldEndIndexExcl; testIndex++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -212,6 +212,64 @@ namespace Microsoft.Blazor.Test
|
|||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecognizesLeadingLoopBlockItemsBeingAdded()
|
||||
{
|
||||
// Arrange
|
||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
||||
var diff = new RenderTreeDiff();
|
||||
oldTree.AddText(2, "x");
|
||||
oldTree.AddText(2, "x"); // Note that the '0' and '1' items are not present on this iteration
|
||||
newTree.AddText(2, "x");
|
||||
newTree.AddText(0, "x");
|
||||
newTree.AddText(1, "x");
|
||||
newTree.AddText(2, "x");
|
||||
|
||||
// Act
|
||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
||||
|
||||
// Assert
|
||||
Assert.Collection(result,
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type),
|
||||
entry =>
|
||||
{
|
||||
Assert.Equal(RenderTreeDiffEntryType.PrependNode, entry.Type);
|
||||
Assert.Equal(1, entry.NewTreeIndex);
|
||||
},
|
||||
entry =>
|
||||
{
|
||||
Assert.Equal(RenderTreeDiffEntryType.PrependNode, entry.Type);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
},
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecognizesLeadingLoopBlockItemsBeingRemoved()
|
||||
{
|
||||
// Arrange
|
||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
||||
var diff = new RenderTreeDiff();
|
||||
oldTree.AddText(2, "x");
|
||||
oldTree.AddText(0, "x");
|
||||
oldTree.AddText(1, "x");
|
||||
oldTree.AddText(2, "x");
|
||||
newTree.AddText(2, "x");
|
||||
newTree.AddText(2, "x"); // Note that the '0' and '1' items are not present on this iteration
|
||||
|
||||
// Act
|
||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
||||
|
||||
// Assert
|
||||
Assert.Collection(result,
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type),
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.RemoveNode, entry.Type),
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.RemoveNode, entry.Type),
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HandlesAdjacentItemsBeingRemovedAndInsertedAtOnce()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue