Skip to content

test(quadraui): TUI MSV paint↔click round-trip harness - #298

Merged
JDonaghy merged 1 commit into
developfrom
quadraui-tui-msv-harness
May 1, 2026
Merged

test(quadraui): TUI MSV paint↔click round-trip harness#298
JDonaghy merged 1 commit into
developfrom
quadraui-tui-msv-harness

Conversation

@JDonaghy

@JDonaghy JDonaghy commented May 1, 2026

Copy link
Copy Markdown
Owner

Summary

First instance of the new paint↔click round-trip harness pattern for quadraui primitives. Adds 4 tests in quadraui::tui::multi_section_view::tests that paint a MultiSectionView into a ratatui::buffer::Buffer, find painted glyph cells in that buffer, hit_test those exact coordinates against the layout the rasteriser used, and assert the hit identifies the painted-into section.

Also extracts pub fn tui_msv_layout(view, area) -> MultiSectionViewLayout from draw_multi_section_view's body so paint and tests consume one source of truth.

Why this PR exists

Step 3 of the Session 346 course correction. The pattern this PR establishes is the gate for re-attempting #296 (step 6) and migrating SC #282 (step 7), and is the template for future quadraui primitive harnesses (TreeView next, then GTK equivalents).

The bug class the harness catches

Pre-cell_quantum (#297, just merged), fractional EqualShare distributions made paint snap to integer rows via bounds.y.round() as u16 while MultiSectionViewLayout::hit_test consumed raw fractional bounds — clicks at the row paint drew Watch's header on landed in Variables' body. The #296 smoke wave chased that drift across 8 commits. Either of the fractional-distribution tests below would have caught it pre-merge.

Tests added

  • header_clicks_land_in_painted_section_under_fractional_distribution — 4 EqualShare sections in 21 cells (5.25 each, the exact worst case). Find each section's title row in the buffer, hit_test there, assert correct Header{section}.
  • body_clicks_land_in_painted_section_under_fractional_distribution — same setup, find item rows in each section's body, hit_test there, assert Body{section}.
  • scrollbar_column_hits_scrollbar_not_body_when_section_overflows — overflowing section reserves a 1-cell scrollbar gutter; clicks on it must hit Scrollbar, not Body.
  • body_and_scrollbar_bounds_never_overlap — geometric exclusion check across multiple sections.

Empirical verification that the harness catches what cell_quantum fixes

Temporarily flipped cell_quantum: 1.00.0 in tui_msv_layout:

test header_clicks_land_in_painted_section_under_fractional_distribution ... FAILED
test body_clicks_land_in_painted_section_under_fractional_distribution ... FAILED
test scrollbar_column_hits_scrollbar_not_body_when_section_overflows ... ok
test body_and_scrollbar_bounds_never_overlap ... ok

Restored cell_quantum: 1.0: all 4 pass. Harness catches exactly the bug class the structural fix in #297 closed.

Refactor: tui_msv_layout

draw_multi_section_view previously inlined LayoutMetrics + bounds + measure + view.layout(...). Extracted to a pub fn tui_msv_layout(view, area) -> MultiSectionViewLayout that the rasteriser calls internally and tests/hosts call independently. This means:

  • Paint and hit_test are guaranteed to use the same metrics (no drift possible from divergent inline definitions).
  • Future MSV consumers in vimcode's TUI can call tui_msv_layout for click handling instead of building their own LayoutMetrics (eliminates the inline cell_quantum: 1.0 duplication that fix(quadraui): MSV snaps section bounds to integer cells (TUI cell_quantum) #297 had to add to mouse.rs and panels.rs).

Test plan

  • cargo build --no-default-features clean
  • cargo clippy --no-default-features -- -D warnings clean
  • cargo fmt --check clean
  • cargo test --no-default-features (1950 vimcode tests) green
  • cd quadraui && cargo test --features tui (298 tests, +4 new harness) green
  • Empirically verified: harness fails when cell_quantum=0.0, passes when cell_quantum=1.0

Files changed

  • quadraui/src/tui/multi_section_view.rs+337/-37. Extract tui_msv_layout; add 4 round-trip tests + helpers (tree_section, row_text, find_row_with, paint_then_layout).

Next steps (per PLAN.md "🧭 Course correction")

🤖 Generated with Claude Code

Adds 4 round-trip tests to quadraui::tui::multi_section_view::tests
that paint a MultiSectionView into a ratatui Buffer, find painted
glyph cells in that buffer, hit_test those exact coordinates against
the layout the rasteriser used, and assert the hit identifies the
painted-into section.

The bug class this catches: paint and hit_test using different
coordinate systems. Pre-cell_quantum (Session 343-346 #296),
fractional EqualShare distributions made paint snap to integer rows
via bounds.y.round() while hit_test consumed raw fractional bounds,
so clicks at the row paint drew Watch's header on landed in
Variables' body. Either of these tests would have caught that
pre-merge.

Tests:
- header_clicks_land_in_painted_section_under_fractional_distribution
- body_clicks_land_in_painted_section_under_fractional_distribution
- scrollbar_column_hits_scrollbar_not_body_when_section_overflows
- body_and_scrollbar_bounds_never_overlap

The fractional-distribution tests use 4 EqualShare sections in 21
cells (5.25 each) — the exact worst case that broke #296.

To prove the harness catches the bug, I temporarily flipped
cell_quantum back to 0.0 in the rasteriser: the two
fractional-distribution tests fail; the structural-bounds tests
still pass. With cell_quantum: 1.0, all four pass. The harness
catches what cell_quantum fixes.

Refactor: extracts pub fn tui_msv_layout(view, area) -> Layout
from draw_multi_section_view's body. Hosts and tests now call this
helper to drive hit-testing without re-deriving metrics that could
drift from paint. draw_multi_section_view itself uses tui_msv_layout
internally — paint and hit_test consume one set of metrics, by
construction. This is the source-of-truth contract MultiSectionView
exists to enforce.

Step 3 of the Session 346 course correction (PLAN.md). Next steps:
- 4 (TreeView round-trip harness, same pattern)
- 5 (extract quadraui to its own repo)
- 6 (re-do #296 with the harness gating)

Quality gate: cargo build / clippy / fmt / 1950 vimcode lib +
integration green; quadraui 298 tests pass under --features tui
(was 215 before this session, +83 from new harness + tui-feature-
activated inline tests).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@JDonaghy
JDonaghy merged commit 4785df2 into develop May 1, 2026
3 of 4 checks passed
JDonaghy added a commit that referenced this pull request May 1, 2026
PROJECT_STATE.md gains a Session 346 entry capturing:
- 5 PRs that landed (cell_quantum #297, TUI MSV harness #298, TUI
  TreeView harness #299, quadraui extraction #300, plus 3 doc commits
  direct to develop)
- Quadraui now lives at its own repo; vimcode consumes via path-dep
  sibling
- Cross-repo blocked-label tracking now in place (vimcode #296, #282,
  #301, #302 all blocked on quadraui issues #1-#7 as appropriate)
- Migration prerequisites rule means no further consumer migrations
  land in vimcode until quadraui's rasterisers + harnesses ship

PLAN.md "Course correction" section: 7 steps now show ✅ status with
PR/SHA references for steps 1-5 (shipped) and ⏳ with cross-repo issue
links for steps 6-7 (in quadraui repo). New "Cross-repo prereq
tracking" subsection explains how the blocked label flows through
plan-next.

Doc-only; landing direct to develop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant