Skip to content

test: cover colour, hit testing and the stateless components - #142

Merged
meszmate merged 2 commits into
mainfrom
test/cover-untested-modules
Aug 14, 2026
Merged

test: cover colour, hit testing and the stateless components#142
meszmate merged 2 commits into
mainfrom
test/cover-untested-modules

Conversation

@meszmate

Copy link
Copy Markdown
Owner

Item 4 from the review — 64 of 88 source files had no tests. This is a first pass over the ones where behaviour is well-defined and bugs are cheap to miss.

44 tests across three files, covering style/color.zig, input/hitbox.zig, and the paginator, progress bar, spinner and keybinding map.

It found a real bug

MouseState.update checked the boundary crossing before the wheel:

if (inside and !was_hover) return .enter;
...
if (event.button == .wheel_up and inside) return .scroll_up;

A trackpad reports movement and scrolling in the same event, so a scroll that also moves the pointer into a region returned .enter and the scroll was dropped. In practice the first scroll into any scrollable region was being lost.

The wheel is now checked first. The crossing is not lost — the caller can still see it as state.hover.

What the tests pin down

Behaviour that is easy to break later, and that I checked against the implementation rather than assuming:

  • hit boxes exclude their far edge, and saturate rather than wrapping at the u16 coordinate limit
  • overlaps is symmetric and excludes merely-touching edges
  • the full press → release → click cycle, and that a release outside does not click
  • the 256-colour grayscale ramp stays monotonic; the cube's corners are black and white
  • contrast ratio hits exactly 21:1 for black on white and 1:1 for a colour against itself
  • NO_COLOR overrides COLORTERM=truecolor
  • a paginator's partial last page — endIndex must not run past the item count
  • the progress head marker disappears exactly when the bar is full

Two things worth knowing, found while writing these

  • Progress.percent() returns 0–100, not 0–1. The tests now say so, since the name reads either way.
  • Component view functions allocate scratch strings and never free them, by design — they expect the frame arena. That makes them leak under testing.allocator, so these tests hand them an arena. Worth documenting on the component contract.

zig build test and zig build clean on 0.16.0. Verified the hitbox test fails against the current code.

44 tests across three modules that had none: `style/color.zig`,
`input/hitbox.zig`, and the paginator, progress bar, spinner and
keybinding map.

Writing them turned up a real bug. `MouseState.update` checked the
boundary crossing before the wheel, so a scroll that also moved the
pointer into the region returned `.enter` and the scroll was dropped.
A trackpad reports movement and scrolling in the same event, so the
first scroll into any region was being lost. The wheel is now checked
first; the crossing is still visible to the caller as `state.hover`.

The tests pin down behaviour that is easy to get wrong later: hit boxes
excluding their far edge and saturating instead of wrapping at the
coordinate limit, the 256-colour ramp staying monotonic, contrast ratio
matching WCAG at both extremes, NO_COLOR overriding COLORTERM, a
paginator's partial last page, and a progress bar's head marker
disappearing exactly when the bar is full.
The new colour tests failed on Windows, which turned out to be the
implementation rather than the tests.

`ColorProfile.detect` returned `.true_color` for Windows before it
looked at `no_color`, so a user who set NO_COLOR on Windows Terminal got
colour anyway. NO_COLOR is a cross-platform convention; it is now
checked first, and the Windows shortcut applies to everything after it.

`hasDarkBackground` ignored COLORFGBG on Windows and always assumed
dark. Windows terminals rarely set it, but when one does there is no
reason to disbelieve it.

The remaining Windows-specific behaviour -- true colour regardless of
TERM -- is asserted per platform in the test.
@meszmate
meszmate merged commit 0c4c14b into main Aug 14, 2026
9 checks passed
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