public async Task When_Two_Roots()
        {
            using (var workspace = WorkspaceUtils.GetSubjectSolution())
            {
                var project = workspace.CurrentSolution.Projects.Single(p => p.Name == "SubjectSolution");

                var graph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default);

                var someClassNode         = graph.Nodes[TypeNodeKey.GetFromFullName("SubjectSolution.SomeClass")];
                var someCircularClassNode = graph.Nodes[TypeNodeKey.GetFromFullName("SubjectSolution.SomeCircularClass")];

                var roots = new HashSet <Node>();
                roots.Add(someClassNode);
                roots.Add(someCircularClassNode);

                var paths = NodeGraphExtensions.GetMultiDependencyRootPaths(graph, roots).ToArray();
                var path  = paths.Single();

                Assert.AreEqual(someClassNode, path.Source);
                Assert.AreEqual(someCircularClassNode, path.Target);
                Assert.AreEqual(2, path.Intermediates.Count);
                Assert.AreEqual("SomeOtherClass", (path.Intermediates[0] as TypeNode).Identifier.Name);
                Assert.AreEqual("SomeDeeperClass", (path.Intermediates[1] as TypeNode).Identifier.Name);
            }
        }
Esempio n. 2
0
        public async Task When_Display_Graph_Two_Roots_No_Extension()
        {
            using (var workspace = WorkspaceUtils.GetSubjectSolution())
            {
                var project     = workspace.CurrentSolution.Projects.Single(p => p.Name == "SubjectSolution");
                var compilation = await project.GetCompilationAsync();

                var someClassTree         = compilation.SyntaxTrees.Single(t => Path.GetFileName(t.FilePath) == "SomeClass.cs");
                var someCircularClassTree = compilation.SyntaxTrees.Single(t => Path.GetFileName(t.FilePath) == "SomeCircularClass.cs");

                var roots =
                    new[] {
                    (await someClassTree.GetRootAsync()).GetAllDeclaredTypes(compilation.GetSemanticModel(someClassTree)).First(),
                    (await someCircularClassTree.GetRootAsync()).GetAllDeclaredTypes(compilation.GetSemanticModel(someCircularClassTree)).First()
                };


                var fullGraph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution),
                                                           ct : default);

                var displayGraph = fullGraph.GetDisplaySubgraph(roots);
                Assert.AreEqual(2, displayGraph.VertexCount);
                var simpleEdges = displayGraph.Edges.OfType <SimpleDisplayEdge>().ToArray();
                var multiEdges  = displayGraph.Edges.OfType <MultiDependencyDisplayEdge>().ToArray();
                Assert.AreEqual(0, simpleEdges.Length);
                Assert.AreEqual(1, multiEdges.Length);
            }
        }
Esempio n. 3
0
        public async Task When_MultiDependency_Edge()
        {
            using (var workspace = WorkspaceUtils.GetSubjectSolution())
            {
                var project = workspace.CurrentSolution.Projects.Single(p => p.Name == "SubjectSolution");

                var graph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default);

                var someClassNode = graph.Nodes[TypeNodeKey.GetFromFullName("SubjectSolution.SomeClass")];
                var deepClassNode = graph.Nodes[TypeNodeKey.GetFromFullName("SubjectSolution.SomeClassDepth5")];

                var roots = new HashSet <Node>();
                roots.Add(someClassNode);
                roots.Add(deepClassNode);

                var paths = NodeGraphExtensions.GetMultiDependencyRootPaths(graph, roots).ToArray();
                var path  = paths.Single();

                var displayGraph = graph.GetDisplaySubgraph(subgraphNodes: roots, pinnedNodes: SetUtils.GetEmpty <NodeKey>());

                var multiEdges = displayGraph.Edges.OfType <MultiDependencyDisplayEdge>();

                AssertEx.ContainsSingle(multiEdges, m => m.Source.DisplayString.EndsWith("SomeClass") && m.Target.DisplayString.EndsWith("SomeClassDepth5"));
            }
        }
Esempio n. 4
0
        public async Task When_Building_From_Subject()
        {
            using (var workspace = WorkspaceUtils.GetSubjectSolution())
            {
                var project     = workspace.CurrentSolution.Projects.Single(p => p.Name == "SubjectSolution");
                var compilation = await project.GetCompilationAsync();

                var someClassTree = compilation.SyntaxTrees.Single(t => Path.GetFileName(t.FilePath) == "SomeClass.cs");
                var rootNode      = await someClassTree.GetRootAsync();

                var model = compilation.GetSemanticModel(someClassTree);

                var classSymbol = rootNode.GetAllDeclaredTypes(model).First();
                Assert.AreEqual("SomeClass", classSymbol.Name);

                var graph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default);

                var root = graph.GetNodeForType(classSymbol);
                Assert.AreEqual(classSymbol.ToIdentifier(), root.Identifier);
                Assert.AreEqual(4, root.ForwardLinks.Count);
                AssertEx.Contains(root.ForwardLinkNodes, n => (n as TypeNode)?.Identifier.Name == "SomeEnumeratedClass");
                AssertEx.Contains(root.ForwardLinkNodes, n => (n as TypeNode)?.Identifier.Name == "SomeClassCore");
                var someOtherClassNode = AssertEx.Contains(root.ForwardLinkNodes, n => (n as TypeNode)?.Identifier.Name == "SomeOtherClass") as TypeNode;

                CollectionAssert.Contains(someOtherClassNode.BackLinkNodes, root);
                AssertEx.Contains(someOtherClassNode.BackLinkNodes, n => (n as TypeNode)?.Identifier.Name == "SomeCircularClass");
                AssertEx.Contains(someOtherClassNode.ForwardLinkNodes, n => (n as TypeNode)?.Identifier.Name == "SomeClassInArray");
                AssertEx.Contains(someOtherClassNode.ForwardLinkNodes, n => (n as TypeNode)?.Identifier.Name == "SomeDeeperClass");

                AssertConsistentState(graph);
            }
        }
Esempio n. 5
0
        public async Task When_Root_With_BackLinks()
        {
            using (var workspace = WorkspaceUtils.GetSubjectSolution())
            {
                var project     = workspace.CurrentSolution.Projects.Single(p => p.Name == "SubjectSolution");
                var compilation = await project.GetCompilationAsync();

                var someClassTree = compilation.SyntaxTrees.Single(t => Path.GetFileName(t.FilePath) == "SomeOtherClass.cs");
                var rootNode      = await someClassTree.GetRootAsync();

                var model = compilation.GetSemanticModel(someClassTree);

                var classSymbol = rootNode.GetAllDeclaredTypes(model).First();
                Assert.AreEqual("SomeOtherClass", classSymbol.Name);

                var graph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default);

                var root = graph.GetNodeForType(classSymbol);
                Assert.AreEqual(classSymbol.ToIdentifier(), root.Identifier);

                Assert.AreEqual(3, root.ForwardLinks.Count);
                Assert.AreEqual(2, root.BackLinks.Count);

                AssertConsistentState(graph);
            }
        }
Esempio n. 6
0
        public async Task When_Implemented_Interface()
        {
            using (var workspace = WorkspaceUtils.GetSubjectSolution())
            {
                var fullGraph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default);

                var implementingClassNode = fullGraph.Nodes.Values.Single(n => (n as TypeNode)?.Identifier.Name == "SomeBaseClass");
                AssertImplements(implementingClassNode, "ISomeInheritedInterface");
                AssertImplements(implementingClassNode, "ISomeStillOtherInterface");
                AssertImplements(implementingClassNode, "ISomeGenericInterface<T>");

                void AssertImplements(Node implementer, string interfaceName)
                {
                    var interfaceLink = AssertEx.ContainsSingle(implementer.ForwardLinks, l => (l.Dependency as TypeNode)?.Identifier.Name == interfaceName);

                    Assert.AreEqual(LinkType.ImplementsInterface, interfaceLink.LinkType);
                }

                ;
                //var baseClassLink = AssertEx.ContainsSingle(inheritedClassNode.ForwardLinks, l => (l.Dependency as TypeNode)?.Identifier.Name == "SomeBaseClass");
                //Assert.AreEqual(LinkType.InheritsFromClass, baseClassLink.LinkType);
                //var derivedClassLink = AssertEx.ContainsSingle(inheritedClassNode.BackLinks, l => (l.Dependent as TypeNode)?.Identifier.Name == "SomeInheritedClassDepth2");
                //Assert.AreEqual(LinkType.InheritsFromClass, baseClassLink.LinkType);
            }
        }
Esempio n. 7
0
        public async Task When_Inherited_Class_Generic()
        {
            using (var workspace = WorkspaceUtils.GetSubjectSolution())
            {
                var fullGraph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default);

                var inheritedClassNode = fullGraph.Nodes.Values.Single(n => (n as TypeNode)?.Identifier.Name == "SomeInheritedConcretifiedClass");
                var baseClassLink      = AssertEx.ContainsSingle(inheritedClassNode.ForwardLinks, l => (l.Dependency as TypeNode)?.Identifier.Name == "SomeBaseGenericClass<T>");
                Assert.AreEqual(LinkType.InheritsFromClass, baseClassLink.LinkType);
            }
        }
Esempio n. 8
0
        public async Task When_Purely_Generated_Excluded()
        {
            using (var workspace = WorkspaceUtils.GetSubjectSolution())
            {
                var fullGraph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default);

                AssertEx.Contains(fullGraph.Nodes, n => (n.Value as TypeNode)?.Identifier.Name == "SomeGeneratedClass");
                AssertEx.Contains(fullGraph.Nodes, n => (n.Value as TypeNode)?.Identifier.Name == "SomePartiallyGeneratedClass");

                var graphWithGeneratedExcluded = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), excludePureGenerated : true);

                AssertEx.None(graphWithGeneratedExcluded.Nodes, n => (n.Value as TypeNode)?.Identifier.Name == "SomeGeneratedClass");
                AssertEx.Contains(graphWithGeneratedExcluded.Nodes, n => (n.Value as TypeNode)?.Identifier.Name == "SomePartiallyGeneratedClass");
            }
        }
Esempio n. 9
0
        public async Task When_Project_Excluded()
        {
            using (var workspace = WorkspaceUtils.GetSubjectSolution())
            {
                var fullGraph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default);

                AssertEx.Contains(fullGraph.Nodes, n => (n.Value as TypeNode)?.Identifier.Name == "SomeClassCore");

                var mainProject = workspace.CurrentSolution.Projects.Single(p => p.Name == "SubjectSolution");

                var graphWithCoreExcluded = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), new[] { mainProject.ToIdentifier() });

                AssertEx.None(graphWithCoreExcluded.Nodes, n => (n.Value as TypeNode)?.Identifier.Name == "SomeClassCore");
            }
        }
Esempio n. 10
0
        public async Task When_Link_External_Assembly()
        {
            using (var workspace = WorkspaceUtils.GetSubjectSolution())
            {
                var graph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default);

                var someClassKey      = TypeNodeKey.GetFromFullName("SubjectSolution.SomeClass");
                var someClassNode     = graph.Nodes[someClassKey];
                var someClassCoreKey  = TypeNodeKey.GetFromFullName("SubjectSolution.Core.SomeClassCore");
                var someClassCoreNode = graph.Nodes[someClassCoreKey];

                var forwardLink = AssertEx.Contains(someClassNode.ForwardLinkNodes, n => n.Key.Equals(someClassCoreKey));
                Assert.AreEqual(someClassCoreNode, forwardLink);

                var backLink = AssertEx.Contains(someClassCoreNode.BackLinkNodes, n => n.Key.Equals(someClassKey));
                Assert.AreEqual(someClassNode, backLink);
            }
        }
        public async Task When_Updated_Reference_Added()
        {
            using var workspace = WorkspaceUtils.GetSubjectSolution();

            var fullGraph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default);

            var mutableClassKey  = TypeNodeKey.GetFromFullName("SubjectSolution.Mutable.SomeMutableClass");
            var mutableClassNode = (TypeNode)fullGraph.Nodes[mutableClassKey];

            Assert.AreEqual(1, mutableClassNode.ForwardLinks.Count);

            var project    = workspace.CurrentSolution.Projects.Single(p => p.Name == "SubjectSolution");
            var mutableDoc = project.Documents.Single(d => d.FilePath.EndsWith("SomeMutableClass.cs"));

            var mutableRoot = await mutableDoc.GetSyntaxRootAsync();

            var replaceableMethod = mutableRoot.DescendantNodes().OfType <MethodDeclarationSyntax>().Single(m => m.Identifier.Text == "MightBeReplaced");

            var replacementText = @"
		public void MightBeReplaced()
		{
			var replacement = new SomeClassAddableReference();
		}
";

            var mutableDocText = await mutableDoc.GetTextAsync();

            var mutatedMutableDocText = mutableDocText.Replace(replaceableMethod.Span, replacementText);
            var mutatedMutableDoc     = mutableDoc.WithText(mutatedMutableDocText);

            Assert.AreEqual(mutableDoc.Id, mutatedMutableDoc.Id);

            var mutatedSolution = mutatedMutableDoc.Project.Solution;

            await fullGraph.Update(CompilationCache.CacheWithSolution(mutatedSolution), new[] { mutableDoc.Id }, default);

            var mutatedmutableClassNode = (TypeNode)fullGraph.Nodes[mutableClassKey];             // For now this is reference-equal to mutableClassNode, but let's try not to rely on it

            Assert.AreEqual(2, mutableClassNode.ForwardLinks.Count);
            AssertEx.Contains(mutableClassNode.ForwardLinkNodes, n => (n as TypeNode).Identifier.Name == "SomeClassAddableReference");

            AssertConsistentState(fullGraph);
        }
        public async Task When_Updated_Invariant()
        {
            using var workspace = WorkspaceUtils.GetSubjectSolution();

            var fullGraph = await NodeGraph.BuildGraph(CompilationCache.CacheWithSolution(workspace.CurrentSolution), ct : default);

            var initialState = fullGraph.Nodes.ToDictionary(kvp => kvp.Key, kvp => (kvp.Value.BackLinks.ToList(), kvp.Value.ForwardLinks.ToList()));

            await fullGraph.Update(CompilationCache.CacheWithSolution(workspace.CurrentSolution), workspace.CurrentSolution.GetAllDocumentIds(), default);

            Assert.AreEqual(initialState.Count, fullGraph.Nodes.Count);

            foreach (var kvp in fullGraph.Nodes)
            {
                Assert.IsTrue(initialState.ContainsKey(kvp.Key));
                var initialNodeState = initialState[kvp.Key];
                var node             = kvp.Value;
                CollectionAssert.AreEqual(initialNodeState.Item1, node.BackLinks);
                CollectionAssert.AreEqual(initialNodeState.Item2, node.ForwardLinks);
            }

            AssertConsistentState(fullGraph);
        }