Add desktop reset history checks and native wiring fixtures

This commit is contained in:
2026-09-24 19:18:31 -07:00
parent 6c44a2d6a1
commit 9eb4642e50
2 changed files with 421 additions and 0 deletions
+158
View File
@@ -1692,3 +1692,161 @@ fn adding_bend_between_close_ports_stays_outside_owner_clearance() {
}]
);
}
fn arrange_reset_fixture() -> (Project, Id, Id) {
let mut project = Project::empty();
let source = project.add(Kind::Activity, "Send report", 20., 70.);
let target = project.add(Kind::Activity, "Receive report", 650., 200.);
let edge = project.relate(RelationKind::Interaction, "Report", source, target);
let diagram = project.ensure_diagram(Layer::Oa);
project
.diagrams
.get_mut(&diagram)
.unwrap()
.routes
.push(EdgeRoute {
edge,
source_attachment: Some(EdgeAttachment {
side: PortAnchorSide::Bottom,
offset: 0.25,
}),
target_attachment: Some(EdgeAttachment {
side: PortAnchorSide::Top,
offset: 0.75,
}),
waypoints: vec![Position { x: 400., y: 500. }],
label: Some(EdgeLabel {
fraction: 0.25,
offset: Position { x: 11., y: 7. },
}),
});
(project, diagram, source)
}
#[test]
fn arrange_reset_document_preserves_multifile_comments_and_exact_undo_redo_reopen() {
use crate::document::Document;
use oa_core::source_project::{self, ProjectLimits};
let (project, diagram, _) = arrange_reset_fixture();
let mut bundle = source_project::format_bundle(&project);
assert!(
bundle.files.len() > 1,
"This must exercise a real include closure"
);
for (path, text) in &mut bundle.files {
*text = format!("// Keep exact authored module: {path}\r\n{text}");
}
let mut document = Document::from_bundle(bundle, ProjectLimits::default()).unwrap();
document.mark_saved(document.snapshot());
let before = document.snapshot();
let original_route = before.decoded.project.diagrams[&diagram].routes[0].clone();
document.execute(Command::Layout(diagram)).unwrap();
let after = document.snapshot();
let routes = &after.decoded.project.diagrams[&diagram].routes;
let mut expected_route = original_route;
expected_route.waypoints.clear();
expected_route.label = None;
assert_eq!(routes, &vec![expected_route]);
let mut outside = after.decoded.project.clone();
outside
.diagrams
.insert(diagram, before.decoded.project.diagrams[&diagram].clone());
assert_eq!(outside, before.decoded.project);
let affected: std::collections::BTreeSet<_> = std::iter::once(diagram)
.chain(
before.decoded.project.diagrams[&diagram]
.nodes
.keys()
.copied(),
)
.map(|id| document.compiled().index.declarations[&id].path.clone())
.collect();
for (path, text) in &before.bundle.files {
assert!(
after.bundle.files[path].contains(&format!("// Keep exact authored module: {path}"))
);
if !affected.contains(path) {
assert_eq!(
&after.bundle.files[path], text,
"Unrelated accepted bytes: {path}"
);
}
}
assert!(document.undo());
assert_eq!(document.bundle(), &before.bundle);
assert_eq!(document.project(), &before.decoded.project);
assert!(!document.dirty());
assert!(document.redo());
assert_eq!(document.bundle(), &after.bundle);
assert_eq!(document.project(), &after.decoded.project);
let reopened = Document::from_bundle(after.bundle.clone(), ProjectLimits::default()).unwrap();
assert_eq!(reopened.bundle(), &after.bundle);
assert_eq!(reopened.project(), &after.decoded.project);
}
#[test]
fn arrange_reset_pending_valid_property_has_separate_apply_and_layout_history() {
let (project, diagram, source) = arrange_reset_fixture();
let mut control = App::with_project(project.clone());
send(&mut control, Message::Select(source));
send(
&mut control,
Message::Field("/name".into(), "Revised sender".into()),
);
send(&mut control, Message::Apply);
let applied_project = control.project().clone();
let applied_bundle = control.document.bundle().clone();
assert_eq!(applied_project.elements[&source].name, "Revised sender");
assert_eq!(
applied_project.diagrams[&diagram].routes,
project.diagrams[&diagram].routes
);
let mut app = App::with_project(project);
let before_project = app.project().clone();
let before_bundle = app.document.bundle().clone();
send(&mut app, Message::Select(source));
send(
&mut app,
Message::Field("/name".into(), "Revised sender".into()),
);
send(&mut app, Message::Command(Command::Layout(diagram)));
assert_eq!(app.project().elements[&source].name, "Revised sender");
assert!(
app.project().diagrams[&diagram].routes[0]
.waypoints
.is_empty()
);
assert!(app.project().diagrams[&diagram].routes[0].label.is_none());
let arranged_project = app.project().clone();
let arranged_bundle = app.document.bundle().clone();
send(&mut app, Message::Undo);
assert_eq!(app.project(), &applied_project);
assert_eq!(app.document.bundle(), &applied_bundle);
send(&mut app, Message::Undo);
assert_eq!(app.project(), &before_project);
assert_eq!(app.document.bundle(), &before_bundle);
send(&mut app, Message::Redo);
assert_eq!(app.project(), &applied_project);
assert_eq!(app.document.bundle(), &applied_bundle);
send(&mut app, Message::Redo);
assert_eq!(app.project(), &arranged_project);
assert_eq!(app.document.bundle(), &arranged_bundle);
}
#[test]
fn arrange_reset_invalid_property_blocks_layout_without_losing_draft_or_accepted_bytes() {
let (project, diagram, _) = arrange_reset_fixture();
let node = *project.diagrams[&diagram].nodes.keys().next().unwrap();
let mut app = App::with_project(project);
send(&mut app, Message::Select(node));
let before_project = app.project().clone();
let before_bundle = app.document.bundle().clone();
let revision = app.document.revision();
send(&mut app, Message::Field("/position/x".into(), "-".into()));
send(&mut app, Message::Command(Command::Layout(diagram)));
assert_eq!(app.project(), &before_project);
assert_eq!(app.document.bundle(), &before_bundle);
assert_eq!(app.document.revision(), revision);
assert!(!app.document.can_undo());
assert_eq!(app.draft.as_ref().unwrap().inputs["/position/x"].raw, "-");
}