jellyflow_runtime/runtime/conformance/scenario/action/
layout_facts.rs1use 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}