Blacksite/docs/editor/operator-regression-testing.md
Rbanh 1ab3886028
Some checks are pending
CI / Format, lint, test, build (push) Waiting to run
Complete editor operator invariants
2026-07-12 23:53:46 -04:00

4.0 KiB

Operator Regression Testing

Blacksite editor operators and modal tools must preserve the authored scene across preview, commit, cancellation, validation failure, and undo/redo. Tests share operators::test_harness::OperatorInvariantHarness so a new tool proves the same contract instead of inventing local assertions.

Required invariants

Every production operator test must cover the paths it exposes:

Path Required proof
Commit Expected authored projection, exact undo-group delta, dirty state, stable operator ID, committed phase
Zero-history commit Authored projection and prior dirty state remain unchanged
Cancel or commit failure Exact authored projection restored, no new history, prior dirty state, stable operator ID, terminal canceled/blocked phase
Blocked start Commit closure never runs; authored state, history, and dirty state are unchanged
Preview failure Cancel finalizer runs, authored state is restored, and helpers are removed
Preview helpers No helper component remains after commit or cancel
Undoable commit assert_undo_redo_round_trip restores both initial and committed semantic projections
Continuous edit The entire interaction creates one history command, not one per frame or target

The harness intentionally fails with the invariant name in the assertion message. Tests may add domain assertions, but should not replace these shared lifecycle checks.

Adding a tool test

  1. Build a minimal World with ActiveOperator, EditorHistory, and SceneIo. Add tool-specific selection/resources and SelectedEntity when history helpers update selection.
  2. Capture OperatorInvariantHarness immediately before starting the operation.
  3. Run the real dispatch path or production finalizer used by the input system. Do not duplicate its state transition in the test.
  4. Call assert_committed, assert_canceled, or assert_blocked with the expected authored and undo deltas, then assert_status with the stable operator ID and terminal phase.
  5. For helpers, call assert_no_helpers::<ToolHelper>. For undoable work, project the meaningful state through assert_undo_redo_round_trip; use assert_projection_unchanged for no-op paths.

Do not satisfy a lifecycle test by constructing an EditorCommand and checking only its label. The test must mutate a world and prove restoration.

Current coverage

Workflow Coverage
Generic EditorOperator Commit cleanup, preview/commit failure rollback, blocked no-op, terminal ID/phase
Palette and registered commands Typed immediate commit versus modal preview ownership; failed CSG start terminates
Selection and scene commands Atomic Group Selection across repeated undo/redo; grouped Reset Lighting and Project Sun history
Asset workflows Asset/sub-asset placement; material/texture group assignment; audio/animation assignment and incompatible targets
Viewport material drop Exact renderer slot/primitive/brush-face preview, cancel, commit, cleanup, undo, and redo
Draw Brush and CSG Modal cancel; decomposed commit; CSG validation/read-only block, cancel, grouped commit, and deleted-brush restoration
Brush clip and element gizmo Production finalizers, geometry round trip, Escape rollback, and helper cleanup
Terrain sculpt and paint Multi-dab grouped commit, no-op release, commit failure rollback, cancel, clean-view interruption, and resource cleanup
Physics placement Prerequisite block, no-op commit, exact cancel, real settle commit, multi-selection grouping, helper cleanup, undo, and redo
Transform gizmo finalization Actual tracker finalizer, continuous multi-target grouping, no-op release, and missing-primary survivor rollback

The shared harness covers formal operators and multi-frame modal paths. Atomic inspector and history mutations that do not own ActiveOperator use focused typed history tests with equivalent semantic projection and undo/redo assertions.