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
|
// preordered merge join (picking from whichever side brings us closer to being
|
||||||
// back in sync)
|
// back in sync)
|
||||||
treatAsInsert = newSeq < oldSeq;
|
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)
|
else if (oldLoopedBack)
|
||||||
{
|
{
|
||||||
// Old sequence looped back but new one didn't
|
// Old sequence looped back but new one didn't
|
||||||
// The new sequence either has some extra trailing elements in the current loop block
|
// 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
|
// 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;
|
var newLoopsBackLater = false;
|
||||||
for (var testIndex = newStartIndex + 1; testIndex < newEndIndexExcl; testIndex++)
|
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
|
// 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
|
// which we should delete, or the new sequence has extra trailing loop blocks which we
|
||||||
// should insert
|
// should insert
|
||||||
|
// TODO: Find a way of not recomputing this next flag on every iteration
|
||||||
var oldLoopsBackLater = false;
|
var oldLoopsBackLater = false;
|
||||||
for (var testIndex = oldStartIndex + 1; testIndex < oldEndIndexExcl; testIndex++)
|
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]
|
[Fact]
|
||||||
public void HandlesAdjacentItemsBeingRemovedAndInsertedAtOnce()
|
public void HandlesAdjacentItemsBeingRemovedAndInsertedAtOnce()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue