249 lines
7.5 KiB
Rust
249 lines
7.5 KiB
Rust
use oa_core::{projection::*, *};
|
|
|
|
#[test]
|
|
fn unplaced_work_parent_cannot_detach_a_leaf_from_its_visible_performer() {
|
|
let mut p = Project::empty();
|
|
let performer = p
|
|
.add_element(Kind::Entity, Layer::Oa, "Rescue team", None)
|
|
.unwrap();
|
|
let work = p
|
|
.add_element(Kind::Activity, Layer::Oa, "Respond", None)
|
|
.unwrap();
|
|
let leaf = p
|
|
.add_element(Kind::Activity, Layer::Oa, "Dispatch", Some(work))
|
|
.unwrap();
|
|
p.relate(RelationKind::Allocation, "Performs", performer, leaf);
|
|
let diagram = p.ensure_diagram(Layer::Oa);
|
|
p.diagrams.get_mut(&diagram).unwrap().projection = ProjectionKind::Allocation;
|
|
let owner = p.place(diagram, performer, Position { x: 0., y: 0. });
|
|
let child = p.place(diagram, leaf, Position { x: 40., y: 80. });
|
|
let view = project_view(&p, diagram);
|
|
assert_eq!(
|
|
view.nodes
|
|
.iter()
|
|
.find(|n| n.id == child)
|
|
.unwrap()
|
|
.visual_parent,
|
|
Some(owner)
|
|
);
|
|
let summary = p.place(diagram, work, Position { x: 24., y: 64. });
|
|
let view = project_view(&p, diagram);
|
|
assert!(
|
|
view.nodes
|
|
.iter()
|
|
.find(|n| n.id == summary)
|
|
.unwrap()
|
|
.allocation_summary
|
|
);
|
|
assert!(
|
|
!view
|
|
.nodes
|
|
.iter()
|
|
.find(|n| n.id == child)
|
|
.unwrap()
|
|
.allocation_summary
|
|
);
|
|
assert_eq!(
|
|
view.nodes
|
|
.iter()
|
|
.find(|n| n.id == child)
|
|
.unwrap()
|
|
.visual_parent,
|
|
Some(summary)
|
|
);
|
|
p.diagrams.get_mut(&diagram).unwrap().projection = ProjectionKind::FunctionalDataflow;
|
|
assert!(
|
|
project_view(&p, diagram)
|
|
.nodes
|
|
.iter()
|
|
.all(|n| !n.allocation_summary)
|
|
);
|
|
p.diagrams.get_mut(&diagram).unwrap().projection = ProjectionKind::Allocation;
|
|
p.diagrams.get_mut(&diagram).unwrap().nodes.remove(&summary);
|
|
let view = project_view(&p, diagram);
|
|
assert_eq!(
|
|
view.nodes
|
|
.iter()
|
|
.find(|n| n.id == child)
|
|
.unwrap()
|
|
.visual_parent,
|
|
Some(owner)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn architecture_is_nested_exchange_context_and_ports_attach_without_placements() {
|
|
let p = Project::demo();
|
|
let d = p
|
|
.diagrams
|
|
.values()
|
|
.find(|d| d.layer == Layer::Sa && d.projection == ProjectionKind::Allocation)
|
|
.unwrap();
|
|
let view = project_view(&p, d.id);
|
|
assert!(!view.nodes.is_empty());
|
|
assert!(view.nodes.iter().all(|n| {
|
|
let kind = p.elements[&n.element].kind();
|
|
kind.is_performer() || kind.is_work()
|
|
}));
|
|
for n in view
|
|
.nodes
|
|
.iter()
|
|
.filter(|n| p.elements[&n.element].kind().is_work())
|
|
{
|
|
let parent = view
|
|
.nodes
|
|
.iter()
|
|
.find(|parent| Some(parent.id) == n.visual_parent)
|
|
.unwrap();
|
|
assert!(p.elements[&parent.element].kind().is_performer());
|
|
assert!(n.position.x > parent.position.x && n.position.y > parent.position.y);
|
|
}
|
|
assert_eq!(view.ports.len(), 4);
|
|
assert!(
|
|
d.nodes
|
|
.values()
|
|
.all(|n| p.elements[&n.element].kind() != Kind::Port)
|
|
);
|
|
assert!(
|
|
view.edges
|
|
.iter()
|
|
.any(|e| p.relations[&e.id].kind() == RelationKind::BoundaryExchange)
|
|
);
|
|
for edge in &view.edges {
|
|
assert!(matches!(
|
|
p.relations[&edge.id].kind(),
|
|
RelationKind::FunctionalExchange | RelationKind::BoundaryExchange
|
|
));
|
|
for (id, owner) in [
|
|
(edge.source_port, edge.source),
|
|
(edge.target_port, edge.target),
|
|
] {
|
|
let port = view.ports.iter().find(|p| Some(p.element) == id).unwrap();
|
|
assert_eq!(port.owner, owner);
|
|
let node = view.nodes.iter().find(|n| n.id == owner).unwrap();
|
|
assert!(
|
|
port.position.x == node.position.x
|
|
|| port.position.x == node.position.x + node.size.width
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn port_identity_collapse_and_group_movement_do_not_invent_semantic_edges() {
|
|
let mut p = Project::demo();
|
|
let diagram = p
|
|
.diagrams
|
|
.values()
|
|
.find(|d| d.layer == Layer::Sa && d.projection == ProjectionKind::Allocation)
|
|
.unwrap()
|
|
.id;
|
|
let view = project_view(&p, diagram);
|
|
let system = view
|
|
.nodes
|
|
.iter()
|
|
.find(|n| p.elements[&n.element].kind() == Kind::System)
|
|
.unwrap();
|
|
let node = system.id;
|
|
let before = p.clone();
|
|
let moved = execute_batch(
|
|
&p,
|
|
&[Command::MoveNode {
|
|
diagram,
|
|
node,
|
|
position: Position {
|
|
x: p.diagrams[&diagram].nodes[&node].position.x + 140.,
|
|
y: p.diagrams[&diagram].nodes[&node].position.y + 80.,
|
|
},
|
|
with_descendants: true,
|
|
}],
|
|
)
|
|
.unwrap();
|
|
let after = project_view(&moved, diagram);
|
|
for port in view.ports.iter().filter(|port| {
|
|
port.owner == node
|
|
|| view
|
|
.nodes
|
|
.iter()
|
|
.any(|n| n.id == port.owner && n.visual_parent == Some(node))
|
|
}) {
|
|
let shifted = after
|
|
.ports
|
|
.iter()
|
|
.find(|p| p.element == port.element)
|
|
.unwrap();
|
|
assert_eq!(shifted.position.x, port.position.x + 140.);
|
|
assert_eq!(shifted.position.y, port.position.y + 80.);
|
|
}
|
|
assert_eq!(moved.elements, before.elements);
|
|
assert_eq!(moved.relations, before.relations);
|
|
p.diagrams
|
|
.get_mut(&diagram)
|
|
.unwrap()
|
|
.nodes
|
|
.get_mut(&node)
|
|
.unwrap()
|
|
.collapsed = true;
|
|
let collapsed = project_view(&p, diagram);
|
|
assert!(collapsed.ports.iter().all(|port| {
|
|
p.elements[&port.element].parent
|
|
!= Some(
|
|
view.nodes
|
|
.iter()
|
|
.find(|n| n.visual_parent == Some(node))
|
|
.unwrap()
|
|
.element,
|
|
)
|
|
}));
|
|
let exchange = collapsed
|
|
.edges
|
|
.iter()
|
|
.find(|e| p.relations[&e.id].kind() == RelationKind::FunctionalExchange)
|
|
.unwrap();
|
|
assert_eq!(exchange.target, node);
|
|
assert_eq!(
|
|
exchange.target_port, None,
|
|
"A collapsed link must not invent a system port"
|
|
);
|
|
assert_eq!(p.relations, before.relations);
|
|
}
|
|
|
|
#[test]
|
|
fn view_filtering_keeps_placements_and_source_and_separates_capability_content() {
|
|
let mut p = Project::demo();
|
|
let diagram = p
|
|
.diagrams
|
|
.values()
|
|
.find(|d| d.layer == Layer::Oa && d.projection == ProjectionKind::Allocation)
|
|
.unwrap()
|
|
.id;
|
|
let cap = p
|
|
.elements
|
|
.values()
|
|
.find(|e| e.kind() == Kind::Capability)
|
|
.unwrap()
|
|
.id;
|
|
p.place(diagram, cap, Position { x: 600., y: 0. });
|
|
let original = p.clone();
|
|
assert!(
|
|
!project_view(&p, diagram)
|
|
.nodes
|
|
.iter()
|
|
.any(|n| n.element == cap)
|
|
);
|
|
p.diagrams.get_mut(&diagram).unwrap().projection = ProjectionKind::Capabilities;
|
|
let view = project_view(&p, diagram);
|
|
assert!(view.nodes.iter().any(|n| n.element == cap));
|
|
assert!(
|
|
!view
|
|
.nodes
|
|
.iter()
|
|
.any(|n| p.elements[&n.element].kind().is_work())
|
|
);
|
|
assert_eq!(
|
|
p.diagrams[&diagram].nodes,
|
|
original.diagrams[&diagram].nodes
|
|
);
|
|
assert_eq!(language::parse(&language::format(&p)).unwrap(), p);
|
|
}
|