use serde::{Deserialize, Serialize};
use crate::io::NodeGraphKeyCode;
use crate::runtime::connection::{CONNECT_EDGE_TRANSACTION_LABEL, ConnectEdgeRequest};
use crate::runtime::delete::DELETE_SELECTION_TRANSACTION_LABEL;
use crate::runtime::drag::NODE_DRAG_TRANSACTION_LABEL;
use crate::runtime::drag::PointerGestureClaim;
use crate::runtime::events::{
ConnectEnd, ConnectEndOutcome, ConnectStart, NodeDragEnd, NodeDragEndOutcome, NodeDragStart,
NodeDragUpdate, NodeGraphGestureEvent, NodeResizeEnd, NodeResizeEndOutcome, NodeResizeStart,
NodeResizeUpdate, ViewportMove, ViewportMoveEnd, ViewportMoveEndOutcome, ViewportMoveKind,
ViewportMoveStart,
};
use crate::runtime::measurement::NodeMeasurement;
use crate::runtime::rendering::RenderingQueryResult;
use crate::runtime::resize::NODE_RESIZE_TRANSACTION_LABEL;
use crate::runtime::resize::NodePointerResizeRequest;
use crate::runtime::selection::{NodePointerDownInput, SelectionBoxInput};
use crate::runtime::viewport::{ViewportDragPanInput, ViewportGestureContext, ViewportTransform};
use crate::runtime::xyflow::callbacks::{ConnectionChange, EdgeConnection};
use jellyflow_core::core::{CanvasPoint, CanvasSize, EdgeId, GroupId, NodeId};
use keyboard_types::Code as KeyCode;
use super::action::{ConformanceAction, ConformanceLayoutFactsExpectation};
use super::suite::ConformanceScenario;
use super::trace::{ConformanceCallbackEvent, ConformanceTraceEvent, ConformanceViewChange};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", content = "data", rename_all = "snake_case")]
pub enum ConformanceBehavior {
NodeDragSession(ConformanceNodeDragSessionContract),
ConnectEdgeSession(ConformanceConnectEdgeSessionContract),
NodeResizeSession(ConformanceNodeResizeSessionContract),
SelectionBox(ConformanceSelectionBoxContract),
DeleteSelection(ConformanceDeleteSelectionContract),
DeleteSelectionDuringNodeDrag(ConformanceDeleteSelectionDuringNodeDragContract),
NodePointerDownSelection(ConformanceNodePointerDownSelectionContract),
ViewportDragPanSession(ConformanceViewportDragPanSessionContract),
RenderingQuery(ConformanceRenderingQueryContract),
LayoutFacts(ConformanceLayoutFactsContract),
}
impl ConformanceBehavior {
pub fn node_drag_session(contract: ConformanceNodeDragSessionContract) -> Self {
Self::NodeDragSession(contract)
}
pub fn connect_edge_session(contract: ConformanceConnectEdgeSessionContract) -> Self {
Self::ConnectEdgeSession(contract)
}
pub fn node_resize_session(contract: ConformanceNodeResizeSessionContract) -> Self {
Self::NodeResizeSession(contract)
}
pub fn selection_box(contract: ConformanceSelectionBoxContract) -> Self {
Self::SelectionBox(contract)
}
pub fn delete_selection(contract: ConformanceDeleteSelectionContract) -> Self {
Self::DeleteSelection(contract)
}
pub fn delete_selection_during_node_drag(
contract: ConformanceDeleteSelectionDuringNodeDragContract,
) -> Self {
Self::DeleteSelectionDuringNodeDrag(contract)
}
pub fn node_pointer_down_selection(
contract: ConformanceNodePointerDownSelectionContract,
) -> Self {
Self::NodePointerDownSelection(contract)
}
pub fn viewport_drag_pan_session(contract: ConformanceViewportDragPanSessionContract) -> Self {
Self::ViewportDragPanSession(contract)
}
pub fn rendering_query(contract: ConformanceRenderingQueryContract) -> Self {
Self::RenderingQuery(contract)
}
pub fn layout_facts(contract: ConformanceLayoutFactsContract) -> Self {
Self::LayoutFacts(contract)
}
pub(crate) fn actions(&self) -> Vec<ConformanceAction> {
match self {
Self::NodeDragSession(contract) => vec![contract.action()],
Self::ConnectEdgeSession(contract) => vec![contract.action()],
Self::NodeResizeSession(contract) => vec![contract.action()],
Self::SelectionBox(contract) => vec![contract.action()],
Self::DeleteSelection(contract) => vec![contract.action()],
Self::DeleteSelectionDuringNodeDrag(contract) => contract.actions(),
Self::NodePointerDownSelection(contract) => vec![contract.action()],
Self::ViewportDragPanSession(contract) => vec![contract.action()],
Self::RenderingQuery(contract) => vec![contract.action()],
Self::LayoutFacts(contract) => contract.actions(),
}
}
pub(crate) fn expected_trace(&self) -> Vec<ConformanceTraceEvent> {
match self {
Self::NodeDragSession(contract) => contract.expected_trace(),
Self::ConnectEdgeSession(contract) => contract.expected_trace(),
Self::NodeResizeSession(contract) => contract.expected_trace(),
Self::SelectionBox(contract) => contract.expected_trace(),
Self::DeleteSelection(contract) => contract.expected_trace(),
Self::DeleteSelectionDuringNodeDrag(contract) => contract.expected_trace(),
Self::NodePointerDownSelection(contract) => contract.expected_trace(),
Self::ViewportDragPanSession(contract) => contract.expected_trace(),
Self::RenderingQuery(contract) => contract.expected_trace(),
Self::LayoutFacts(contract) => contract.expected_trace(),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConformanceNodeDragSessionContract {
pub primary: NodeId,
pub nodes: Vec<NodeId>,
pub start: CanvasPoint,
pub to: CanvasPoint,
pub commit_op_kinds: Vec<String>,
}
impl ConformanceNodeDragSessionContract {
pub fn new(primary: NodeId, start: CanvasPoint, to: CanvasPoint) -> Self {
Self {
primary,
nodes: vec![primary],
start,
to,
commit_op_kinds: vec!["set_node_pos".to_owned()],
}
}
pub fn with_nodes(mut self, nodes: impl IntoIterator<Item = NodeId>) -> Self {
self.nodes = nodes.into_iter().collect();
self
}
pub fn with_commit_op_kinds(
mut self,
op_kinds: impl IntoIterator<Item = impl Into<String>>,
) -> Self {
self.commit_op_kinds = op_kinds.into_iter().map(Into::into).collect();
self
}
fn action(&self) -> ConformanceAction {
ConformanceAction::apply_node_drag_session(self.primary, self.start, self.to)
}
fn expected_trace(&self) -> Vec<ConformanceTraceEvent> {
let start = NodeDragStart {
primary: self.primary,
nodes: self.nodes.clone(),
pointer: self.start,
};
let update = NodeDragUpdate {
primary: self.primary,
nodes: self.nodes.clone(),
pointer: self.to,
};
let end = NodeDragEnd {
primary: self.primary,
nodes: self.nodes.clone(),
pointer: self.to,
outcome: NodeDragEndOutcome::Committed,
};
vec![
ConformanceTraceEvent::gesture(NodeGraphGestureEvent::NodeDragStart(start.clone())),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::NodeDragStart(start)),
ConformanceTraceEvent::graph_commit(
Some(NODE_DRAG_TRANSACTION_LABEL),
self.commit_op_kinds.iter().map(String::as_str),
),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::GraphCommit {
label: Some(NODE_DRAG_TRANSACTION_LABEL.to_owned()),
}),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::NodeEdgeChanges {
nodes: self.nodes.len(),
edges: 0,
}),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::NodesChange {
count: self.nodes.len(),
}),
ConformanceTraceEvent::gesture(NodeGraphGestureEvent::NodeDragUpdate(update.clone())),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::NodeDrag(update)),
ConformanceTraceEvent::gesture(NodeGraphGestureEvent::NodeDragEnd(end.clone())),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::NodeDragEnd(end)),
]
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConformanceConnectEdgeSessionContract {
pub start: ConnectStart,
pub request: ConnectEdgeRequest,
pub connection: EdgeConnection,
}
impl ConformanceConnectEdgeSessionContract {
pub fn new(
start: ConnectStart,
request: ConnectEdgeRequest,
connection: EdgeConnection,
) -> Self {
Self {
start,
request,
connection,
}
}
fn action(&self) -> ConformanceAction {
ConformanceAction::apply_connect_edge_session(self.start.clone(), self.request)
}
fn expected_trace(&self) -> Vec<ConformanceTraceEvent> {
let end = ConnectEnd {
kind: self.start.kind.clone(),
mode: self.start.mode,
target: Some(self.request.to),
outcome: ConnectEndOutcome::Committed,
};
vec![
ConformanceTraceEvent::gesture(NodeGraphGestureEvent::ConnectStart(self.start.clone())),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::ConnectStart(
self.start.clone(),
)),
ConformanceTraceEvent::graph_commit(Some(CONNECT_EDGE_TRANSACTION_LABEL), ["add_edge"]),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::GraphCommit {
label: Some(CONNECT_EDGE_TRANSACTION_LABEL.to_owned()),
}),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::NodeEdgeChanges {
nodes: 0,
edges: 1,
}),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::EdgesChange { count: 1 }),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::ConnectionChange(
ConnectionChange::Connected(self.connection),
)),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::Connect(self.connection)),
ConformanceTraceEvent::gesture(NodeGraphGestureEvent::ConnectEnd(end.clone())),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::ConnectEnd(end)),
]
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConformanceNodeResizeSessionContract {
pub request: NodePointerResizeRequest,
pub update: NodeResizeUpdate,
pub commit_op_kinds: Vec<String>,
}
impl ConformanceNodeResizeSessionContract {
pub fn new(request: NodePointerResizeRequest, update: NodeResizeUpdate) -> Self {
Self {
request,
update,
commit_op_kinds: vec!["set_node_size".to_owned()],
}
}
pub fn with_commit_op_kinds(
mut self,
op_kinds: impl IntoIterator<Item = impl Into<String>>,
) -> Self {
self.commit_op_kinds = op_kinds.into_iter().map(Into::into).collect();
self
}
fn action(&self) -> ConformanceAction {
ConformanceAction::apply_node_pointer_resize_session(self.request)
}
fn expected_trace(&self) -> Vec<ConformanceTraceEvent> {
let start = NodeResizeStart {
node: self.request.node,
direction: self.request.direction,
pointer: self.request.start,
};
let end = NodeResizeEnd {
node: self.request.node,
direction: self.request.direction,
pointer: self.request.current,
outcome: NodeResizeEndOutcome::Committed,
};
vec![
ConformanceTraceEvent::gesture(NodeGraphGestureEvent::NodeResizeStart(start.clone())),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::NodeResizeStart(start)),
ConformanceTraceEvent::graph_commit(
Some(NODE_RESIZE_TRANSACTION_LABEL),
self.commit_op_kinds.iter().map(String::as_str),
),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::GraphCommit {
label: Some(NODE_RESIZE_TRANSACTION_LABEL.to_owned()),
}),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::NodeEdgeChanges {
nodes: 1,
edges: 0,
}),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::NodesChange { count: 1 }),
ConformanceTraceEvent::gesture(NodeGraphGestureEvent::NodeResizeUpdate(
self.update.clone(),
)),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::NodeResize(
self.update.clone(),
)),
ConformanceTraceEvent::gesture(NodeGraphGestureEvent::NodeResizeEnd(end.clone())),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::NodeResizeEnd(end)),
]
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConformanceSelectionBoxContract {
pub input: SelectionBoxInput,
pub nodes: Vec<NodeId>,
pub edges: Vec<EdgeId>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub groups: Vec<GroupId>,
}
impl ConformanceSelectionBoxContract {
pub fn new(
input: SelectionBoxInput,
nodes: impl IntoIterator<Item = NodeId>,
edges: impl IntoIterator<Item = EdgeId>,
) -> Self {
Self {
input,
nodes: nodes.into_iter().collect(),
edges: edges.into_iter().collect(),
groups: Vec::new(),
}
}
pub fn with_groups(mut self, groups: impl IntoIterator<Item = GroupId>) -> Self {
self.groups = groups.into_iter().collect();
self
}
fn action(&self) -> ConformanceAction {
ConformanceAction::apply_selection_box(self.input)
}
fn expected_trace(&self) -> Vec<ConformanceTraceEvent> {
selection_trace_events(&self.nodes, &self.edges, &self.groups)
}
}
fn selection_trace_events(
nodes: &[NodeId],
edges: &[EdgeId],
groups: &[GroupId],
) -> Vec<ConformanceTraceEvent> {
vec![
ConformanceTraceEvent::selection(nodes.to_vec(), edges.to_vec(), groups.to_vec()),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::ViewChange {
changes: vec![ConformanceViewChange::Selection {
nodes: nodes.to_vec(),
edges: edges.to_vec(),
groups: groups.to_vec(),
}],
}),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::SelectionChange {
nodes: nodes.to_vec(),
edges: edges.to_vec(),
groups: groups.to_vec(),
}),
]
}
fn usize_is_zero(value: &usize) -> bool {
*value == 0
}
fn default_delete_commit_op_kinds(nodes: usize, edges: usize) -> Vec<String> {
if nodes > 0 {
return vec!["remove_node".to_owned()];
}
if edges > 0 {
return vec!["remove_edge".to_owned()];
}
Vec::new()
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConformanceDeleteSelectionContract {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub key: Option<NodeGraphKeyCode>,
pub nodes: usize,
pub edges: usize,
#[serde(default, skip_serializing_if = "usize_is_zero")]
pub groups: usize,
#[serde(default, skip_serializing_if = "usize_is_zero")]
pub sticky_notes: usize,
pub commit_op_kinds: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub disconnected: Vec<EdgeConnection>,
}
impl ConformanceDeleteSelectionContract {
pub fn new(nodes: usize, edges: usize) -> Self {
Self {
key: None,
nodes,
edges,
groups: 0,
sticky_notes: 0,
commit_op_kinds: default_delete_commit_op_kinds(nodes, edges),
disconnected: Vec::new(),
}
}
pub fn for_key(mut self, key: KeyCode) -> Self {
self.key = Some(NodeGraphKeyCode(key));
self
}
pub fn with_commit_op_kinds(
mut self,
op_kinds: impl IntoIterator<Item = impl Into<String>>,
) -> Self {
self.commit_op_kinds = op_kinds.into_iter().map(Into::into).collect();
self
}
pub fn with_deleted_groups(mut self, groups: usize) -> Self {
self.groups = groups;
self
}
pub fn with_deleted_sticky_notes(mut self, sticky_notes: usize) -> Self {
self.sticky_notes = sticky_notes;
self
}
pub fn with_disconnected(
mut self,
disconnected: impl IntoIterator<Item = EdgeConnection>,
) -> Self {
self.disconnected = disconnected.into_iter().collect();
self
}
fn action(&self) -> ConformanceAction {
match self.key {
Some(key) => ConformanceAction::apply_delete_selection_for_key(key.0),
None => ConformanceAction::apply_delete_selection(),
}
}
fn expected_trace(&self) -> Vec<ConformanceTraceEvent> {
let mut trace = vec![
ConformanceTraceEvent::graph_commit(
Some(DELETE_SELECTION_TRANSACTION_LABEL),
self.commit_op_kinds.iter().map(String::as_str),
),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::GraphCommit {
label: Some(DELETE_SELECTION_TRANSACTION_LABEL.to_owned()),
}),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::NodeEdgeChanges {
nodes: self.nodes,
edges: self.edges,
}),
];
if self.nodes > 0 {
trace.push(ConformanceTraceEvent::callback(
ConformanceCallbackEvent::NodesChange { count: self.nodes },
));
}
if self.edges > 0 {
trace.push(ConformanceTraceEvent::callback(
ConformanceCallbackEvent::EdgesChange { count: self.edges },
));
}
for connection in self.disconnected.iter().copied() {
trace.push(ConformanceTraceEvent::callback(
ConformanceCallbackEvent::ConnectionChange(ConnectionChange::Disconnected(
connection,
)),
));
trace.push(ConformanceTraceEvent::callback(
ConformanceCallbackEvent::Disconnect(connection),
));
}
if self.nodes > 0 {
trace.push(ConformanceTraceEvent::callback(
ConformanceCallbackEvent::NodesDelete { count: self.nodes },
));
}
if self.edges > 0 {
trace.push(ConformanceTraceEvent::callback(
ConformanceCallbackEvent::EdgesDelete { count: self.edges },
));
}
if self.groups > 0 {
trace.push(ConformanceTraceEvent::callback(
ConformanceCallbackEvent::GroupsDelete { count: self.groups },
));
}
if self.sticky_notes > 0 {
trace.push(ConformanceTraceEvent::callback(
ConformanceCallbackEvent::StickyNotesDelete {
count: self.sticky_notes,
},
));
}
trace.push(ConformanceTraceEvent::callback(
ConformanceCallbackEvent::Delete {
nodes: self.nodes,
edges: self.edges,
groups: self.groups,
sticky_notes: self.sticky_notes,
},
));
trace.extend(selection_trace_events(&[], &[], &[]));
trace
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConformanceDeleteSelectionDuringNodeDragContract {
pub start: NodeDragStart,
pub end: NodeDragEnd,
pub delete: ConformanceDeleteSelectionContract,
}
impl ConformanceDeleteSelectionDuringNodeDragContract {
pub fn new(
start: NodeDragStart,
end: NodeDragEnd,
delete: ConformanceDeleteSelectionContract,
) -> Self {
Self { start, end, delete }
}
fn actions(&self) -> Vec<ConformanceAction> {
vec![
ConformanceAction::emit_gesture(NodeGraphGestureEvent::NodeDragStart(
self.start.clone(),
)),
self.delete.action(),
ConformanceAction::emit_gesture(NodeGraphGestureEvent::NodeDragEnd(self.end.clone())),
]
}
fn expected_trace(&self) -> Vec<ConformanceTraceEvent> {
let mut trace = vec![
ConformanceTraceEvent::gesture(NodeGraphGestureEvent::NodeDragStart(
self.start.clone(),
)),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::NodeDragStart(
self.start.clone(),
)),
];
trace.extend(self.delete.expected_trace());
trace.extend([
ConformanceTraceEvent::gesture(NodeGraphGestureEvent::NodeDragEnd(self.end.clone())),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::NodeDragEnd(
self.end.clone(),
)),
]);
trace
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConformanceNodePointerDownSelectionContract {
pub input: NodePointerDownInput,
pub expected_claim: PointerGestureClaim,
pub nodes: Vec<NodeId>,
pub edges: Vec<EdgeId>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub groups: Vec<GroupId>,
}
impl ConformanceNodePointerDownSelectionContract {
pub fn new(
input: NodePointerDownInput,
expected_claim: PointerGestureClaim,
nodes: impl IntoIterator<Item = NodeId>,
edges: impl IntoIterator<Item = EdgeId>,
) -> Self {
Self {
input,
expected_claim,
nodes: nodes.into_iter().collect(),
edges: edges.into_iter().collect(),
groups: Vec::new(),
}
}
pub fn with_groups(mut self, groups: impl IntoIterator<Item = GroupId>) -> Self {
self.groups = groups.into_iter().collect();
self
}
fn action(&self) -> ConformanceAction {
ConformanceAction::apply_node_pointer_down_expect_claim(
self.input.node,
self.input.multi_selection_active,
self.input.screen_delta,
self.expected_claim,
)
}
fn expected_trace(&self) -> Vec<ConformanceTraceEvent> {
selection_trace_events(&self.nodes, &self.edges, &self.groups)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct ConformanceViewportDragPanSessionContract {
pub context: ViewportGestureContext,
pub input: ViewportDragPanInput,
pub start: ViewportTransform,
pub end: ViewportTransform,
}
impl ConformanceViewportDragPanSessionContract {
pub fn new(
context: ViewportGestureContext,
input: ViewportDragPanInput,
start: ViewportTransform,
end: ViewportTransform,
) -> Self {
Self {
context,
input,
start,
end,
}
}
fn action(&self) -> ConformanceAction {
ConformanceAction::apply_viewport_drag_pan_session(self.context, self.input)
}
fn expected_trace(&self) -> Vec<ConformanceTraceEvent> {
let start = ViewportMoveStart {
kind: ViewportMoveKind::PanDrag,
pan: self.start.pan,
zoom: self.start.zoom,
};
let update = ViewportMove {
kind: ViewportMoveKind::PanDrag,
pan: self.end.pan,
zoom: self.end.zoom,
};
let end = ViewportMoveEnd {
kind: ViewportMoveKind::PanDrag,
pan: self.end.pan,
zoom: self.end.zoom,
outcome: ViewportMoveEndOutcome::Ended,
};
vec![
ConformanceTraceEvent::gesture(NodeGraphGestureEvent::ViewportMoveStart(start)),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::ViewportMoveStart(start)),
ConformanceTraceEvent::viewport(self.end.pan, self.end.zoom),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::ViewChange {
changes: vec![ConformanceViewChange::Viewport {
pan: self.end.pan,
zoom: self.end.zoom,
}],
}),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::ViewportChange {
pan: self.end.pan,
zoom: self.end.zoom,
}),
ConformanceTraceEvent::gesture(NodeGraphGestureEvent::ViewportMove(update)),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::ViewportMove(update)),
ConformanceTraceEvent::gesture(NodeGraphGestureEvent::ViewportMoveEnd(end)),
ConformanceTraceEvent::callback(ConformanceCallbackEvent::ViewportMoveEnd(end)),
]
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConformanceRenderingQueryContract {
pub viewport_size: CanvasSize,
pub expected: RenderingQueryResult,
}
impl ConformanceRenderingQueryContract {
pub fn new(viewport_size: CanvasSize, expected: RenderingQueryResult) -> Self {
Self {
viewport_size,
expected,
}
}
fn action(&self) -> ConformanceAction {
ConformanceAction::assert_rendering_query(self.viewport_size, self.expected.clone())
}
fn expected_trace(&self) -> Vec<ConformanceTraceEvent> {
Vec::new()
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConformanceLayoutFactsContract {
pub measurements: Vec<NodeMeasurement>,
pub viewport_size: CanvasSize,
pub expected: ConformanceLayoutFactsExpectation,
}
impl ConformanceLayoutFactsContract {
pub fn new(
measurements: impl IntoIterator<Item = NodeMeasurement>,
viewport_size: CanvasSize,
expected: ConformanceLayoutFactsExpectation,
) -> Self {
Self {
measurements: measurements.into_iter().collect(),
viewport_size,
expected,
}
}
fn actions(&self) -> Vec<ConformanceAction> {
self.measurements
.iter()
.cloned()
.map(ConformanceAction::report_node_measurement)
.chain([ConformanceAction::assert_layout_facts(
self.viewport_size,
self.expected.clone(),
)])
.collect()
}
fn expected_trace(&self) -> Vec<ConformanceTraceEvent> {
Vec::new()
}
}
impl ConformanceScenario {
pub fn with_node_drag_session_contract(
self,
contract: ConformanceNodeDragSessionContract,
) -> Self {
self.with_behavior(ConformanceBehavior::node_drag_session(contract))
}
pub fn with_connect_edge_session_contract(
self,
contract: ConformanceConnectEdgeSessionContract,
) -> Self {
self.with_behavior(ConformanceBehavior::connect_edge_session(contract))
}
pub fn with_node_resize_session_contract(
self,
contract: ConformanceNodeResizeSessionContract,
) -> Self {
self.with_behavior(ConformanceBehavior::node_resize_session(contract))
}
pub fn with_selection_box_contract(self, contract: ConformanceSelectionBoxContract) -> Self {
self.with_behavior(ConformanceBehavior::selection_box(contract))
}
pub fn with_delete_selection_contract(
self,
contract: ConformanceDeleteSelectionContract,
) -> Self {
self.with_behavior(ConformanceBehavior::delete_selection(contract))
}
pub fn with_delete_selection_during_node_drag_contract(
self,
contract: ConformanceDeleteSelectionDuringNodeDragContract,
) -> Self {
self.with_behavior(ConformanceBehavior::delete_selection_during_node_drag(
contract,
))
}
pub fn with_node_pointer_down_selection_contract(
self,
contract: ConformanceNodePointerDownSelectionContract,
) -> Self {
self.with_behavior(ConformanceBehavior::node_pointer_down_selection(contract))
}
pub fn with_viewport_drag_pan_session_contract(
self,
contract: ConformanceViewportDragPanSessionContract,
) -> Self {
self.with_behavior(ConformanceBehavior::viewport_drag_pan_session(contract))
}
pub fn with_rendering_query_contract(
self,
contract: ConformanceRenderingQueryContract,
) -> Self {
self.with_behavior(ConformanceBehavior::rendering_query(contract))
}
pub fn with_layout_facts_contract(self, contract: ConformanceLayoutFactsContract) -> Self {
self.with_behavior(ConformanceBehavior::layout_facts(contract))
}
}