Forge
csharpdeeb25a2
1using CascadeIDE.Features.WorkspaceNavigation.Application;
2using CascadeIDE.Services.CodeNavigation;
3using Microsoft.CodeAnalysis.CSharp;
4using Xunit;
5
6namespace CascadeIDE.Tests;
7
8public sealed class CodeNavigationControlFlowScopeResolverTests
9{
10 [Fact]
11 public void TryFindScope_InClassMethod_ReturnsMethodBody()
12 {
13 const string source = """
14using System;
15
16var x = 1;
17if (x > 0) { }
18
19class SmokeClient
20{
21 public void RequestPermissionAsync()
22 {
23 DoWork();
24 }
25
26 void DoWork() { }
27}
28""";
29
30 var tree = CSharpSyntaxTree.ParseText(source);
31 var root = tree.GetRoot()!;
32 var offset = source.IndexOf("DoWork();", StringComparison.Ordinal);
33 var (line, col) = WorkspaceNavigationMapOrchestrator.ComputeLineColumn(source, offset);
34
35 var scope = CodeNavigationControlFlowScopeResolver.TryFindScope(root, tree, line, col);
36
37 Assert.NotNull(scope);
38 Assert.False(scope.IsTopLevel);
39 Assert.Equal("RequestPermissionAsync", scope.ScopeLabel);
40 }
41
42 [Fact]
43 public void TryFindScope_InTopLevel_ReturnsAllGlobals()
44 {
45 const string source = """
46var x = 1;
47Console.WriteLine(x);
48""";
49
50 var tree = CSharpSyntaxTree.ParseText(source);
51 var root = tree.GetRoot()!;
52 var scope = CodeNavigationControlFlowScopeResolver.TryFindScope(root, tree, line: 2, column: 5);
53
54 Assert.NotNull(scope);
55 Assert.True(scope.IsTopLevel);
56 Assert.Equal(2, scope.TopLevelStatements.Count);
57 }
58
59 [Fact]
60 public void TryFindScope_InLocalFunction_ReturnsFunctionBody()
61 {
62 const string source = """
63var x = 1;
64
65static void Helper()
66{
67 Console.WriteLine("hi");
68}
69""";
70
71 var tree = CSharpSyntaxTree.ParseText(source);
72 var root = tree.GetRoot()!;
73 var offset = source.IndexOf("Console.WriteLine", StringComparison.Ordinal);
74 var (line, col) = WorkspaceNavigationMapOrchestrator.ComputeLineColumn(source, offset);
75
76 var scope = CodeNavigationControlFlowScopeResolver.TryFindScope(root, tree, line, col);
77
78 Assert.NotNull(scope);
79 Assert.False(scope.IsTopLevel);
80 Assert.Equal("Helper", scope.ScopeLabel);
81 }
82
83 [Fact]
84 public void BuildJson_AcpSmoke_InSmokeClientMethod_SmallerThanTopLevel()
85 {
86 var path = Path.GetFullPath(Path.Combine(
87 AppContext.BaseDirectory,
88 "..", "..", "..", "..", "..",
89 "samples", "AcpSmokeDotnet", "Program.cs"));
90 Assert.True(File.Exists(path), path);
91
92 var source = File.ReadAllText(path);
93 var methodOffset = source.IndexOf("RequestPermissionAsync", StringComparison.Ordinal);
94 var (methodLine, methodCol) = WorkspaceNavigationMapOrchestrator.ComputeLineColumn(source, methodOffset);
95
96 var topOffset = source.IndexOf("InitializeAsync", StringComparison.Ordinal);
97 var (topLine, topCol) = WorkspaceNavigationMapOrchestrator.ComputeLineColumn(source, topOffset);
98
99 var methodJson = CodeNavigationMethodIntentSubgraphBuilder.BuildJson(
100 path, source, methodLine, methodCol, 48, 96);
101 var topJson = CodeNavigationMethodIntentSubgraphBuilder.BuildJson(
102 path, source, topLine, topCol, 48, 96);
103
104 using var methodDoc = System.Text.Json.JsonDocument.Parse(methodJson);
105 using var topDoc = System.Text.Json.JsonDocument.Parse(topJson);
106 var methodNodes = methodDoc.RootElement.GetProperty("nodes").GetArrayLength();
107 var topNodes = topDoc.RootElement.GetProperty("nodes").GetArrayLength();
108
109 Assert.True(methodNodes < topNodes, $"method={methodNodes}, top-level={topNodes}");
110 Assert.True(methodNodes <= 6, $"method scope should be compact, got {methodNodes}");
111 Assert.True(topNodes >= 15, $"top-level should be large, got {topNodes}");
112 }
113}
114
View only · write via MCP/CIDE