Skip to main content

jellyflow_runtime/runtime/conformance/scenario/action/
layout_facts.rs

1use serde::{Deserialize, Serialize};
2
3use crate::runtime::connection::{ConnectionHandleRef, ResolvedConnectionTarget};
4use crate::runtime::geometry::{EdgePosition, HandlePosition, ResolvedEdgeRouteKind};
5use crate::runtime::measurement::NodeMeasurement;
6use jellyflow_core::core::{CanvasPoint, CanvasSize, EdgeId, NodeId};
7
8use super::ConformanceAction;
9
10pub(super) fn kind(action: &ConformanceAction) -> Option<&'static str> {
11    Some(match action {
12        ConformanceAction::ReportNodeMeasurement { .. } => "report_node_measurement",
13        ConformanceAction::AssertLayoutFacts { .. } => "assert_layout_facts",
14        _ => return None,
15    })
16}
17
18#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
19pub struct ConformanceLayoutFactsExpectation {
20    #[serde(default, skip_serializing_if = "Vec::is_empty")]
21    pub visible_node_ids: Vec<NodeId>,
22    #[serde(default, skip_serializing_if = "Vec::is_empty")]
23    pub visible_edge_ids: Vec<EdgeId>,
24    #[serde(default, skip_serializing_if = "Vec::is_empty")]
25    pub edge_positions: Vec<ConformanceLayoutEdgePosition>,
26    #[serde(default, skip_serializing_if = "Vec::is_empty")]
27    pub edge_routes: Vec<ConformanceLayoutEdgeRouteFacts>,
28    #[serde(default, skip_serializing_if = "Option::is_none")]
29    pub connection_target: Option<ConformanceLayoutFactsConnectionTargetExpectation>,
30}
31
32impl ConformanceLayoutFactsExpectation {
33    pub fn new(
34        visible_node_ids: impl IntoIterator<Item = NodeId>,
35        visible_edge_ids: impl IntoIterator<Item = EdgeId>,
36    ) -> Self {
37        Self {
38            visible_node_ids: visible_node_ids.into_iter().collect(),
39            visible_edge_ids: visible_edge_ids.into_iter().collect(),
40            edge_positions: Vec::new(),
41            edge_routes: Vec::new(),
42            connection_target: None,
43        }
44    }
45
46    pub fn with_edge_positions(
47        mut self,
48        edge_positions: impl IntoIterator<Item = ConformanceLayoutEdgePosition>,
49    ) -> Self {
50        self.edge_positions = edge_positions.into_iter().collect();
51        self
52    }
53
54    pub fn with_edge_routes(
55        mut self,
56        edge_routes: impl IntoIterator<Item = ConformanceLayoutEdgeRouteFacts>,
57    ) -> Self {
58        self.edge_routes = edge_routes.into_iter().collect();
59        self
60    }
61
62    pub fn with_connection_target(
63        mut self,
64        connection_target: ConformanceLayoutFactsConnectionTargetExpectation,
65    ) -> Self {
66        self.connection_target = Some(connection_target);
67        self
68    }
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
72pub struct ConformanceLayoutEdgePosition {
73    pub edge: EdgeId,
74    pub source: ConformanceEdgeEndpointPosition,
75    pub target: ConformanceEdgeEndpointPosition,
76}
77
78impl ConformanceLayoutEdgePosition {
79    pub fn new(
80        edge: EdgeId,
81        source: ConformanceEdgeEndpointPosition,
82        target: ConformanceEdgeEndpointPosition,
83    ) -> Self {
84        Self {
85            edge,
86            source,
87            target,
88        }
89    }
90
91    pub fn from_edge_position(edge: EdgeId, position: EdgePosition) -> Self {
92        Self {
93            edge,
94            source: ConformanceEdgeEndpointPosition::new(
95                position.source.point,
96                position.source.position,
97            ),
98            target: ConformanceEdgeEndpointPosition::new(
99                position.target.point,
100                position.target.position,
101            ),
102        }
103    }
104
105    pub(crate) fn matches_edge_position(self, position: EdgePosition) -> bool {
106        self.source.matches_endpoint(position.source)
107            && self.target.matches_endpoint(position.target)
108    }
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
112pub struct ConformanceEdgeEndpointPosition {
113    pub point: CanvasPoint,
114    pub position: HandlePosition,
115}
116
117impl ConformanceEdgeEndpointPosition {
118    pub fn new(point: CanvasPoint, position: HandlePosition) -> Self {
119        Self { point, position }
120    }
121
122    fn matches_endpoint(self, endpoint: crate::runtime::geometry::EdgeEndpointPosition) -> bool {
123        self.point == endpoint.point && self.position == endpoint.position
124    }
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
128pub struct ConformanceLayoutEdgeRouteFacts {
129    pub edge: EdgeId,
130    pub kind: ResolvedEdgeRouteKind,
131    pub interaction_width: f32,
132    pub selected: bool,
133}
134
135impl ConformanceLayoutEdgeRouteFacts {
136    pub fn new(
137        edge: EdgeId,
138        kind: ResolvedEdgeRouteKind,
139        interaction_width: f32,
140        selected: bool,
141    ) -> Self {
142        Self {
143            edge,
144            kind,
145            interaction_width,
146            selected,
147        }
148    }
149}
150
151#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
152pub struct ConformanceLayoutFactsConnectionTargetExpectation {
153    pub pointer: CanvasPoint,
154    pub from: ConnectionHandleRef,
155    pub expected: ResolvedConnectionTarget,
156}
157
158impl ConformanceLayoutFactsConnectionTargetExpectation {
159    pub fn new(
160        pointer: CanvasPoint,
161        from: ConnectionHandleRef,
162        expected: ResolvedConnectionTarget,
163    ) -> Self {
164        Self {
165            pointer,
166            from,
167            expected,
168        }
169    }
170}
171
172impl ConformanceAction {
173    pub fn report_node_measurement(measurement: NodeMeasurement) -> Self {
174        Self::ReportNodeMeasurement { measurement }
175    }
176
177    pub fn assert_layout_facts(
178        viewport_size: CanvasSize,
179        expected: ConformanceLayoutFactsExpectation,
180    ) -> Self {
181        Self::AssertLayoutFacts {
182            viewport_size,
183            expected,
184        }
185    }
186}