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);
        }
Example #8
0
 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());
     }
 }
Example #9
0
        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);
        }
        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 NewNode(params ProjectTree[] children)
        {
            this.nodeCounter++;
            var tree = ProjectTree.Create(Caption + this.nodeCounter);

            if (children != null)
            {
                tree = tree.WithChildren(children);
            }

            return(tree);
        }
Example #14
0
        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);
        }
Example #22
0
        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 }));
 }
        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());
        }
Example #26
0
        internal ProjectTree CloneProjectTreeLeafToRoot(ProjectTree templateTree)
        {
            var clone = ProjectTree.Create(templateTree.Caption).AddChildren(templateTree.Children.Select(this.CloneProjectTreeLeafToRoot));

            return(clone);
        }
Example #27
0
        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);
 }
 public UnattachedProjectTreeNodeTest2()
 {
     this.node = (ProjectTree)this.NewTree(Caption, children: this.Children);
 }
partial         static void CreateDefaultTemplate(ref ProjectTree.Template template)
        {
            template.Children = ImmutableSortedSet.Create(ProjectTreeSort.Default);
            template.Capabilities = ImmutableHashSet.Create<string>(StringComparer.OrdinalIgnoreCase);
            template.Visible = true;
        }
        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);
        }