185 lines
6.9 KiB
Rust
185 lines
6.9 KiB
Rust
//! Accepted semantic review keeps selection, layer and visible diagram coherent.
|
|
use super::*;
|
|
use crate::{
|
|
semantic_review::{RowEvent, State},
|
|
workflow::{Event, Workflow},
|
|
};
|
|
|
|
fn send(app: &mut App, message: Message) {
|
|
let _ = app.update(message);
|
|
}
|
|
fn state(app: &App) -> &State {
|
|
let Some(Workflow::Semantic(state)) = &app.workflow else {
|
|
panic!("{}", app.status)
|
|
};
|
|
state
|
|
}
|
|
fn row_event(app: &mut App, event: RowEvent) {
|
|
let event = state(app).address_event(event);
|
|
send(app, Message::Workflow(Event::Semantic(event)));
|
|
}
|
|
fn fixture(reverse: bool, destination_view: bool) -> (App, Id, Id, Id, Option<Id>) {
|
|
let mut p = Project::empty();
|
|
let oa = p
|
|
.add_element(Kind::Activity, Layer::Oa, "Confirm stable pressure", None)
|
|
.unwrap();
|
|
let sa = p
|
|
.add_element(Kind::Function, Layer::Sa, "Confirm safe pressure", None)
|
|
.unwrap();
|
|
let trace = Id::new_v4();
|
|
p.traces.insert(
|
|
trace,
|
|
Trace {
|
|
id: trace,
|
|
alias: "confirm_trace".into(),
|
|
name: "Confirmation refinement".into(),
|
|
description: String::new(),
|
|
oa,
|
|
sa,
|
|
kind: TraceKind::Refinement,
|
|
baseline: None,
|
|
},
|
|
);
|
|
let (source, target, source_layer, target_layer) = if reverse {
|
|
(sa, oa, Layer::Sa, Layer::Oa)
|
|
} else {
|
|
(oa, sa, Layer::Oa, Layer::Sa)
|
|
};
|
|
let from = p.ensure_diagram(source_layer);
|
|
p.place(from, source, Position { x: 91., y: 143. });
|
|
let to = destination_view.then(|| {
|
|
let view = p.ensure_diagram(target_layer);
|
|
p.place(view, target, Position { x: 487., y: 213. });
|
|
view
|
|
});
|
|
let mut app = App::with_project(p);
|
|
app.page = Page::Diagram;
|
|
app.layer = source_layer;
|
|
app.active_diagram = Some(from);
|
|
app.selected = source;
|
|
app.refresh_draft();
|
|
(app, source, target, from, to)
|
|
}
|
|
fn name_take(app: &mut App, source: Id) -> Project {
|
|
send(app, Message::StartSemanticReview(source));
|
|
let facet = FacetSelector::Header(HeaderFacet::Name);
|
|
row_event(app, RowEvent::Select(facet.clone()));
|
|
row_event(
|
|
app,
|
|
RowEvent::Decide(facet, Some(SemanticDecision::TakeSource)),
|
|
);
|
|
assert!(state(app).can_apply(), "{:?}", state(app).error);
|
|
let Some(Workflow::Semantic(state)) = &mut app.workflow else {
|
|
unreachable!()
|
|
};
|
|
let command = state.command(app.document.project()).unwrap();
|
|
execute_batch(app.document.project(), &[command]).unwrap()
|
|
}
|
|
|
|
#[test]
|
|
fn semantic_name_take_selects_the_counterpart_view_in_both_directions_with_one_exact_history_entry()
|
|
{
|
|
for reverse in [false, true] {
|
|
let (mut app, source, target, from, to) = fixture(reverse, true);
|
|
app.search = format!("@{}", app.project().elements[&source].alias);
|
|
let query = app.search.clone();
|
|
let before = app.document.snapshot();
|
|
let expected = name_take(&mut app, source);
|
|
app.selected_node = app.project().diagrams[&from].nodes.keys().next().copied();
|
|
send(&mut app, Message::Workflow(Event::Apply));
|
|
assert_eq!(app.project(), &expected);
|
|
assert_eq!(app.project().diagrams, before.decoded.project.diagrams);
|
|
assert_eq!(app.selected, target);
|
|
assert_eq!(app.layer, app.project().elements[&target].layer());
|
|
assert_eq!(app.active_diagram, to);
|
|
assert_eq!(
|
|
app.project().diagrams[&app.active_diagram.unwrap()].layer,
|
|
app.layer
|
|
);
|
|
// refresh_draft deliberately selects the target's visible placement.
|
|
// The invariant is that the old-layer placement cannot survive.
|
|
let placement = app.selected_node.expect("visible counterpart placement");
|
|
assert_eq!(
|
|
app.project().diagrams[&to.unwrap()].nodes[&placement].element,
|
|
target
|
|
);
|
|
assert!(!app.project().diagrams[&from].nodes.contains_key(&placement));
|
|
assert_eq!(app.page, Page::Diagram);
|
|
assert_eq!(app.search, query);
|
|
assert!(app.workflow.is_none());
|
|
assert_eq!(app.document.revision(), 1);
|
|
let accepted = app.document.snapshot();
|
|
assert_eq!(
|
|
source_project::compile_bundle(&accepted.bundle, LIMITS)
|
|
.unwrap()
|
|
.decoded
|
|
.project,
|
|
expected
|
|
);
|
|
send(&mut app, Message::Undo);
|
|
assert_eq!(app.project(), &before.decoded.project);
|
|
assert_eq!(app.document.bundle(), &before.bundle);
|
|
assert!(!app.document.can_undo());
|
|
send(&mut app, Message::Redo);
|
|
assert_eq!(app.project(), &accepted.decoded.project);
|
|
assert_eq!(app.document.bundle(), &accepted.bundle);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn semantic_review_without_a_destination_view_clears_the_old_layer_canvas_without_creating_a_view()
|
|
{
|
|
let (mut app, source, target, _, _) = fixture(false, false);
|
|
let expected = name_take(&mut app, source);
|
|
send(&mut app, Message::Workflow(Event::Apply));
|
|
assert_eq!(app.project(), &expected);
|
|
assert_eq!(app.selected, target);
|
|
assert_eq!(app.layer, Layer::Sa);
|
|
assert_eq!(app.active_diagram, None);
|
|
assert_eq!(app.project().diagrams.len(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn review_already_showing_the_target_keeps_its_camera_and_query() {
|
|
let (mut app, source, target, _, to) = fixture(false, true);
|
|
app.layer = Layer::Sa;
|
|
app.active_diagram = to;
|
|
app.selected = target;
|
|
app.zoom = 1.31;
|
|
app.pan = iced::Vector::new(-219., 88.);
|
|
app.search = "pressure".into();
|
|
app.refresh_draft();
|
|
let expected = name_take(&mut app, source);
|
|
send(&mut app, Message::Workflow(Event::Apply));
|
|
assert_eq!(app.project(), &expected);
|
|
assert_eq!(app.active_diagram, to);
|
|
assert_eq!(app.zoom, 1.31);
|
|
assert_eq!(app.pan, iced::Vector::new(-219., 88.));
|
|
assert_eq!(app.search, "pressure");
|
|
}
|
|
|
|
#[test]
|
|
fn rejected_semantic_source_writeback_retains_review_camera_and_original_navigation() {
|
|
let (mut app, source, _, from, _) = fixture(false, true);
|
|
let bundle = app.document.bundle().clone();
|
|
let mut limits = source_project::ProjectLimits::default();
|
|
limits.model.max_source_bytes = bundle.files.values().map(String::len).sum::<usize>() + 1;
|
|
app.document = Document::from_bundle(bundle, limits).unwrap();
|
|
app.zoom = 1.21;
|
|
app.pan = iced::Vector::new(72., -44.);
|
|
app.search = "confirmation".into();
|
|
let before = app.document.snapshot();
|
|
let _valid_model = name_take(&mut app, source);
|
|
send(&mut app, Message::Workflow(Event::Apply));
|
|
assert!(Arc::ptr_eq(&before, &app.document.snapshot()));
|
|
assert_eq!(app.selected, source);
|
|
assert_eq!(app.layer, Layer::Oa);
|
|
assert_eq!(app.active_diagram, Some(from));
|
|
assert_eq!(app.page, Page::Diagram);
|
|
assert_eq!(app.zoom, 1.21);
|
|
assert_eq!(app.pan, iced::Vector::new(72., -44.));
|
|
assert_eq!(app.search, "confirmation");
|
|
assert!(state(&app).error.is_some());
|
|
assert!(!app.document.can_undo());
|
|
}
|