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};
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 = "Option::is_none")]
27    pub connection_target: Option<ConformanceLayoutFactsConnectionTargetExpectation>,
28}
29
30impl ConformanceLayoutFactsExpectation {
31    pub fn new(
32        visible_node_ids: impl IntoIterator<Item = NodeId>,
33        visible_edge_ids: impl IntoIterator<Item = EdgeId>,
34    ) -> Self {
35        Self {
36            visible_node_ids: visible_node_ids.into_iter().collect(),
37            visible_edge_ids: visible_edge_ids.into_iter().collect(),
38            edge_positions: Vec::new(),
39            connection_target: None,
40        }
41    }
42
43    pub fn with_edge_positions(
44        mut self,
45        edge_positions: impl IntoIterator<Item = ConformanceLayoutEdgePosition>,
46    ) -> Self {
47        self.edge_positions = edge_positions.into_iter().collect();
48        self
49    }
50
51    pub fn with_connection_target(
52        mut self,
53        connection_target: ConformanceLayoutFactsConnectionTargetExpectation,
54    ) -> Self {
55        self.connection_target = Some(connection_target);
56        self
57    }
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
61pub struct ConformanceLayoutEdgePosition {
62    pub edge: EdgeId,
63    pub source: ConformanceEdgeEndpointPosition,
64    pub target: ConformanceEdgeEndpointPosition,
65}
66
67impl ConformanceLayoutEdgePosition {
68    pub fn new(
69        edge: EdgeId,
70        source: ConformanceEdgeEndpointPosition,
71        target: ConformanceEdgeEndpointPosition,
72    ) -> Self {
73        Self {
74            edge,
75            source,
76            target,
77        }
78    }
79
80    pub fn from_edge_position(edge: EdgeId, position: EdgePosition) -> Self {
81        Self {
82            edge,
83            source: ConformanceEdgeEndpointPosition::new(
84                position.source.point,
85                position.source.position,
86            ),
87            target: ConformanceEdgeEndpointPosition::new(
88                position.target.point,
89                position.target.position,
90            ),
91        }
92    }
93
94    pub(crate) fn matches_edge_position(self, position: EdgePosition) -> bool {
95        self.source.matches_endpoint(position.source)
96            && self.target.matches_endpoint(position.target)
97    }
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
101pub struct ConformanceEdgeEndpointPosition {
102    pub point: CanvasPoint,
103    pub position: HandlePosition,
104}
105
106impl ConformanceEdgeEndpointPosition {
107    pub fn new(point: CanvasPoint, position: HandlePosition) -> Self {
108        Self { point, position }
109    }
110
111    fn matches_endpoint(self, endpoint: crate::runtime::geometry::EdgeEndpointPosition) -> bool {
112        self.point == endpoint.point && self.position == endpoint.position
113    }
114}
115
116#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
117pub struct ConformanceLayoutFactsConnectionTargetExpectation {
118    pub pointer: CanvasPoint,
119    pub from: ConnectionHandleRef,
120    pub expected: ResolvedConnectionTarget,
121}
122
123impl ConformanceLayoutFactsConnectionTargetExpectation {
124    pub fn new(
125        pointer: CanvasPoint,
126        from: ConnectionHandleRef,
127        expected: ResolvedConnectionTarget,
128    ) -> Self {
129        Self {
130            pointer,
131            from,
132            expected,
133        }
134    }
135}
136
137impl ConformanceAction {
138    pub fn report_node_measurement(measurement: NodeMeasurement) -> Self {
139        Self::ReportNodeMeasurement { measurement }
140    }
141
142    pub fn assert_layout_facts(
143        viewport_size: CanvasSize,
144        expected: ConformanceLayoutFactsExpectation,
145    ) -> Self {
146        Self::AssertLayoutFacts {
147            viewport_size,
148            expected,
149        }
150    }
151}