Add a new #[cfg(test)] mod chprop_integration_tests to src/app/properties.rs
with four end-to-end tests that exercise the converted CHPROP / MATCHPROP
handlers through the real Message dispatcher and the CLI command driver:
- prop_color_change_multiple_entities_undo_redo: a colour change on two
selected lines flows through Message::PropColorChanged -> the property-op
handler -> apply_property_op, and is reversible via undo / redo. Seeds
the panel's source_handles (selected_handles() is empty in this test
setup) so the converted non-empty branch runs.
- prop_change_on_locked_layer_is_ignored: when a selected entity's layer
is locked, property_target_handles filters it out and the handler's
empty-handles branch leaves the entity itself untouched. Asserts the
entity-level invariant only; the empty branch updates the document
header (CECOLOR) and sets dirty as a separate, pre-existing behaviour.
- ribbon_lineweight_updates_after_change: the Home-ribbon Lineweight chip
is updated by the converted RibbonLineweightChanged handler. Uses
acadrust::types::LineWeight::from_value(50) (the real constructor;
Lineweight::from_mm does not exist).
- cli_chprop_undo_restores_previous_state: regression test for the CLI
CHPROP command. Before Mission #15 it recorded the undo snapshot after
mutating the entities, so undo restored the post-edit state (a no-op
undo); converting the site to apply_property_op moved the snapshot
before the mutation. #[ignore]d: CLI CHPROP dispatch via
run_command_line / automation-op "run" does not reach the handler in
this test setup. The helper-level invariant is already covered by
apply_property_op_tests::applies_to_each_handle_sets_dirty_and_mutates
and the strengthened missing_entity_does_not_abort_loop.
The fifth proposed test (matchprop_empty_dest_no_dirty) was not added:
MATCHPROP is the interactive command driver (source pick -> dest pick)
and cannot be exercised from a unit test in isolation. The empty-handles
early-return is already covered at the helper level by
empty_handles_does_not_invoke_or_dirty.
Setup lessons that shaped these tests (panel vs scene selection,
LineWeight::from_value, the layer-locking pattern, undo not clearing
dirty) are documented in MISSION_15_REVIEW.md section 6.2.
Full suite: 478 passed / 1 pre-existing fail (diameter_dim_bakes_through_center,
unrelated) / 5 ignored. No regression. No production code changed -- the
new module is #[cfg(test)]-only.
test app::properties::chprop_integration_tests::prop_color_change_multiple_entities_undo_redo
test app::properties::chprop_integration_tests::cli_chprop_undo_restores_previous_state
test app::properties::chprop_integration_tests::prop_change_on_locked_layer_is_ignored
test app::properties::chprop_integration_tests::ribbon_lineweight_updates_after_change
Extract the push-undo → per-handle → invalidate → dirty → refresh
contract into one helper on OpenCADStudio. The helper is the single
source of truth for property-op side effects, so future property
handlers can't forget the cache invalidation or the panel refresh.
Note: MATCHPROP now no-ops when the destination selection is empty
(previously it marked the tab dirty and refreshed the panel). This is
a minor correctness improvement; restore the old behaviour with a
2-line guard at the MATCHPROP call site if desired.
test app::properties::apply_property_op_tests::empty_handles_does_not_invoke_or_dirty
test app::properties::apply_property_op_tests::applies_to_each_handle_sets_dirty_and_mutates
test app::properties::apply_property_op_tests::missing_entity_does_not_abort_loop
Introduce a cache for the grid overlay to prevent redundant geometry
reconstruction on every UI redraw. Extract the pure projection logic
from draw_grid into a renderer-free grid_segments function, and add
GridKey and GridCanvasState to memoize the resulting Geometry.
The cache key includes all per-pane GridParams and the overlay bounds,
preventing stale geometry when camera changes within the same canvas
size. On a params-key miss, the iced cache is cleared before redrawing
to bypass its bounds-only reuse.
Tests: 8 new unit tests cover key invalidation and state handling.
Benchmarks: uncached geometry ~32 us/frame vs cached decision ~90 ns,
a >99% reduction. Verified: 472 passed / 1 pre-existing failure / 4
ignored.
Tests:
ui::overlay::grid_key_tests::grid_key_matches_identical_params
ui::overlay::grid_key_tests::grid_key_invalidates_on_changed_fields
ui::overlay::grid_key_tests::grid_key_invalidates_when_any_pane_changes
ui::overlay::grid_key_tests::should_reuse_empty
ui::overlay::grid_key_tests::should_reuse_equal
ui::overlay::grid_key_tests::should_reuse_changed
ui::overlay::grid_canvas_state_tests::default_state_has_no_cached_key
ui::overlay::grid_canvas_state_tests::stored_key_is_recognized_by_should_reuse
Sync current main and companion codec changes before preserving unsupported frame rows, rendering in the entity plane, and sharing final layout metrics with placement preview.