| 1 | using Avalonia; |
| 2 | using CascadeIDE.Models; |
| 3 | using CascadeIDE.Cockpit.Graph; |
| 4 | using CascadeIDE.Services.CodeNavigation; |
| 5 | using CascadeIDE.Services.Navigation; |
| 6 | using CascadeIDE.Features.WorkspaceNavigation.Application; |
| 7 | using CascadeIDE.ViewModels; |
| 8 | using Xunit; |
| 9 | |
| 10 | namespace CascadeIDE.Tests; |
| 11 | |
| 12 | public sealed class CodeNavigationMapWorkspaceInstrumentBlockCompositorTests |
| 13 | { |
| 14 | [Fact] |
| 15 | public void Empty_Scene_Yields_No_Blocks() |
| 16 | { |
| 17 | var scene = new CodeNavigationMapGraphSceneVm { Nodes = [], Edges = [] }; |
| 18 | var blocks = CodeNavigationMapWorkspaceInstrumentBlockCompositor.Compose(scene, 400, 300); |
| 19 | Assert.Empty(blocks); |
| 20 | } |
| 21 | |
| 22 | [Fact] |
| 23 | public void File_Mode_No_Legend_One_Graph_Block_Full_Viewport() |
| 24 | { |
| 25 | var n = new CodeNavigationMapGraphNodeLayout |
| 26 | { |
| 27 | Id = "a", |
| 28 | Kind = "anchor", |
| 29 | FullPath = "x", |
| 30 | Label = "a", |
| 31 | Center = new Point(50, 50), |
| 32 | Radius = 10, |
| 33 | IsAnchor = true |
| 34 | }; |
| 35 | var scene = new CodeNavigationMapGraphSceneVm |
| 36 | { |
| 37 | Nodes = [n], |
| 38 | Edges = [], |
| 39 | UseLegendColumn = false, |
| 40 | LegendColumnLeft = 400 |
| 41 | }; |
| 42 | var blocks = CodeNavigationMapWorkspaceInstrumentBlockCompositor.Compose(scene, 400, 300); |
| 43 | Assert.Single(blocks); |
| 44 | Assert.Equal(CodeNavigationMapWorkspaceInstrumentBlockIds.Graph, blocks[0].Id); |
| 45 | Assert.Equal(new Rect(0, 0, 400, 300), blocks[0].Bounds); |
| 46 | } |
| 47 | |
| 48 | [Fact] |
| 49 | public void ControlFlow_Beside_Legend_Splits_Horizontally() |
| 50 | { |
| 51 | var scene = new CodeNavigationMapGraphSceneVm |
| 52 | { |
| 53 | Nodes = [TestNode("n0", 10, 10)], |
| 54 | Edges = [], |
| 55 | UseLegendColumn = true, |
| 56 | LegendColumnLeft = 220, |
| 57 | LegendPlacement = CodeNavigationMapLegendBlockPlacement.BesideGraph |
| 58 | }; |
| 59 | var blocks = CodeNavigationMapWorkspaceInstrumentBlockCompositor.Compose(scene, 400, 300); |
| 60 | Assert.Equal(2, blocks.Count); |
| 61 | Assert.Equal(CodeNavigationMapWorkspaceInstrumentBlockKind.Graph, blocks[0].Kind); |
| 62 | Assert.Equal(CodeNavigationMapWorkspaceInstrumentBlockKind.Legend, blocks[1].Kind); |
| 63 | Assert.Equal(new Rect(0, 0, 220, 300), blocks[0].Bounds); |
| 64 | Assert.Equal(new Rect(220, 0, 180, 300), blocks[1].Bounds); |
| 65 | } |
| 66 | |
| 67 | [Fact] |
| 68 | public void ControlFlow_Below_Legend_Splits_Vertically() |
| 69 | { |
| 70 | var scene = new CodeNavigationMapGraphSceneVm |
| 71 | { |
| 72 | Nodes = [TestNode("n0", 10, 10)], |
| 73 | Edges = [], |
| 74 | UseLegendColumn = true, |
| 75 | LegendColumnLeft = 0, |
| 76 | LegendPlacement = CodeNavigationMapLegendBlockPlacement.BelowGraph, |
| 77 | LegendBlockTopY = 180 |
| 78 | }; |
| 79 | var blocks = CodeNavigationMapWorkspaceInstrumentBlockCompositor.Compose(scene, 400, 400); |
| 80 | Assert.Equal(2, blocks.Count); |
| 81 | Assert.Equal(new Rect(0, 0, 400, 180), blocks[0].Bounds); |
| 82 | Assert.Equal(new Rect(0, 180, 400, 220), blocks[1].Bounds); |
| 83 | } |
| 84 | |
| 85 | [Fact] |
| 86 | public void Compositor_Integration_ControlFlow_Produces_Two_Blocks() |
| 87 | { |
| 88 | var c = new CodeNavigationMapCompositor(); |
| 89 | var doc = new GraphDocument |
| 90 | { |
| 91 | AnchorPath = "A.cs", |
| 92 | Nodes = |
| 93 | [ |
| 94 | new GraphNode |
| 95 | { |
| 96 | Id = "n0", |
| 97 | Path = "A.cs", |
| 98 | Kind = "anchor", |
| 99 | Label = "A" |
| 100 | }, |
| 101 | new GraphNode |
| 102 | { |
| 103 | Id = "n1", |
| 104 | Path = "A.cs", |
| 105 | Kind = "call_step", |
| 106 | Label = "S1", |
| 107 | LegendIndex = 1, |
| 108 | LegendText = "first line" |
| 109 | } |
| 110 | ], |
| 111 | Edges = [new GraphEdge { FromId = "n0", ToId = "n1", Kind = "Call" }] |
| 112 | }; |
| 113 | var r = c.Compose(doc, CodeNavigationMapLevelKind.ControlFlow, 500, 400, CodeNavigationMapDetailLevel.Inspect); |
| 114 | Assert.NotEmpty(r.CodeNavigationMapInstrumentBlocks); |
| 115 | Assert.Equal(2, r.CodeNavigationMapInstrumentBlocks.Count); |
| 116 | Assert.Contains(r.CodeNavigationMapInstrumentBlocks, b => b.Id == CodeNavigationMapInstrumentBlockIds.Graph); |
| 117 | Assert.Contains(r.CodeNavigationMapInstrumentBlocks, b => b.Id == CodeNavigationMapInstrumentBlockIds.Legend); |
| 118 | } |
| 119 | |
| 120 | private static CodeNavigationMapGraphNodeLayout TestNode(string id, double x, double y) => |
| 121 | new() |
| 122 | { |
| 123 | Id = id, |
| 124 | Kind = "call_step", |
| 125 | FullPath = "p", |
| 126 | Label = id, |
| 127 | Center = new Point(x, y), |
| 128 | Radius = 8, |
| 129 | IsAnchor = false |
| 130 | }; |
| 131 | } |
| 132 | |