Forge
csharp4405de34
1using CascadeIDE.Cockpit.Graph;
2using CascadeIDE.Cockpit.Graph.Layout;
3using CascadeIDE.Features.WorkspaceNavigation.Application;
4using CascadeIDE.Models;
5using Xunit;
6
7namespace CascadeIDE.Tests;
8
9public sealed class GraphRelatedFileHierarchyLayoutEngineTests
10{
11 /// <summary>
12 /// Регрессия 2026-05: <c>Math.Clamp(step, 38, innerH/(n+1))</c> при <c>38 &gt; innerH/(n+1)</c>
13 /// (типично ~32 при умеренной высоте) кидал ArgumentException → «Не удалось разобрать ответ навигации».
14 /// </summary>
15 [Theory]
16 [InlineData(5, 200)]
17 [InlineData(37, 520)]
18 public void Layout_top_down_regression_inverted_math_clamp_bounds_does_not_throw(int satelliteCount, double height)
19 {
20 var doc = BuildStarDoc(satelliteCount);
21 var engine = new GraphRelatedFileHierarchyLayoutEngine(anchorAtTop: true);
22
23 var ex = Record.Exception(() =>
24 engine.Layout(doc, width: 280, height, CodeNavigationMapDetailLevel.Normal));
25
26 Assert.Null(ex);
27 }
28
29 [Fact]
30 public void Layout_many_satellites_top_down_places_all_nodes()
31 {
32 var doc = BuildStarDoc(satelliteCount: 37);
33 var engine = new GraphRelatedFileHierarchyLayoutEngine(anchorAtTop: true);
34
35 var scene = engine.Layout(doc, width: 280, height: 520, CodeNavigationMapDetailLevel.Normal);
36
37 Assert.Equal(38, scene.Nodes.Count);
38 Assert.All(scene.Nodes, n => Assert.True(n.Radius > 0));
39 Assert.All(scene.Nodes, n => Assert.Equal(GraphNodeShape.Rectangle, n.Shape));
40 }
41
42 [Fact]
43 public void Compositor_file_top_down_many_related_nodes_does_not_throw()
44 {
45 var nodes = new List<GraphNode>
46 {
47 new() { Id = "n0", Path = @"D:\w\A.cs", Kind = "anchor", Label = "A.cs" }
48 };
49 for (var i = 1; i <= 37; i++)
50 {
51 nodes.Add(new GraphNode
52 {
53 Id = $"n{i}",
54 Path = $@"D:\w\B{i}.cs",
55 Kind = "project_peer",
56 Label = $"B{i}.cs"
57 });
58 }
59
60 var doc = new GraphDocument
61 {
62 AnchorPath = @"D:\w\A.cs",
63 Kind = GraphKind.RelatedFiles,
64 Nodes = nodes,
65 Edges = nodes.Skip(1).Select(n => new GraphEdge { FromId = "n0", ToId = n.Id, Kind = "related_to" }).ToList()
66 };
67
68 var compositor = new CodeNavigationMapCompositor();
69 var result = compositor.Compose(
70 new CodeNavigationMapCompositionIntent(
71 doc,
72 CodeNavigationMapLevelKind.File,
73 CodeNavigationMapDetailLevel.Normal,
74 CodeNavigationMapRelatedGraphLayoutKind.TopDown,
75 CodeNavigationMapControlFlowMainAxisKind.Auto),
76 new Services.SkiaInstruments.SkiaInstrumentViewport(280, 120));
77
78 Assert.True(result.PreferredHeight >= 120);
79 Assert.Equal(38, result.ToSceneVm(280, result.PreferredHeight).Nodes.Count);
80 }
81
82 private static GraphDocument BuildStarDoc(int satelliteCount)
83 {
84 var nodes = new List<GraphNode>
85 {
86 new() { Id = "n0", Path = @"D:\w\A.cs", Kind = "anchor", Label = "A.cs" }
87 };
88 for (var i = 1; i <= satelliteCount; i++)
89 {
90 nodes.Add(new GraphNode
91 {
92 Id = $"n{i}",
93 Path = $@"D:\w\B{i}.cs",
94 Kind = "project_peer",
95 Label = $"B{i}.cs"
96 });
97 }
98
99 return new GraphDocument
100 {
101 AnchorPath = @"D:\w\A.cs",
102 Nodes = nodes,
103 Edges = nodes.Skip(1).Select(n => new GraphEdge { FromId = "n0", ToId = n.Id }).ToList()
104 };
105 }
106}
107
View only · write via MCP/CIDE