| 1 | using Avalonia; |
| 2 | using CascadeIDE.Cockpit.Cds; |
| 3 | using CascadeIDE.Cockpit.Channels.TraceFlow; |
| 4 | using CascadeIDE.Cockpit.Composition.TraceFlow; |
| 5 | using CascadeIDE.ViewModels; |
| 6 | using Xunit; |
| 7 | |
| 8 | namespace CascadeIDE.Tests; |
| 9 | |
| 10 | public sealed class TraceFlowSurfaceCompositorTests |
| 11 | { |
| 12 | [Fact] |
| 13 | public void Compose_WhenEnabled_AppliesHighlights() |
| 14 | { |
| 15 | var scene = BuildScene(); |
| 16 | var snapshot = new TraceFlowChannelSnapshot( |
| 17 | new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "n0", "n1" }, |
| 18 | new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "n0->n1" }); |
| 19 | var compositor = new TraceFlowSurfaceCompositor(); |
| 20 | |
| 21 | var result = compositor.Compose(scene, snapshot, new TraceFlowCdsDecision(true, "pfd", "normal")); |
| 22 | |
| 23 | Assert.Contains("n1", result.HighlightedNodeIds); |
| 24 | Assert.Contains("n0->n1", result.HighlightedEdgeKeys); |
| 25 | Assert.Equal(CodeNavigationMapGraphPresentationKind.CodeControlFlow, result.Presentation); |
| 26 | } |
| 27 | |
| 28 | [Fact] |
| 29 | public void Compose_WhenEnabled_PreservesWorkspacePresentation() |
| 30 | { |
| 31 | var scene = BuildScene(CodeNavigationMapGraphPresentationKind.WorkspaceRelatedFiles); |
| 32 | var snapshot = new TraceFlowChannelSnapshot( |
| 33 | new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "n0" }, |
| 34 | new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "n0->n1" }); |
| 35 | var compositor = new TraceFlowSurfaceCompositor(); |
| 36 | |
| 37 | var result = compositor.Compose(scene, snapshot, new TraceFlowCdsDecision(true, "pfd", "normal")); |
| 38 | |
| 39 | Assert.Equal(CodeNavigationMapGraphPresentationKind.WorkspaceRelatedFiles, result.Presentation); |
| 40 | } |
| 41 | |
| 42 | [Fact] |
| 43 | public void Compose_WhenDisabled_LeavesSceneUnhighlighted() |
| 44 | { |
| 45 | var scene = BuildScene(); |
| 46 | var snapshot = new TraceFlowChannelSnapshot( |
| 47 | new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "n0", "n1" }, |
| 48 | new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "n0->n1" }); |
| 49 | var compositor = new TraceFlowSurfaceCompositor(); |
| 50 | |
| 51 | var result = compositor.Compose(scene, snapshot, new TraceFlowCdsDecision(false, "none", "off")); |
| 52 | |
| 53 | Assert.Empty(result.HighlightedNodeIds); |
| 54 | Assert.Empty(result.HighlightedEdgeKeys); |
| 55 | } |
| 56 | |
| 57 | [Fact] |
| 58 | public void Router_EnablesOnlyForControlFlowInPfd() |
| 59 | { |
| 60 | var cds = new CockpitSurfaceState( |
| 61 | SchemaVersion: "0.3", |
| 62 | UiMode: "flight", |
| 63 | PresentationEffectiveLine: "line", |
| 64 | PresentationParseSuccess: true, |
| 65 | Topology: new CockpitSurfaceTopology("main", false, false, true), |
| 66 | MfdShell: new CockpitSurfaceMfdShell("none"), |
| 67 | Zones: new CockpitSurfaceZones(true, true, true, true, true, true), |
| 68 | Instruments: []); |
| 69 | |
| 70 | var router = new TraceFlowCdsRouter(); |
| 71 | var enabled = router.Route(new TraceFlowCdsRouteInput(cds, "controlFlow")); |
| 72 | var disabled = router.Route(new TraceFlowCdsRouteInput(cds, "file")); |
| 73 | |
| 74 | Assert.True(enabled.Enabled); |
| 75 | Assert.False(disabled.Enabled); |
| 76 | } |
| 77 | |
| 78 | private static CodeNavigationMapGraphSceneVm BuildScene( |
| 79 | CodeNavigationMapGraphPresentationKind presentation = CodeNavigationMapGraphPresentationKind.CodeControlFlow) => |
| 80 | new() |
| 81 | { |
| 82 | Nodes = |
| 83 | [ |
| 84 | Node("n0", true), |
| 85 | Node("n1") |
| 86 | ], |
| 87 | Edges = |
| 88 | [ |
| 89 | Edge("n0", "n1", "Call") |
| 90 | ], |
| 91 | Presentation = presentation |
| 92 | }; |
| 93 | |
| 94 | private static CodeNavigationMapGraphNodeLayout Node(string id, bool anchor = false) => new() |
| 95 | { |
| 96 | Id = id, |
| 97 | Kind = anchor ? "anchor" : "call_step", |
| 98 | FullPath = @"D:\w\A.cs", |
| 99 | Label = id, |
| 100 | Center = new Point(0, 0), |
| 101 | Radius = 10, |
| 102 | IsAnchor = anchor, |
| 103 | Shape = CodeNavigationMapNodeShape.Circle |
| 104 | }; |
| 105 | |
| 106 | private static CodeNavigationMapGraphEdgeLayout Edge(string from, string to, string kind) => new() |
| 107 | { |
| 108 | FromNodeId = from, |
| 109 | ToNodeId = to, |
| 110 | From = new Point(0, 0), |
| 111 | To = new Point(1, 1), |
| 112 | ToRadius = 10, |
| 113 | Kind = kind, |
| 114 | RelatedKind = kind |
| 115 | }; |
| 116 | } |
| 117 | |