Test Process and Allocation stale gestures after real Text Apply

This commit is contained in:
2026-09-24 01:17:40 -07:00
parent 62d3ffe9cb
commit 542b10ac58
2 changed files with 304 additions and 0 deletions
@@ -190,6 +190,165 @@ fn exact_history(
assert!(!app.document.can_redo());
}
#[test]
fn completed_text_apply_rejects_old_allocation_packets_without_retiring_a_new_drag() {
for layer in [Layer::Oa, Layer::Sa] {
let mut g = group(layer);
select(&mut g.f.app, &[g.f.node, g.yn]);
let before = g.f.app.document.snapshot();
assert!(!g.f.app.document.can_undo());
let from = node_point(&g.f.app, g.f.node);
let mut old_canvas = CanvasState::default();
let old = begin(&mut g.f.app, &mut old_canvas, from);
assert!(g.f.app.allocation_drag.active.is_some());
let location = g.f.app.document.compiled().index.declarations[&g.f.work].clone();
let original = &before.bundle.files[&location.path];
let quoted_name = format!("\"{}\"", g.f.app.project().elements[&g.f.work].name);
assert_eq!(original.matches(quoted_name.as_str()).count(), 1);
let edited = original.replace(quoted_name.as_str(), "\"Changed through Text\"");
let mut expected = before.decoded.project.clone();
expected.elements.get_mut(&g.f.work).unwrap().name = "Changed through Text".into();
let mut expected_bundle = before.bundle.clone();
expected_bundle
.files
.insert(location.path.clone(), edited.clone());
let _ = g.f.app.update(Message::Page(Page::Text));
assert!(g.f.app.allocation_drag.active.is_none());
let _ = g.f.app.update(Message::SourceFile(location.path));
let _ =
g.f.app
.update(Message::SourceEdit(text_editor::Action::SelectAll));
let _ =
g.f.app
.update(Message::SourceEdit(text_editor::Action::Edit(
text_editor::Edit::Paste(Arc::new(edited.clone())),
)));
assert!(g.f.app.source_dirty());
assert_eq!(g.f.app.source_editor.text(), edited);
assert!(Arc::ptr_eq(&before, &g.f.app.document.snapshot()));
let _ = g.f.app.update(Message::ApplySource);
assert!(!g.f.app.source_dirty(), "{}", g.f.app.status);
assert_eq!(g.f.app.project(), &expected);
assert_eq!(g.f.app.document.bundle(), &expected_bundle);
let _ = g.f.app.update(Message::Page(Page::Diagram));
assert_eq!(g.f.app.active_diagram, Some(g.f.diagram));
select(&mut g.f.app, &[g.f.node, g.yn]);
let from = node_point(&g.f.app, g.f.node);
let to = from + Vector::new(1400., 0.);
let mut current_canvas = CanvasState::default();
let current = begin(&mut g.f.app, &mut current_canvas, from);
assert_ne!(current.token, old.token);
assert_ne!(current.stamp.context, old.stamp.context);
move_pointer(&mut g.f.app, &mut current_canvas, to);
let preview =
g.f.app
.allocation_drag
.preview
.as_ref()
.expect(&g.f.app.status)
.clone();
let Candidate::Assignment(plan) = &preview.candidate else {
panic!("the current gesture must be a real group assignment");
};
assert_eq!(plan.changed_count(), 2);
let accepted = g.f.app.document.snapshot();
let revision = g.f.app.document.revision();
let held = selection(&g.f.app);
let selected = g.f.app.multiselect_snapshot().unwrap();
let workspace = g.f.app.source_workspace.bundle();
let editor = g.f.app.source_editor.text();
let camera = (
g.f.app.zoom,
g.f.app.pan,
g.f.app.fit_to_view,
g.f.app.canvas_size,
);
let epochs = (
g.f.app.canvas_epoch,
g.f.app.camera_epoch,
g.f.app.allocation_drag.epoch,
);
let draft =
g.f.app
.draft
.as_ref()
.map(|d| serde_json::to_value(d.recovery_snapshot()).unwrap());
let form = g.f.app.behavior.recovery_snapshot();
let status = g.f.app.status.clone();
let pending_reveal = g.f.app.pending_diagram_reveal.clone();
let arrange = g.f.app.allocation_drag.arrange_next;
// An idle obsolete press intentionally reports a stale-view explanation.
// With a newer real gesture active, both old packets must be fully inert.
for event in [
Event::Press(old.clone()),
Event::Release(old.stamp, old.token, Some(to)),
] {
let _ = g.f.app.update(Message::WorkDrag(event));
assert!(Arc::ptr_eq(&accepted, &g.f.app.document.snapshot()));
assert_eq!(g.f.app.project(), &expected);
assert_eq!(g.f.app.document.bundle(), &expected_bundle);
assert_eq!(g.f.app.document.revision(), revision);
assert_eq!(selection(&g.f.app), held);
assert_eq!(g.f.app.multiselect_snapshot(), Some(selected.clone()));
assert!(Arc::ptr_eq(
&g.f.app.allocation_drag.active.as_ref().unwrap().press,
&current
));
assert!(Arc::ptr_eq(
g.f.app.allocation_drag.preview.as_ref().unwrap(),
&preview
));
assert_eq!(g.f.app.source_workspace.bundle(), workspace);
assert_eq!(g.f.app.source_editor.text(), editor);
assert_eq!(
(
g.f.app.zoom,
g.f.app.pan,
g.f.app.fit_to_view,
g.f.app.canvas_size
),
camera
);
assert_eq!(
(
g.f.app.canvas_epoch,
g.f.app.camera_epoch,
g.f.app.allocation_drag.epoch
),
epochs
);
assert_eq!(
g.f.app
.draft
.as_ref()
.map(|d| serde_json::to_value(d.recovery_snapshot()).unwrap()),
draft
);
assert_eq!(g.f.app.behavior.recovery_snapshot(), form);
assert_eq!(g.f.app.pending_diagram_reveal, pending_reveal);
assert_eq!(g.f.app.allocation_drag.arrange_next, arrange);
assert_eq!(g.f.app.status, status);
assert!(!g.f.app.source_dirty());
assert!(g.f.app.document.can_undo());
assert!(!g.f.app.document.can_redo());
}
// The current gesture remains only a preview. History contains solely
// the accepted text rename, never either stale assignment packet.
let _ = g.f.app.update(Message::Undo);
assert_eq!(g.f.app.project(), &before.decoded.project);
assert_eq!(g.f.app.document.bundle(), &before.bundle);
assert!(!g.f.app.document.can_undo());
assert!(g.f.app.document.can_redo());
let _ = g.f.app.update(Message::Redo);
assert_eq!(g.f.app.project(), &expected);
assert_eq!(g.f.app.document.bundle(), &expected_bundle);
assert!(g.f.app.document.can_undo());
assert!(!g.f.app.document.can_redo());
}
}
#[test]
fn group_assignment_split_rebuild_preserves_primary_and_commits_one_complete_candidate() {
for layer in [Layer::Oa, Layer::Sa] {