public void CanConvertCodeFlowToTreeOnlyDeclarations() { var codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[] { new ThreadFlowLocation { NestingLevel = 0, // Declaration }, new ThreadFlowLocation { NestingLevel = 0, // Declaration }, new ThreadFlowLocation { NestingLevel = 0, // Declaration }, }); List <CallTreeNode> topLevelNodes = CodeFlowToTreeConverter.Convert(codeFlow, run: null); topLevelNodes.Count.Should().Be(3); topLevelNodes[0].Children.Should().BeEmpty(); topLevelNodes[1].Children.Should().BeEmpty(); topLevelNodes[2].Children.Should().BeEmpty(); topLevelNodes[1].Location.NestingLevel.Should().Be(0); // Declaration topLevelNodes[0].Location.NestingLevel.Should().Be(0); // Declaration topLevelNodes[2].Location.NestingLevel.Should().Be(0); // Declaration topLevelNodes[0].Parent.Should().Be(null); topLevelNodes[1].Parent.Should().Be(null); topLevelNodes[2].Parent.Should().Be(null); }
public void SelectPreviousNextCommandsTest() { var codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[] { new ThreadFlowLocation { NestingLevel = 0 }, new ThreadFlowLocation { NestingLevel = 1 }, new ThreadFlowLocation { NestingLevel = 1 }, new ThreadFlowLocation { NestingLevel = 1 }, new ThreadFlowLocation { NestingLevel = 0 }, new ThreadFlowLocation { NestingLevel = 0 } }); var mockToolWindow = new Mock <IToolWindow>(); mockToolWindow.Setup(s => s.UpdateSelectionList(It.IsAny <object[]>())); CallTree callTree = new CallTree(CodeFlowToTreeConverter.Convert(codeFlow, run: null), mockToolWindow.Object); callTree.FindPrevious().Should().Be(null); callTree.FindNext().Should().Be(null); callTree.SelectedItem = callTree.TopLevelNodes[0]; callTree.FindPrevious().Should().Be(callTree.TopLevelNodes[0]); callTree.FindNext().Should().Be(callTree.TopLevelNodes[0].Children[0]); callTree.SelectedItem = callTree.TopLevelNodes[0].Children[0]; callTree.FindPrevious().Should().Be(callTree.TopLevelNodes[0]); callTree.FindNext().Should().Be(callTree.TopLevelNodes[0].Children[1]); callTree.SelectedItem = callTree.TopLevelNodes[0].Children[2]; callTree.FindPrevious().Should().Be(callTree.TopLevelNodes[0].Children[1]); callTree.FindNext().Should().Be(callTree.TopLevelNodes[1]); callTree.SelectedItem = callTree.TopLevelNodes[1]; callTree.FindPrevious().Should().Be(callTree.TopLevelNodes[0].Children[2]); callTree.FindNext().Should().Be(callTree.TopLevelNodes[2]); callTree.SelectedItem = callTree.TopLevelNodes[2]; callTree.FindPrevious().Should().Be(callTree.TopLevelNodes[1]); callTree.FindNext().Should().Be(callTree.TopLevelNodes[2]); }
public void SelectPreviousNextCommandsTest() { CodeFlow codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[] { new ThreadFlowLocation { NestingLevel = 0, }, new ThreadFlowLocation { NestingLevel = 1, }, new ThreadFlowLocation { NestingLevel = 1, }, new ThreadFlowLocation { NestingLevel = 1, }, new ThreadFlowLocation { NestingLevel = 0, }, new ThreadFlowLocation { NestingLevel = 0, }, }); var analysisStep = new AnalysisStep(CodeFlowToTreeConverter.Convert(codeFlow, run: null, resultId: 0, runIndex: 0)); analysisStep.FindPrevious().Should().Be(null); analysisStep.FindNext().Should().Be(null); analysisStep.SelectedItem = analysisStep.TopLevelNodes[0]; analysisStep.FindPrevious().Should().Be(analysisStep.TopLevelNodes[0]); analysisStep.FindNext().Should().Be(analysisStep.TopLevelNodes[0].Children[0]); analysisStep.SelectedItem = analysisStep.TopLevelNodes[0].Children[0]; analysisStep.FindPrevious().Should().Be(analysisStep.TopLevelNodes[0]); analysisStep.FindNext().Should().Be(analysisStep.TopLevelNodes[0].Children[1]); analysisStep.SelectedItem = analysisStep.TopLevelNodes[0].Children[2]; analysisStep.FindPrevious().Should().Be(analysisStep.TopLevelNodes[0].Children[1]); analysisStep.FindNext().Should().Be(analysisStep.TopLevelNodes[1]); analysisStep.SelectedItem = analysisStep.TopLevelNodes[1]; analysisStep.FindPrevious().Should().Be(analysisStep.TopLevelNodes[0].Children[2]); analysisStep.FindNext().Should().Be(analysisStep.TopLevelNodes[2]); analysisStep.SelectedItem = analysisStep.TopLevelNodes[2]; analysisStep.FindPrevious().Should().Be(analysisStep.TopLevelNodes[1]); analysisStep.FindNext().Should().Be(analysisStep.TopLevelNodes[2]); }
public static AnalysisStep ToAnalysisStep(this CodeFlow codeFlow, Run run, int resultId, int runIndex) { if (codeFlow.ThreadFlows?[0]?.Locations?.Count == 0) { return(null); } List <AnalysisStepNode> topLevelNodes = CodeFlowToTreeConverter.ToFlatList(codeFlow, run, resultId, runIndex); return(new AnalysisStep(topLevelNodes)); }
public static CallTree ToCallTree(this CodeFlow codeFlow) { if (codeFlow.ThreadFlows?[0]?.Locations?.Count == 0) { return(null); } List <CallTreeNode> topLevelNodes = CodeFlowToTreeConverter.Convert(codeFlow); return(new CallTree(topLevelNodes, SarifViewerPackage.SarifToolWindow)); }
private CallTree CreateCallTree() { var codeFlow = new CodeFlow { Locations = new List <AnnotatedCodeLocation> { new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.Call, Importance = AnnotatedCodeLocationImportance.Unimportant, }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.Declaration, Importance = AnnotatedCodeLocationImportance.Important, }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.Declaration, Importance = AnnotatedCodeLocationImportance.Essential, }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.CallReturn, Importance = AnnotatedCodeLocationImportance.Unimportant, }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.Declaration, Importance = AnnotatedCodeLocationImportance.Unimportant, }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.Declaration, Importance = AnnotatedCodeLocationImportance.Essential, } } }; var mockToolWindow = new Mock <IToolWindow>(); mockToolWindow.Setup(s => s.UpdateSelectionList(It.IsAny <object[]>())); CallTree callTree = new CallTree(CodeFlowToTreeConverter.Convert(codeFlow), mockToolWindow.Object); return(callTree); }
private CallTree CreateCallTree() { var codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[] { new ThreadFlowLocation { NestingLevel = 0, Importance = ThreadFlowLocationImportance.Unimportant, }, new ThreadFlowLocation { NestingLevel = 1, Importance = ThreadFlowLocationImportance.Important, }, new ThreadFlowLocation { NestingLevel = 1, Importance = ThreadFlowLocationImportance.Essential, }, new ThreadFlowLocation { NestingLevel = 1, Importance = ThreadFlowLocationImportance.Unimportant, }, new ThreadFlowLocation { NestingLevel = 0, Importance = ThreadFlowLocationImportance.Unimportant, }, new ThreadFlowLocation { NestingLevel = 0, Importance = ThreadFlowLocationImportance.Essential, } }); var mockToolWindow = new Mock <IToolWindow>(); mockToolWindow.Setup(s => s.UpdateSelectionList(It.IsAny <object[]>())); CallTree callTree = new CallTree(CodeFlowToTreeConverter.Convert(codeFlow, run: null), mockToolWindow.Object); return(callTree); }
private AnalysisStep CreateAnalysisStep() { CodeFlow codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[] { new ThreadFlowLocation { NestingLevel = 0, Importance = ThreadFlowLocationImportance.Unimportant, }, new ThreadFlowLocation { NestingLevel = 1, Importance = ThreadFlowLocationImportance.Important, }, new ThreadFlowLocation { NestingLevel = 1, Importance = ThreadFlowLocationImportance.Essential, }, new ThreadFlowLocation { NestingLevel = 1, Importance = ThreadFlowLocationImportance.Unimportant, }, new ThreadFlowLocation { NestingLevel = 0, Importance = ThreadFlowLocationImportance.Unimportant, }, new ThreadFlowLocation { NestingLevel = 0, Importance = ThreadFlowLocationImportance.Essential, }, }); var analysisStep = new AnalysisStep(CodeFlowToTreeConverter.Convert(codeFlow, run: null, resultId: 0, runIndex: 0)); return(analysisStep); }
public void SelectPreviousNextCommandsCallNoChildrenTest() { var codeFlow = new CodeFlow { Locations = new List <AnnotatedCodeLocation> { new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.Call } } }; var mockToolWindow = new Mock <IToolWindow>(); mockToolWindow.Setup(s => s.UpdateSelectionList(It.IsAny <object[]>())); CallTree callTree = new CallTree(CodeFlowToTreeConverter.Convert(codeFlow), mockToolWindow.Object); callTree.SelectedItem = callTree.TopLevelNodes[0]; callTree.FindPrevious().Should().Be(callTree.TopLevelNodes[0]); callTree.FindNext().Should().Be(callTree.TopLevelNodes[0]); }
public void CanConvertCodeFlowToTreeOnlyDeclarations() { CodeFlow codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[] { new ThreadFlowLocation { NestingLevel = 0, // Declaration }, new ThreadFlowLocation { NestingLevel = 0, // Declaration }, new ThreadFlowLocation { NestingLevel = 0, // Declaration }, }); List <AnalysisStepNode> topLevelNodes = CodeFlowToTreeConverter.Convert(codeFlow, run: null, resultId: 0, runIndex: 0); topLevelNodes.Count.Should().Be(3); topLevelNodes[0].Children.Should().BeEmpty(); topLevelNodes[1].Children.Should().BeEmpty(); topLevelNodes[2].Children.Should().BeEmpty(); topLevelNodes[1].Location.NestingLevel.Should().Be(0); // Declaration topLevelNodes[0].Location.NestingLevel.Should().Be(0); // Declaration topLevelNodes[2].Location.NestingLevel.Should().Be(0); // Declaration topLevelNodes[0].Parent.Should().Be(null); topLevelNodes[1].Parent.Should().Be(null); topLevelNodes[2].Parent.Should().Be(null); List <AnalysisStepNode> flatNodes = CodeFlowToTreeConverter.ToFlatList(codeFlow, run: null, resultId: 0, runIndex: 0); VerifyCodeFlowFlatList(flatNodes, codeFlow, run: null); }
public void CanConvertCodeFlowToTreeOnlyDeclarations() { var codeFlow = new CodeFlow { Locations = new List <AnnotatedCodeLocation> { new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.Declaration }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.Declaration }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.Declaration }, } }; List <CallTreeNode> topLevelNodes = CodeFlowToTreeConverter.Convert(codeFlow); topLevelNodes.Count.Should().Be(3); topLevelNodes[0].Children.Should().BeEmpty(); topLevelNodes[1].Children.Should().BeEmpty(); topLevelNodes[2].Children.Should().BeEmpty(); topLevelNodes[0].Location.Kind.Should().Be(AnnotatedCodeLocationKind.Declaration); topLevelNodes[1].Location.Kind.Should().Be(AnnotatedCodeLocationKind.Declaration); topLevelNodes[2].Location.Kind.Should().Be(AnnotatedCodeLocationKind.Declaration); topLevelNodes[0].Parent.Should().Be(null); topLevelNodes[1].Parent.Should().Be(null); topLevelNodes[2].Parent.Should().Be(null); }
public void CanConvertCodeFlowToTree() { var codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[] { new ThreadFlowLocation { NestingLevel = 0, // Call Location = new Location { Message = new Message { Text = "first parent" } } }, new ThreadFlowLocation { NestingLevel = 1, // Call Location = new Location { Message = new Message { Text = "second parent" } } }, new ThreadFlowLocation { NestingLevel = 2, // CallReturn }, new ThreadFlowLocation { NestingLevel = 1, // Call Location = new Location { Message = new Message { Text = "third parent" } } }, new ThreadFlowLocation { NestingLevel = 2, // CallReturn }, new ThreadFlowLocation { NestingLevel = 1, // Call Location = new Location { Message = new Message { Text = "fourth parent" } } }, new ThreadFlowLocation { NestingLevel = 2, // CallReturn }, new ThreadFlowLocation { NestingLevel = 1, // CallReturn }, new ThreadFlowLocation { NestingLevel = 0, // Call Location = new Location { Message = new Message { Text = "fifth parent" } } }, new ThreadFlowLocation { NestingLevel = 1, // CallReturn, } }); List <CallTreeNode> topLevelNodes = CodeFlowToTreeConverter.Convert(codeFlow, run: null); topLevelNodes.Count.Should().Be(2); topLevelNodes[0].Children.Count.Should().Be(4); topLevelNodes[0].Children[2].Children.Count.Should().Be(1); // Check that we have the right nodes at the right places in the tree. topLevelNodes[0].Location.NestingLevel.Should().Be(0); // Call topLevelNodes[0].Children[0].Location.NestingLevel.Should().Be(1); // Call topLevelNodes[0].Children[0].Children[0].Location.NestingLevel.Should().Be(2); // CallReturn topLevelNodes[0].Children[1].Location.NestingLevel.Should().Be(1); // Call topLevelNodes[0].Children[1].Children[0].Location.NestingLevel.Should().Be(2); // CallReturn topLevelNodes[0].Children[2].Location.NestingLevel.Should().Be(1); // Call topLevelNodes[0].Children[2].Children[0].Location.NestingLevel.Should().Be(2); // CallReturn topLevelNodes[0].Children[3].Location.NestingLevel.Should().Be(1); // CallReturn topLevelNodes[1].Location.NestingLevel.Should().Be(0); // Call topLevelNodes[1].Children[0].Location.NestingLevel.Should().Be(1); // CallReturn // Check parents topLevelNodes[0].Parent.Should().Be(null); topLevelNodes[0].Children[0].Parent.Location.Location.Message.Text.Should().Be("first parent"); topLevelNodes[0].Children[0].Children[0].Parent.Location.Location.Message.Text.Should().Be("second parent"); topLevelNodes[0].Children[1].Parent.Location.Location.Message.Text.Should().Be("first parent"); topLevelNodes[0].Children[1].Children[0].Parent.Location.Location.Message.Text.Should().Be("third parent"); topLevelNodes[0].Children[2].Parent.Location.Location.Message.Text.Should().Be("first parent"); topLevelNodes[0].Children[2].Children[0].Parent.Location.Location.Message.Text.Should().Be("fourth parent"); topLevelNodes[0].Children[3].Parent.Location.Location.Message.Text.Should().Be("first parent"); topLevelNodes[1].Parent.Should().Be(null); topLevelNodes[1].Children[0].Parent.Location.Location.Message.Text.Should().Be("fifth parent"); }
public void CanConvertCodeFlowToTreeNonCallOrReturn() { var codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[] { new ThreadFlowLocation { NestingLevel = 0, // Call Location = new Location { Message = new Message { Text = "first parent", }, }, }, new ThreadFlowLocation { NestingLevel = 1, // Declaration }, new ThreadFlowLocation { NestingLevel = 1, // Declaration }, new ThreadFlowLocation { NestingLevel = 1, // Declaration }, new ThreadFlowLocation { NestingLevel = 1, // CallReturn }, new ThreadFlowLocation { NestingLevel = 0, // Call Location = new Location { Message = new Message { Text = "second parent", }, }, }, new ThreadFlowLocation { NestingLevel = 1, // Declaration }, new ThreadFlowLocation { NestingLevel = 1, // Declaration }, new ThreadFlowLocation { NestingLevel = 1, // CallReturn }, }); List <AnalysisStepNode> topLevelNodes = CodeFlowToTreeConverter.Convert(codeFlow, run: null, resultId: 0, runIndex: 0); topLevelNodes.Count.Should().Be(2); topLevelNodes[0].Children.Count.Should().Be(4); topLevelNodes[1].Children.Count.Should().Be(3); // Spot-check that we have the right nodes at the right places in the tree. topLevelNodes[0].Location.NestingLevel.Should().Be(0); // Call topLevelNodes[0].Children[0].Location.NestingLevel.Should().Be(1); // Declaration topLevelNodes[0].Children[3].Location.NestingLevel.Should().Be(1); // CallReturn topLevelNodes[1].Location.NestingLevel.Should().Be(0); // Call topLevelNodes[1].Children[2].Location.NestingLevel.Should().Be(1); // CallReturn // Check parents topLevelNodes[0].Parent.Should().Be(null); topLevelNodes[0].Children[0].Parent.Location.Location.Message.Text.Should().Be("first parent"); topLevelNodes[0].Children[1].Parent.Location.Location.Message.Text.Should().Be("first parent"); topLevelNodes[0].Children[2].Parent.Location.Location.Message.Text.Should().Be("first parent"); topLevelNodes[0].Children[3].Parent.Location.Location.Message.Text.Should().Be("first parent"); topLevelNodes[1].Parent.Should().Be(null); topLevelNodes[1].Children[0].Parent.Location.Location.Message.Text.Should().Be("second parent"); topLevelNodes[1].Children[1].Parent.Location.Location.Message.Text.Should().Be("second parent"); topLevelNodes[1].Children[2].Parent.Location.Location.Message.Text.Should().Be("second parent"); }
public void CanConvertCodeFlowToFlatListNonZeroBasedLevel() { CodeFlow codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[] { new ThreadFlowLocation { NestingLevel = 5, Location = new Location { Message = new Message { Text = "location level 5", }, PhysicalLocation = new PhysicalLocation { ArtifactLocation = new ArtifactLocation { Index = 0, } }, }, }, new ThreadFlowLocation { NestingLevel = 6, Location = new Location { Message = new Message { Text = "location level 6", }, PhysicalLocation = new PhysicalLocation { ArtifactLocation = new ArtifactLocation { Index = 0, } }, }, }, new ThreadFlowLocation { NestingLevel = 7, Location = new Location { Message = new Message { Text = "location level 7", }, PhysicalLocation = new PhysicalLocation { ArtifactLocation = new ArtifactLocation { Index = 0, } }, }, }, new ThreadFlowLocation { NestingLevel = 8, Location = new Location { Message = new Message { Text = "location level 8", }, PhysicalLocation = new PhysicalLocation { ArtifactLocation = new ArtifactLocation { Index = 0, } }, }, }, new ThreadFlowLocation { NestingLevel = 7, }, new ThreadFlowLocation { NestingLevel = 6, }, new ThreadFlowLocation { NestingLevel = 5, }, new ThreadFlowLocation { NestingLevel = 5, Location = new Location { Message = new Message { Text = "location level 5", }, PhysicalLocation = new PhysicalLocation { ArtifactLocation = new ArtifactLocation { Index = 1 } }, }, }, new ThreadFlowLocation { NestingLevel = 5, Location = new Location { Message = new Message { Text = "location level 5", }, PhysicalLocation = new PhysicalLocation { ArtifactLocation = new ArtifactLocation { Index = 2 } }, }, }, }); var run = new Run { Artifacts = new[] { new Artifact { Location = new ArtifactLocation { Uri = new Uri("path/to/file1.cpp", UriKind.Relative), } }, new Artifact { Location = new ArtifactLocation { Uri = new Uri("path/to/file2.cpp", UriKind.Relative), } }, new Artifact { Location = new ArtifactLocation { Uri = new Uri("path/to/file3.cpp", UriKind.Relative), } }, }, }; List <AnalysisStepNode> nodes = CodeFlowToTreeConverter.ToFlatList(codeFlow, run, resultId: 0, runIndex: 0); VerifyCodeFlowFlatList(nodes, codeFlow, run: null); }
public void CanConvertCodeFlowToFlatListZeroBasedLevel() { CodeFlow codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[] { new ThreadFlowLocation { NestingLevel = 0, Location = new Location { Message = new Message { Text = "location level 0", }, PhysicalLocation = new PhysicalLocation { ArtifactLocation = new ArtifactLocation { Uri = new Uri("path/to/file.cpp", UriKind.Relative), } }, }, }, new ThreadFlowLocation { NestingLevel = 1, Location = new Location { Message = new Message { Text = "location level 1", }, PhysicalLocation = new PhysicalLocation { ArtifactLocation = new ArtifactLocation { Uri = new Uri("path/to/file.cpp", UriKind.Relative), } }, }, }, new ThreadFlowLocation { NestingLevel = 2, }, new ThreadFlowLocation { NestingLevel = 1, Location = new Location { Message = new Message { Text = "location level 1", }, PhysicalLocation = new PhysicalLocation { ArtifactLocation = new ArtifactLocation { Uri = new Uri("path/to/file.cpp", UriKind.Relative), } }, }, }, new ThreadFlowLocation { NestingLevel = 2, }, new ThreadFlowLocation { NestingLevel = 1, Location = new Location { Message = new Message { Text = "location level 1", }, PhysicalLocation = new PhysicalLocation { ArtifactLocation = new ArtifactLocation { Uri = new Uri("path/to/file.cpp", UriKind.Relative), } }, }, }, new ThreadFlowLocation { NestingLevel = 2, }, new ThreadFlowLocation { NestingLevel = 1, }, new ThreadFlowLocation { NestingLevel = 0, Location = new Location { Message = new Message { Text = "location level 0", }, PhysicalLocation = new PhysicalLocation { ArtifactLocation = new ArtifactLocation { Uri = new Uri("path/to/file.cpp", UriKind.Relative), } }, }, }, new ThreadFlowLocation { NestingLevel = 1, }, }); List <AnalysisStepNode> nodes = CodeFlowToTreeConverter.ToFlatList(codeFlow, run: null, resultId: 0, runIndex: 0); VerifyCodeFlowFlatList(nodes, codeFlow, run: null); }
public void CanConvertCodeFlowToTree() { var codeFlow = new CodeFlow { Locations = new List <AnnotatedCodeLocation> { new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.Call, Message = "first parent" }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.Call, Message = "second parent" }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.CallReturn }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.Call, Message = "third parent" }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.CallReturn }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.Call, Message = "fourth parent" }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.CallReturn }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.CallReturn }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.Call, Message = "fifth parent" }, new AnnotatedCodeLocation { Kind = AnnotatedCodeLocationKind.CallReturn, }, } }; List <CallTreeNode> topLevelNodes = CodeFlowToTreeConverter.Convert(codeFlow); topLevelNodes.Count.Should().Be(2); topLevelNodes[0].Children.Count.Should().Be(4); topLevelNodes[0].Children[2].Children.Count.Should().Be(1); // Check that we have the right nodes at the right places in the tree. topLevelNodes[0].Location.Kind.Should().Be(AnnotatedCodeLocationKind.Call); topLevelNodes[0].Children[0].Location.Kind.Should().Be(AnnotatedCodeLocationKind.Call); topLevelNodes[0].Children[0].Children[0].Location.Kind.Should().Be(AnnotatedCodeLocationKind.CallReturn); topLevelNodes[0].Children[1].Location.Kind.Should().Be(AnnotatedCodeLocationKind.Call); topLevelNodes[0].Children[1].Children[0].Location.Kind.Should().Be(AnnotatedCodeLocationKind.CallReturn); topLevelNodes[0].Children[2].Location.Kind.Should().Be(AnnotatedCodeLocationKind.Call); topLevelNodes[0].Children[2].Children[0].Location.Kind.Should().Be(AnnotatedCodeLocationKind.CallReturn); topLevelNodes[0].Children[3].Location.Kind.Should().Be(AnnotatedCodeLocationKind.CallReturn); topLevelNodes[1].Location.Kind.Should().Be(AnnotatedCodeLocationKind.Call); topLevelNodes[1].Children[0].Location.Kind.Should().Be(AnnotatedCodeLocationKind.CallReturn); // Check parents topLevelNodes[0].Parent.Should().Be(null); topLevelNodes[0].Children[0].Parent.Location.Message.Should().Be("first parent"); topLevelNodes[0].Children[0].Children[0].Parent.Location.Message.Should().Be("second parent"); topLevelNodes[0].Children[1].Parent.Location.Message.Should().Be("first parent"); topLevelNodes[0].Children[1].Children[0].Parent.Location.Message.Should().Be("third parent"); topLevelNodes[0].Children[2].Parent.Location.Message.Should().Be("first parent"); topLevelNodes[0].Children[2].Children[0].Parent.Location.Message.Should().Be("fourth parent"); topLevelNodes[0].Children[3].Parent.Location.Message.Should().Be("first parent"); topLevelNodes[1].Parent.Should().Be(null); topLevelNodes[1].Children[0].Parent.Location.Message.Should().Be("fifth parent"); }