golden

package
v0.0.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 4, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package golden loads and asserts against the cell-exact terminal fixtures in docs/fixtures — the acceptance artifact for TUI 2.0's frame integrity and column alignment (docs/tui-2.0.md, decision 11).

The fixtures exist before the renderer does. That is the point: they turn the frame and grid work from "does this look right" into red/green, so a row that is one cell too wide fails a test instead of shearing a panel in someone's terminal.

Two assertions, deliberately reported separately, because they have different lifetimes:

  • Display width. Every rendered row must be exactly the frame width. This must pass from the first commit and must never be regenerated away — a width diff is a layout bug.
  • Byte equality against the fixture. This is the design contract. Expect to regenerate a fixture when copy changes; never when geometry does.

Fixture.Compare returns both kinds tagged by DiffKind so a caller can gate on the first while tolerating churn in the second.

This package deliberately does not import "testing": it returns values and errors so it can also back a regeneration command. Callers in _test.go files turn a non-empty []Diff into t.Errorf.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Dir

func Dir() (string, error)

Dir returns the absolute path of docs/fixtures, located by walking up from the working directory to the module root. Tests run with their package directory as the working directory, so a relative path would differ per package; this keeps every caller writing golden.Dir().

func SplitLines

func SplitLines(rendered string) []string

SplitLines normalises rendered output into frame rows: ANSI stripped, a single trailing newline tolerated. A View() that ends with a newline and one that does not must not disagree about how many rows it drew.

func StripANSI

func StripANSI(s string) string

StripANSI removes escape sequences, leaving the plain text a fixture stores. Rendered output is styled; fixtures are not, so every comparison goes through this first.

func Width

func Width(s string) int

Width returns the display width of s in terminal cells.

This deliberately delegates to cell.Width rather than measuring independently: the harness must agree with the renderer it judges, and two measurement implementations would eventually disagree about some grapheme and make a real shear look like a passing test.

Types

type Diff

type Diff struct {
	Kind DiffKind
	// Row is the 1-indexed frame row, or 0 for a whole-frame problem such
	// as DiffRowCount.
	Row int
	// Got and Want are the rendered and expected rows, ANSI already
	// stripped. Both are empty for DiffRowCount.
	Got, Want string
	// GotWidth and WantWidth are display widths in cells.
	GotWidth, WantWidth int
}

Diff is a single mismatch between rendered output and a fixture.

func (Diff) Error

func (d Diff) Error() string

Error lets a Diff be used where an error is expected.

func (Diff) String

func (d Diff) String() string

type DiffKind

type DiffKind int

DiffKind classifies a mismatch. Callers gate on this: DiffWidth, DiffRowCount, and DiffControl are always bugs in the renderer, while DiffContent can legitimately mean the fixture needs regenerating after a copy change.

const (
	// DiffRowCount means the rendered output had the wrong number of rows.
	DiffRowCount DiffKind = iota
	// DiffWidth means a row's display width was not the frame width. This
	// is the assertion that must pass from day one.
	DiffWidth
	// DiffContent means a row's text did not match the fixture.
	DiffContent
	// DiffControl means a row contained a control character. Tabs and
	// carriage returns make "display width" meaningless — a tab's width
	// depends on the terminal's tab stops, not on the string — so they are
	// rejected outright rather than measured.
	DiffControl
)

func (DiffKind) String

func (k DiffKind) String() string

type Fixture

type Fixture struct {
	// Name is the file name without its extension, e.g. "frame-80x24".
	Name string
	// Path is the file the fixture was read from.
	Path string
	// Width and Height are the frame's dimensions in cells and rows.
	Width, Height int
	// Lines is the frame itself, with the comment header and the two rule
	// lines removed. Fixtures carry geometry, not colour, so these are
	// plain text with no escape sequences.
	Lines []string
}

Fixture is one parsed golden file: a frame of exactly Height lines, each exactly Width display cells wide.

func Load

func Load(path string) (*Fixture, error)

Load reads and parses a single fixture file.

func LoadAll

func LoadAll(dir string) ([]*Fixture, error)

LoadAll reads every .txt fixture in dir, sorted by name for deterministic test output.

func (*Fixture) Bytes

func (f *Fixture) Bytes() []byte

Bytes renders the fixture back into its on-disk form, header and rules included. Load(Bytes()) round-trips.

func (*Fixture) Compare

func (f *Fixture) Compare(rendered string) []Diff

Compare checks rendered output against the fixture. rendered may carry ANSI styling and may end with a trailing newline; both are normalised away first, since fixtures store geometry rather than colour.

Every row is checked for width even when the row count is wrong, so a frame that lost one row still reports which of the remaining rows are mis-sized instead of hiding them behind a single count failure.

func (*Fixture) Update

func (f *Fixture) Update(rendered string) error

Update replaces the fixture's frame with rendered output and writes it back to disk. It backs the -update flag that regenerates goldens once a renderer exists.

It refuses to write output that is not self-consistent — wrong row count, a mis-sized row, a stray control character — because the whole value of these files is that every line is exactly the frame width. A regeneration that laundered a layout bug into the expected output would destroy that. Height is taken from the fixture, not from the rendered output, so -update cannot quietly resize a frame either.

func (*Fixture) Validate

func (f *Fixture) Validate() []Diff

Validate checks a fixture against its own header: the right number of rows, every row exactly Width cells, and no control characters.

This guards the fixtures themselves, which are hand-maintained until the renderer can regenerate them. It is what catches a row padded with the wrong width rule — the ZWJ-emoji defect found on first review.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL