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); } }
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); } }
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")); } }
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); } }
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); } }
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); } }
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); } }
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"); } }
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"); } }
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); }