public void HistoryRemovalOfParentWithChangedChildExpectOnlyRemove() { var head = this.NewTree("some tree"); var treeRevisions = new List <ProjectTree>(); treeRevisions.Add(head); ProjectTree child, grandchild; treeRevisions.Add(head = head.AddChildren(child = this.NewTree("child"))); treeRevisions.Add(head = head.AddDescendent(grandchild = this.NewTree("grand-child"), child)); ProjectTree originalTree = head; grandchild = head.Find(grandchild.Identity); treeRevisions.Add(head = head.ReplaceDescendent(grandchild, grandchild.WithVisible(false))); child = head.Find(child.Identity); treeRevisions.Add(head = head.RemoveChildren(child)); var differences = ProjectTree.GetDelta(originalTree, head).ToList(); Assert.Single(differences); Assert.Equal(ChangeKind.Removed, differences[0].Kind); Assert.Equal(differences[0].Identity, child.Identity); // Expected the removed node to be the child node }
public void AsProjectItemTree_OnNonItem() { var root = ProjectTree.Create("hi").AsRoot; var item = root.AsProjectItemTree; Assert.True(item.IsDefault); }
public void ReplaceNodeWithChildrenAndChangeIdentity() { var grandchild = this.NewTree("grandchild"); var child = this.NewTree("child", new[] { grandchild }); this.node = this.node.AddChildren(child); // Ensure we exercise our lookup table update code by filling the tree with enough nodes. for (int i = 0; i < RecursiveTypeExtensions.InefficiencyLoadThreshold; i++) { this.node = this.node.AddChildren(this.NewTree("child " + i)); } // Verify that we can find the interesting child. var spine = this.node.GetSpine(child.Identity); Assert.Same(this.node, spine.Peek()); Assert.Same(child, spine.Pop().Peek()); // Now replace the child with one of a different identity. var newChild = this.NewTree("newChild", child.Children); this.node = this.node.ReplaceDescendent(child, newChild); spine = this.node.GetSpine(newChild.Identity); Assert.Same(this.node, spine.Peek()); Assert.Same(newChild, spine.Last()); spine = this.node.GetSpine(grandchild.Identity); Assert.Same(this.node, spine.Peek()); Assert.Same(newChild, spine.Pop().Peek()); Assert.Same(grandchild, spine.Last()); }
public void HistoryIncludesOnlyTopLevelRemovals() { var head = this.NewTree("some tree"); var treeRevisions = new List <ProjectTree>(); treeRevisions.Add(head); ProjectTree child, grandchild1, grandchild2; treeRevisions.Add(head = head.AddChildren(child = this.NewTree("child"))); treeRevisions.Add(head = head.AddDescendent(grandchild1 = this.NewTree("grand-child1"), child)); treeRevisions.Add(head = head.ReplaceDescendent(grandchild1, grandchild2 = grandchild1.WithCaption("grand-child2"))); // Add a sub-tree all at once to the tree. var greatX2grandChild1 = this.NewTree("great-great-grand-child1"); var greatX2grandChild2 = this.NewTree("great-great-grand-child2"); treeRevisions.Add(head = head.AddDescendent(this.NewTree("great-grand-child", children: new ProjectTree[] { greatX2grandChild1, greatX2grandChild2 }), grandchild1)); // Now delete one of those discretly added nodes. (the idea here is to do our best to generate a funky history) treeRevisions.Add(head = head.RemoveDescendent(greatX2grandChild2)); // And finally remove the top-level child node. treeRevisions.Add(head = head.RemoveDescendent(child)); var differences = ProjectTree.GetDelta((ProjectTree)treeRevisions.First(), (ProjectTree)treeRevisions.Last()).ToList(); Assert.Empty(differences); differences = ProjectTree.GetDelta((ProjectTree)treeRevisions[3], (ProjectTree)treeRevisions.Last()).ToList(); Assert.Single(differences); Assert.Equal(ChangeKind.Removed, differences[0].Kind); Assert.Equal(ProjectTreeChangedProperties.None, differences[0].Changes); Assert.Equal(differences[0].Identity, child.Identity); // The added node in history should be identity-equal to the most recent node. }
public void HistoryAddOfParentWithChangedChildExpectsOnlyAdd() { var head = this.NewTree("some tree"); var treeRevisions = new List <ProjectTree>(); treeRevisions.Add(head); ProjectTree originalTree = head; ProjectTree child, grandchild; child = this.NewTree("child"); child = child.AddChildren(grandchild = this.NewTree("grand-child")); grandchild = child.Find(grandchild.Identity); child = child.ReplaceDescendent(grandchild, grandchild.WithVisible(false)); treeRevisions.Add(head = head.AddChildren(child)); // 1 // Also change the grandchild again grandchild = head.Find(grandchild.Identity); treeRevisions.Add(head = head.ReplaceDescendent(grandchild, grandchild.WithCapabilities("sc"))); // 2 // Verify that up to when the subtree was added, only one change is reported. var differences = ProjectTree.GetDelta(originalTree, treeRevisions[1]).ToList(); Assert.Single(differences); Assert.Equal(ChangeKind.Added, differences[0].Kind); Assert.Equal(differences[0].Identity, child.Identity); // Expected the removed node to be the child node // Verify that from beginning to very end, still only one change is reported. differences = ProjectTree.GetDelta(originalTree, head).ToList(); Assert.Single(differences); Assert.Equal(ChangeKind.Added, differences[0].Kind); Assert.Equal(differences[0].Identity, child.Identity); // Expected the removed node to be the child node }
public void MovingNodeAroundHierarchyWithChildRemoves() { ProjectTree aa, ab; var root = ProjectTree.Create("A").WithChildren( aa = ProjectTree.Create("AA").WithChildren( ProjectTree.Create("AAA")), ab = ProjectTree.Create("AB")); var aaModified = aa.RemoveChild(aa.Children[0]); var moved = root.RemoveDescendent(aa).AddDescendent(aaModified, ab); var history = moved.ChangesSince(root); Assert.Equal(2, history.Count); Assert.Equal(ChangeKind.Removed, history[0].Kind); Assert.Same(aa.Children[0], history[0].Before); Assert.Null(history[0].After); Assert.Equal(aa.Children[0].Identity, history[0].Identity); Assert.Equal(ChangeKind.Replaced, history[1].Kind); Assert.Equal(ProjectTreeChangedProperties.Parent, history[1].Changes); Assert.Same(aa, history[1].Before); Assert.Same(aaModified, history[1].After); Assert.Equal(aa.Identity, history[1].Identity); }
public void ImmutableNodeConstructorTest() { this.Children = this.Children.Add(this.NewNode()); // children must be non-empty for the collection to be used in the node. this.node = (ProjectTree)this.NewTree(Caption, children: this.Children); Assert.Same(Caption, this.node.Caption); Assert.Same(Children, this.node.Children); }
private static void RecursiveAddChildren(ProjectTree template, ProjectTree.Builder receiver) { foreach (var templateChild in template) { var clonedTemplateChild = ProjectTree.Create(templateChild.Caption).ToBuilder(); RecursiveAddChildren(templateChild, clonedTemplateChild); receiver.Children.Add(clonedTemplateChild.ToImmutable()); } }
internal RootedProjectTree CloneProjectTreeRootToLeafWithBuilders(RootedProjectTree templateTree) { var rootBuilder = ProjectTree.Create(templateTree.Caption).ToBuilder(); RecursiveAddChildren(templateTree.ProjectTree, rootBuilder); var root = rootBuilder.ToImmutable(); return(root.AsRoot); }
public void AddChild() { this.Children = this.Children.Add(this.NewNode()); // children must be non-empty for the collection to be used in the node. this.node = this.NewTree(Caption, children: this.Children); var newChild = this.NewNode(); var newNode = this.node.AddChildren(newChild); Assert.Same(this.Children, this.node.Children); Assert.Equal(2, newNode.Children.Count); Assert.Same(newChild, newNode.Children[1]); }
internal ProjectTree NewTree(string caption, IEnumerable <ProjectTree> children = null) { var tree = ProjectTree.Create(caption); if (children != null) { tree = tree.WithChildren(children); } return(tree); }
internal ProjectTree NewNode(params ProjectTree[] children) { this.nodeCounter++; var tree = ProjectTree.Create(Caption + this.nodeCounter); if (children != null) { tree = tree.WithChildren(children); } return(tree); }
private static RootedProjectTree RecursiveAddChildren(ProjectTree template, RootedProjectTree receiver) { RootedProjectTree latest = receiver; foreach (var templateChild in template) { var clonedTemplateChild = ProjectTree.Create(templateChild.Caption); var asChild = latest.AddChild(clonedTemplateChild).Value; var childWithChildren = RecursiveAddChildren(templateChild, asChild); latest = childWithChildren.Parent; } return(latest); }
public void HistoryOmitsAddedThenRemovedItems() { var head = this.NewTree("some tree"); var treeRevisions = new List <ProjectTree>(); treeRevisions.Add(head); ProjectTree node1a, node1b; treeRevisions.Add(head = head.AddChildren(node1a = this.NewTree("node1a"))); treeRevisions.Add(head = head.ReplaceDescendent(node1a, node1b = node1a.WithCaption("node1b"))); treeRevisions.Add(head = head.RemoveDescendent(node1b)); var differences = ProjectTree.GetDelta((ProjectTree)treeRevisions.First(), (ProjectTree)treeRevisions.Last()).ToList(); Assert.Empty(differences); }
public void RepositioningNodeWithinParentsChildren() { ProjectTree aa, ab; var root = ProjectTree.Create("A").WithChildren( aa = ProjectTree.Create("AA"), ab = ProjectTree.Create("AB")); var ac = aa.WithCaption("AC"); var modified = root.ReplaceDescendent(aa, ac); var history = modified.ChangesSince(root); Assert.Equal(1, history.Count); Assert.Equal(ChangeKind.Replaced, history[0].Kind); Assert.Equal(ProjectTreeChangedProperties.Caption | ProjectTreeChangedProperties.PositionUnderParent, history[0].Changes); Assert.Same(aa, history[0].Before); Assert.Same(ac, history[0].After); }
public void HistoryIncludesChangesToNodeProperties() { var head = this.NewTree("some tree"); var treeRevisions = new List <ProjectTree>(); treeRevisions.Add(head); ProjectTree node1a, node1b; treeRevisions.Add(head = head.AddChildren(node1a = this.NewTree("node1a"))); treeRevisions.Add(head = head.ReplaceDescendent(node1a, node1b = node1a.WithCaption("node1b"))); var differences = ProjectTree.GetDelta((ProjectTree)treeRevisions[1], (ProjectTree)treeRevisions.Last()).ToList(); Assert.Single(differences); Assert.Equal(ChangeKind.Replaced, differences[0].Kind); Assert.Equal(ProjectTreeChangedProperties.Caption, differences[0].Changes); }
public void MovingNodeAroundHierarchy() { ProjectTree aa, ab; var root = ProjectTree.Create("A").WithChildren( aa = ProjectTree.Create("AA"), ab = ProjectTree.Create("AB")); var moved = root.RemoveDescendent(aa).AddDescendent(aa, ab); var history = moved.ChangesSince(root); Assert.Equal(1, history.Count); Assert.Equal(ChangeKind.Replaced, history[0].Kind); Assert.Same(aa, history[0].Before); Assert.Same(aa, history[0].After); Assert.Equal(ProjectTreeChangedProperties.Parent, history[0].Changes); }
public void HistoryOmitsChangesAfterAdd() { var head = this.NewTree("some tree"); var treeRevisions = new List <ProjectTree>(); treeRevisions.Add(head); ProjectTree node1a, node1b; treeRevisions.Add(head = head.AddChildren(node1a = this.NewTree("node1a"))); treeRevisions.Add(head = head.ReplaceDescendent(node1a, node1b = node1a.WithCapabilities("node1b"))); var differences = ProjectTree.GetDelta((ProjectTree)treeRevisions.First(), (ProjectTree)treeRevisions.Last()).ToList(); Assert.Single(differences); Assert.Equal(ChangeKind.Added, differences[0].Kind); Assert.Equal(ProjectTreeChangedProperties.None, differences[0].Changes); Assert.Equal(differences[0].Identity, node1b.Identity); // The added node in history should be identity-equal to the most recent node. }
public void HistoryIncludesOnlyTopLevelAddsWhenDescendentsChanged() { var head = this.NewTree("some tree"); var treeRevisions = new List <ProjectTree>(); treeRevisions.Add(head); ProjectTree child, grandchild; treeRevisions.Add(head = head.AddChildren(child = this.NewTree("child"))); treeRevisions.Add(head = head.AddDescendent(grandchild = this.NewTree("grand-child"), child)); grandchild = head.Find(grandchild.Identity); treeRevisions.Add(head = head.ReplaceDescendent(grandchild, grandchild.WithVisible(false))); // Verify that from beginning to very end, still only one change is reported. var differences = ProjectTree.GetDelta(treeRevisions[0], treeRevisions.Last()).ToList(); Assert.Single(differences); Assert.Equal(ChangeKind.Added, differences[0].Kind); Assert.Equal(differences[0].Identity, child.Identity); // Expected the removed node to be the child node }
public void HistoryClaimsAtMostOneChangePerPropertyPerNode() { var head = this.NewTree("some tree"); var treeRevisions = new List <ProjectTree>(); treeRevisions.Add(head); ProjectTree node1a, node1b, node1c, node1d; treeRevisions.Add(head = head.AddChildren(node1a = this.NewTree("node1"))); treeRevisions.Add(head = head.ReplaceDescendent(node1a, node1b = node1a.With("node1", visible: false))); treeRevisions.Add(head = head.ReplaceDescendent(node1b, node1c = node1b.With("node1", visible: false).WithCapabilities(ProjectTreeCapabilities.IncludeInProjectCandidate))); treeRevisions.Add(head = head.ReplaceDescendent(node1c, node1d = node1c.With("node1", visible: false).WithCapabilities(ProjectTreeCapabilities.IncludeInProjectCandidate, ProjectTreeCapabilities.SourceFile))); var differences = ProjectTree.GetDelta(treeRevisions[1], treeRevisions.Last()).ToList(); // The point of this test is however to verify that if a given node changes multiple times along a tree's history // that each changed property is only reported once, rather than once each time the node changes at all. Assert.Single(differences); Assert.Equal(ChangeKind.Replaced, differences[0].Kind); Assert.Equal(ProjectTreeChangedProperties.Visible | ProjectTreeChangedProperties.Capabilities, differences[0].Changes); }
public void ProjectTreeValueComparer() { var tree = ProjectTree.Create("root"); Assert.Equal(tree, tree, ProjectTree.Comparers.Identity); Assert.Equal(tree, tree, ProjectTree.Comparers.ByValue); var newPath = tree.WithFilePath("c:\\some\\path"); Assert.Equal(tree, newPath, ProjectTree.Comparers.Identity); Assert.NotEqual(tree, newPath, ProjectTree.Comparers.ByValue); var changedBackToOriginal = newPath.WithFilePath(tree.FilePath); Assert.Equal(tree, changedBackToOriginal, ProjectTree.Comparers.Identity); Assert.Equal(tree, changedBackToOriginal, ProjectTree.Comparers.ByValue); var derivedType = tree.ToProjectItemTree(new ProjectPropertiesContext()); Assert.Equal(tree, derivedType, ProjectTree.Comparers.Identity); Assert.NotEqual(tree, derivedType, ProjectTree.Comparers.ByValue); }
public void HistoryOmitsSelfCancelingPropertyChanges() { var head = this.NewTree("some tree"); var treeRevisions = new List <ProjectTree>(); treeRevisions.Add(head); ProjectTree node1a, node1b, node1c, node1d; treeRevisions.Add(head = head.AddChildren(node1a = this.NewTree("node1"))); treeRevisions.Add(head = head.ReplaceDescendent(node1a, node1b = node1a.With("node1", visible: false))); treeRevisions.Add(head = head.ReplaceDescendent(node1b, node1c = node1b.With("node1", visible: true))); treeRevisions.Add(head = head.ReplaceDescendent(node1c, node1d = node1c.With("node1", visible: false).WithCapabilities(ProjectTreeCapabilities.IncludeInProjectCandidate))); // span the visible: true -> false change var differences = ProjectTree.GetDelta(treeRevisions[1], treeRevisions[2]).ToList(); Assert.Single(differences); Assert.Equal(ChangeKind.Replaced, differences[0].Kind); Assert.Equal(ProjectTreeChangedProperties.Visible, differences[0].Changes); // span the visible: true -> false -> true change differences = ProjectTree.GetDelta(treeRevisions[1], treeRevisions[3]).ToList(); Assert.Empty(differences); // span the visible: true -> false+capabilities change. differences = ProjectTree.GetDelta(treeRevisions[3], treeRevisions[4]).ToList(); Assert.Single(differences); Assert.Equal(ChangeKind.Replaced, differences[0].Kind); Assert.Equal(ProjectTreeChangedProperties.Capabilities | ProjectTreeChangedProperties.Visible, differences[0].Changes); // span the visible: false -> true -> false+capabilities change. differences = ProjectTree.GetDelta(treeRevisions[2], treeRevisions[4]).ToList(); Assert.Single(differences); Assert.Equal(ChangeKind.Replaced, differences[0].Kind); Assert.Equal(ProjectTreeChangedProperties.Capabilities, differences[0].Changes); }
internal ProjectTree NewTree(string caption, ProjectTree singleChild) { return(this.NewTree(caption, new[] { singleChild })); }
internal ProjectTree CloneProjectTreeLeafToRoot(ProjectTree templateTree) { var clone = ProjectTree.Create(templateTree.Caption).AddChildren(templateTree.Children.Select(this.CloneProjectTreeLeafToRoot)); return(clone); }
internal static RootedProjectTree ConstructVeryLargeTree(Random random, int depth, int maxImmediateChildrenCount, int totalNodeCount, Func <string> counter = null) { Requires.NotNull(random, "random"); Requires.Range(depth > 0, "maxDepth"); Requires.Range(totalNodeCount > 0, "totalNodeCount"); if (counter == null) { int counterPosition = 0; counter = () => "Node " + ++counterPosition; } var tree = RootedProjectTree.Create(counter()); int nodesAllocated = 1; int maxChildrenCount = Math.Min(maxImmediateChildrenCount, totalNodeCount - nodesAllocated); if (depth == 1) { tree = tree.AddChildren(Enumerable.Range(1, maxChildrenCount).Select(n => ProjectTree.Create(counter()))); nodesAllocated += maxChildrenCount; } else { int childrenCount = random.Next(maxChildrenCount) + 1; int sizePerBranch = (totalNodeCount - nodesAllocated) / childrenCount; if (sizePerBranch > 0) { tree = tree.AddChildren(Enumerable.Range(1, childrenCount).Select(n => ConstructVeryLargeTree(random, depth - 1, maxImmediateChildrenCount, sizePerBranch, counter).ProjectTree)); } } return(tree); }
public UnattachedProjectTreeNodeTest2() { this.node = (ProjectTree)this.NewTree(Caption, children: this.Children); }
public static IReadOnlyList <DiffGram> GetDelta(ProjectTree before, ProjectTree after) { return(after.ChangesSince(before)); }
public static IReadOnlyList<DiffGram> GetDelta(ProjectTree before, ProjectTree after) { return after.ChangesSince(before); }
partial static void CreateDefaultTemplate(ref ProjectTree.Template template) { template.Children = ImmutableSortedSet.Create(ProjectTreeSort.Default); template.Capabilities = ImmutableHashSet.Create<string>(StringComparer.OrdinalIgnoreCase); template.Visible = true; }